]> code.ossystems Code Review - openembedded-core.git/commitdiff
linux-rp: Tidy up .bb file and clean up unused patches
authorRichard Purdie <richard@openedhand.com>
Sun, 20 Jan 2008 17:03:32 +0000 (17:03 +0000)
committerRichard Purdie <richard@openedhand.com>
Sun, 20 Jan 2008 17:03:32 +0000 (17:03 +0000)
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3557 311d38ba-8fff-0310-9ca6-ca027cbcb966

22 files changed:
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/connectplus-prevent-oops-HACK.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/hx2750_base-r31.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/mmcsd_no_scr_check-r2.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pda-power.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pxa27x_overlay-r8.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.0-2.6.15.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.3.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.2-2.6.20-r0.patch with 81% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/uvesafb-0.1-rc3-2.6.22.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/vt_ioctl_race.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/w100fb-unused-var.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/wm97xx-lcdnoise-r0.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23/pda-power.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23/versatile-armv6.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23/w100fb-unused-var.patch [deleted file]
meta/packages/linux/linux-rp-2.6.23/wm9712-reset-loop-r2.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23/wm9712-suspend-cold-res-r2.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0-fix-r0.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0.patch [new file with mode: 0644]
meta/packages/linux/linux-rp_2.6.23+2.6.24-rc8.bb
meta/packages/linux/linux-rp_2.6.23.bb

diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/connectplus-prevent-oops-HACK.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/connectplus-prevent-oops-HACK.patch
new file mode 100644 (file)
index 0000000..b5439c6
--- /dev/null
@@ -0,0 +1,17 @@
+Index: linux-2.6.21/drivers/net/wireless/hostap/hostap_hw.c
+===================================================================
+--- linux-2.6.21.orig/drivers/net/wireless/hostap/hostap_hw.c  2007-07-07 12:45:39.000000000 +0100
++++ linux-2.6.21/drivers/net/wireless/hostap/hostap_hw.c       2007-07-07 12:47:30.000000000 +0100
+@@ -2666,6 +2666,12 @@
+       iface = netdev_priv(dev);
+       local = iface->local;
++      if(dev->base_addr == 0)
++      {
++              printk(KERN_DEBUG "%s: IRQ before base_addr set\n", dev->name);
++              return IRQ_HANDLED;
++      }
++
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
+       if (local->func->card_present && !local->func->card_present(local)) {
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/hx2750_base-r31.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/hx2750_base-r31.patch
deleted file mode 100644 (file)
index 5d58bcf..0000000
+++ /dev/null
@@ -1,1094 +0,0 @@
----
- 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-rc8/mmcsd_no_scr_check-r2.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/mmcsd_no_scr_check-r2.patch
deleted file mode 100644 (file)
index ac2245f..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
----
- drivers/mmc/core/sd.c |   11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
-Index: linux-2.6.23/drivers/mmc/core/sd.c
-===================================================================
---- linux-2.6.23.orig/drivers/mmc/core/sd.c    2007-10-17 11:33:26.000000000 +0200
-+++ linux-2.6.23/drivers/mmc/core/sd.c 2007-10-17 11:33:49.000000000 +0200
-@@ -173,14 +173,15 @@
-       scr_struct = UNSTUFF_BITS(resp, 60, 4);
-       if (scr_struct != 0) {
--              printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
-+              printk(KERN_WARNING "%s: unrecognised SCR structure version %d\n",
-                       mmc_hostname(card->host), scr_struct);
--              return -EINVAL;
-+              scr->sda_vsn = 0;
-+              scr->bus_widths = 0;
-+      } else {
-+              scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
-+              scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
-       }
--      scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
--      scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
--
-       return 0;
- }
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pda-power.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pda-power.patch
deleted file mode 100644 (file)
index face2f4..0000000
+++ /dev/null
@@ -1,3373 +0,0 @@
----
- arch/arm/Kconfig                   |    2 
- drivers/Kconfig                    |    2 
- drivers/Makefile                   |    1 
- drivers/power/Kconfig              |   70 +++++
- drivers/power/Makefile             |   28 ++
- drivers/power/adc_battery.c        |  278 +++++++++++++++++++++
- drivers/power/apm_power.c          |  247 +++++++++++++++++++
- drivers/power/ds2760_battery.c     |  475 +++++++++++++++++++++++++++++++++++++
- drivers/power/micro_battery.c      |  257 ++++++++++++++++++++
- drivers/power/olpc_battery.c       |  302 +++++++++++++++++++++++
- drivers/power/pda_power.c          |  263 ++++++++++++++++++++
- drivers/power/pmu_battery.c        |  215 ++++++++++++++++
- drivers/power/power_supply.h       |   42 +++
- drivers/power/power_supply_core.c  |  168 +++++++++++++
- drivers/power/power_supply_leds.c  |  188 ++++++++++++++
- drivers/power/power_supply_sysfs.c |  289 ++++++++++++++++++++++
- drivers/power/simpad-battery.c     |  242 ++++++++++++++++++
- include/linux/power_supply.h       |  175 +++++++++++++
- 18 files changed, 3244 insertions(+)
-
-Index: linux-2.6.22/drivers/power/adc_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/adc_battery.c   2007-08-23 12:26:28.000000000 +0200
-@@ -0,0 +1,278 @@
-+/*
-+ * Copyright (c) 2007 Paul Sokolovsky
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ */
-+
-+//#define DEBUG
-+
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/pm.h>
-+#include <linux/delay.h>
-+#include <linux/workqueue.h>
-+#include <linux/platform_device.h>
-+#include <linux/power_supply.h>
-+#include <linux/adc.h>
-+#include <linux/adc_battery.h>
-+
-+#include <asm/irq.h>
-+
-+#define PIN_NO_VOLT 0
-+#define PIN_NO_CURR 1
-+#define PIN_NO_TEMP 2
-+
-+struct battery_adc_priv {
-+      struct power_supply batt_cdev;
-+
-+      struct battery_adc_platform_data *pdata;
-+
-+      struct adc_request req;
-+      struct adc_sense pins[3];
-+      struct adc_sense last_good_pins[3];
-+
-+      struct workqueue_struct *wq;
-+      struct delayed_work work;
-+};
-+
-+/*
-+ *  Battery properties
-+ */
-+
-+static int adc_battery_get_property(struct power_supply *psy,
-+                                    enum power_supply_property psp,
-+                                    union power_supply_propval *val)
-+{
-+      struct battery_adc_priv* drvdata = (struct battery_adc_priv*)psy;
-+      int voltage;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              val->intval = drvdata->pdata->charge_status;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.voltage_max_design;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.voltage_min_design;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.charge_full_design;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.charge_empty_design;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+              val->intval = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_NOW:
-+              val->intval = drvdata->last_good_pins[PIN_NO_CURR].value * drvdata->pdata->current_mult;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_NOW:
-+              /* We do calculations in mX, not uX, because todo it in uX we should use "long long"s,
-+               * which is a mess (need to use do_div) when you need divide operation). */
-+              voltage = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
-+              val->intval = ((voltage/1000 - drvdata->pdata->battery_info.voltage_min_design/1000) *
-+                   (drvdata->pdata->battery_info.charge_full_design/1000 -
-+                    drvdata->pdata->battery_info.charge_empty_design/1000)) /
-+                   (drvdata->pdata->battery_info.voltage_max_design/1000 -
-+                    drvdata->pdata->battery_info.voltage_min_design/1000);
-+              val->intval *= 1000; /* convert final result to uX */
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = drvdata->last_good_pins[PIN_NO_TEMP].value * drvdata->pdata->temperature_mult / 1000;
-+              break;
-+      default:
-+              return -EINVAL;
-+      };
-+      return 0;
-+}
-+
-+/*
-+ *  Driver body
-+ */
-+
-+static void adc_battery_query(struct battery_adc_priv *drvdata)
-+{
-+      struct battery_adc_platform_data *pdata = drvdata->pdata;
-+      int powered, charging;
-+
-+      adc_request_sample(&drvdata->req);
-+
-+      powered = power_supply_am_i_supplied(&drvdata->batt_cdev);
-+      charging = pdata->is_charging ? pdata->is_charging() : -1;
-+
-+      if (powered && charging)
-+              pdata->charge_status = POWER_SUPPLY_STATUS_CHARGING;
-+      else if (powered && !charging && charging != -1)
-+              pdata->charge_status = POWER_SUPPLY_STATUS_FULL;
-+      else
-+              pdata->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
-+
-+      /* Throw away invalid samples, this may happen soon after resume for example. */
-+      if (drvdata->pins[PIN_NO_VOLT].value > 0) {
-+              memcpy(drvdata->last_good_pins, drvdata->pins, sizeof(drvdata->pins));
-+#ifdef DEBUG
-+              printk("%d %d %d\n", drvdata->pins[PIN_NO_VOLT].value,
-+                                   drvdata->pins[PIN_NO_CURR].value,
-+                                   drvdata->pins[PIN_NO_TEMP].value);
-+#endif
-+      }
-+}
-+
-+static void adc_battery_charge_power_changed(struct power_supply *bat)
-+{
-+      struct battery_adc_priv *drvdata = (struct battery_adc_priv*)bat;
-+      cancel_delayed_work(&drvdata->work);
-+      queue_delayed_work(drvdata->wq, &drvdata->work, 0);
-+}
-+
-+static void adc_battery_work_func(struct work_struct *work)
-+{
-+      struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);
-+      struct battery_adc_priv *drvdata = container_of(delayed_work, struct battery_adc_priv, work);
-+
-+      adc_battery_query(drvdata);
-+      power_supply_changed(&drvdata->batt_cdev);
-+
-+      queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
-+}
-+
-+static int adc_battery_probe(struct platform_device *pdev)
-+{
-+        int retval;
-+      struct battery_adc_platform_data *pdata = pdev->dev.platform_data;
-+      struct battery_adc_priv *drvdata;
-+      int i, j;
-+      enum power_supply_property props[] = {
-+              POWER_SUPPLY_PROP_STATUS,
-+              POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+              POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-+              POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+              POWER_SUPPLY_PROP_CURRENT_NOW,
-+              POWER_SUPPLY_PROP_CHARGE_NOW,
-+              POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+              POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
-+              POWER_SUPPLY_PROP_TEMP,
-+      };
-+
-+      // Initialize ts data structure.
-+      drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-+      if (!drvdata)
-+              return -ENOMEM;
-+
-+      drvdata->batt_cdev.name           = pdata->battery_info.name;
-+      drvdata->batt_cdev.use_for_apm    = pdata->battery_info.use_for_apm;
-+      drvdata->batt_cdev.num_properties = ARRAY_SIZE(props);
-+      drvdata->batt_cdev.get_property   = adc_battery_get_property;
-+      drvdata->batt_cdev.external_power_changed =
-+                                adc_battery_charge_power_changed;
-+
-+      if (!pdata->voltage_pin) {
-+              drvdata->batt_cdev.num_properties--;
-+              props[3] = -1;
-+      }
-+      if (!pdata->current_pin) {
-+              drvdata->batt_cdev.num_properties--;
-+              props[4] = -1;
-+      }
-+      if (!pdata->temperature_pin) {
-+              drvdata->batt_cdev.num_properties--;
-+              props[8] = -1;
-+      }
-+
-+      drvdata->batt_cdev.properties = kmalloc(
-+                      sizeof(*drvdata->batt_cdev.properties) *
-+                      drvdata->batt_cdev.num_properties, GFP_KERNEL);
-+      if (!drvdata->batt_cdev.properties)
-+              return -ENOMEM;
-+
-+      j = 0;
-+      for (i = 0; i < ARRAY_SIZE(props); i++) {
-+              if (props[i] == -1)
-+                      continue;
-+              drvdata->batt_cdev.properties[j++] = props[i];
-+      }
-+
-+      retval = power_supply_register(&pdev->dev, &drvdata->batt_cdev);
-+      if (retval) {
-+              printk("adc-battery: Error registering battery classdev");
-+              return retval;
-+      }
-+
-+      drvdata->req.senses = drvdata->pins;
-+      drvdata->req.num_senses = ARRAY_SIZE(drvdata->pins);
-+      drvdata->pins[PIN_NO_VOLT].name = pdata->voltage_pin;
-+      drvdata->pins[PIN_NO_CURR].name = pdata->current_pin;
-+      drvdata->pins[PIN_NO_TEMP].name = pdata->temperature_pin;
-+
-+      adc_request_register(&drvdata->req);
-+
-+      /* Here we assume raw values in mV */
-+      if (!pdata->voltage_mult)
-+              pdata->voltage_mult = 1000;
-+      /* Here we assume raw values in mA */
-+      if (!pdata->current_mult)
-+              pdata->current_mult = 1000;
-+      /* Here we assume raw values in 1/10 C */
-+      if (!pdata->temperature_mult)
-+              pdata->temperature_mult = 1000;
-+
-+      drvdata->pdata = pdata;
-+      pdata->drvdata = drvdata; /* Seems ugly, we need better solution */
-+
-+      platform_set_drvdata(pdev, drvdata);
-+
-+        // Load initial values ASAP
-+      adc_battery_query(drvdata);
-+
-+      // Still schedule next sampling soon
-+      INIT_DELAYED_WORK(&drvdata->work, adc_battery_work_func);
-+      drvdata->wq = create_workqueue(pdev->dev.bus_id);
-+      if (!drvdata->wq)
-+              return -ESRCH;
-+
-+      queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
-+
-+      return retval;
-+}
-+
-+static int adc_battery_remove(struct platform_device *pdev)
-+{
-+      struct battery_adc_priv *drvdata = platform_get_drvdata(pdev);
-+      cancel_delayed_work(&drvdata->work);
-+      destroy_workqueue(drvdata->wq);
-+      power_supply_unregister(&drvdata->batt_cdev);
-+      adc_request_unregister(&drvdata->req);
-+      kfree(drvdata->batt_cdev.properties);
-+      return 0;
-+}
-+
-+static struct platform_driver adc_battery_driver = {
-+      .driver         = {
-+              .name   = "adc-battery",
-+      },
-+      .probe          = adc_battery_probe,
-+      .remove         = adc_battery_remove,
-+};
-+
-+static int __init adc_battery_init(void)
-+{
-+      return platform_driver_register(&adc_battery_driver);
-+}
-+
-+static void __exit adc_battery_exit(void)
-+{
-+      platform_driver_unregister(&adc_battery_driver);
-+}
-+
-+module_init(adc_battery_init)
-+module_exit(adc_battery_exit)
-+
-+MODULE_AUTHOR("Paul Sokolovsky");
-+MODULE_DESCRIPTION("Battery driver for ADC device");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/drivers/power/apm_power.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/apm_power.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,247 @@
-+/*
-+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
-+ * Copyright (c) 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
-+ *
-+ * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
-+ *
-+ * Use consistent with the GNU GPL is permitted,
-+ * provided that this copyright notice is
-+ * preserved in its entirety in all copies and derived works.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/power_supply.h>
-+#include <linux/apm-emulation.h>
-+
-+#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
-+                         POWER_SUPPLY_PROP_##prop, val)
-+
-+#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
-+                                                         prop, val)
-+
-+#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
-+
-+static struct power_supply *main_battery;
-+
-+static void find_main_battery(void)
-+{
-+      struct device *dev;
-+      struct power_supply *bat, *batm;
-+      union power_supply_propval full;
-+      int max_charge = 0;
-+
-+      main_battery = NULL;
-+      batm = NULL;
-+      list_for_each_entry(dev, &power_supply_class->devices, node) {
-+              bat = dev_get_drvdata(dev);
-+              /* If none of battery devices cantains 'use_for_apm' flag,
-+                 choice one with maximum design charge */
-+              if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
-+                      if (full.intval > max_charge) {
-+                              batm = bat;
-+                              max_charge = full.intval;
-+                      }
-+              }
-+
-+              if (bat->use_for_apm)
-+                      main_battery = bat;
-+      }
-+      if (!main_battery)
-+              main_battery = batm;
-+
-+      return;
-+}
-+
-+static int calculate_time(int status)
-+{
-+      union power_supply_propval charge_full, charge_empty;
-+      union power_supply_propval charge, I;
-+
-+      if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
-+              /* if battery can't report this property, use design value */
-+              if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
-+                      return -1;
-+      }
-+
-+      if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
-+              /* if battery can't report this property, use design value */
-+              if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
-+                      charge_empty.intval = 0;
-+      }
-+
-+      if (MPSY_PROP(CHARGE_AVG, &charge)) {
-+              /* if battery can't report average value, use momentary */
-+              if (MPSY_PROP(CHARGE_NOW, &charge))
-+                      return -1;
-+      }
-+
-+      if (MPSY_PROP(CURRENT_AVG, &I)) {
-+              /* if battery can't report average value, use momentary */
-+              if (MPSY_PROP(CURRENT_NOW, &I))
-+                      return -1;
-+      }
-+
-+      if (I.intval == 0)
-+              return 0;
-+      else if (status == POWER_SUPPLY_STATUS_CHARGING)
-+              return ((charge.intval - charge_full.intval) * 60L) /
-+                     I.intval;
-+      else
-+              return -((charge.intval - charge_empty.intval) * 60L) /
-+                      I.intval;
-+}
-+
-+static int calculate_capacity(int using_charge)
-+{
-+      enum power_supply_property full_prop, empty_prop;
-+      enum power_supply_property full_design_prop, empty_design_prop;
-+      enum power_supply_property now_prop, avg_prop;
-+      union power_supply_propval empty, full, cur;
-+      int ret;
-+
-+      if (using_charge) {
-+              full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
-+              empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
-+              full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
-+              empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
-+              now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
-+              avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
-+      }
-+      else {
-+              full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
-+              empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
-+              full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
-+              empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
-+              now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
-+              avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
-+      }
-+
-+      if (_MPSY_PROP(full_prop, &full)) {
-+              /* if battery can't report this property, use design value */
-+              if (_MPSY_PROP(full_design_prop, &full))
-+                      return -1;
-+      }
-+
-+      if (_MPSY_PROP(avg_prop, &cur)) {
-+              /* if battery can't report average value, use momentary */
-+              if (_MPSY_PROP(now_prop, &cur))
-+                      return -1;
-+      }
-+
-+      if (_MPSY_PROP(empty_prop, &empty)) {
-+              /* if battery can't report this property, use design value */
-+              if (_MPSY_PROP(empty_design_prop, &empty))
-+                      empty.intval = 0;
-+      }
-+
-+      if (full.intval - empty.intval)
-+              ret =  ((cur.intval - empty.intval) * 100L) /
-+                     (full.intval - empty.intval);
-+      else
-+              return -1;
-+
-+      if (ret > 100)
-+              return 100;
-+      else if (ret < 0)
-+              return 0;
-+
-+      return ret;
-+}
-+
-+static void apm_battery_apm_get_power_status(struct apm_power_info *info)
-+{
-+      union power_supply_propval status;
-+      union power_supply_propval capacity, time_to_full, time_to_empty;
-+
-+      down(&power_supply_class->sem);
-+      find_main_battery();
-+      if (!main_battery) {
-+              up(&power_supply_class->sem);
-+              return;
-+      }
-+
-+      /* status */
-+
-+      if (MPSY_PROP(STATUS, &status))
-+              status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+      /* ac line status */
-+
-+      if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
-+          (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
-+          (status.intval == POWER_SUPPLY_STATUS_FULL))
-+              info->ac_line_status = APM_AC_ONLINE;
-+      else
-+              info->ac_line_status = APM_AC_OFFLINE;
-+
-+      /* battery life (i.e. capacity, in percents) */
-+
-+      if (MPSY_PROP(CAPACITY, &capacity) == 0)
-+              info->battery_life = capacity.intval;
-+      else {
-+              /* try calculate using energy */
-+              info->battery_life = calculate_capacity(0);
-+              /* if failed try calculate using charge instead */
-+              if (info->battery_life == -1)
-+                      info->battery_life = calculate_capacity(1);
-+      }
-+
-+      /* charging status */
-+
-+      if (status.intval == POWER_SUPPLY_STATUS_CHARGING)
-+              info->battery_status = APM_BATTERY_STATUS_CHARGING;
-+      else {
-+              if (info->battery_life > 50)
-+                      info->battery_status = APM_BATTERY_STATUS_HIGH;
-+              else if (info->battery_life > 5)
-+                      info->battery_status = APM_BATTERY_STATUS_LOW;
-+              else
-+                      info->battery_status = APM_BATTERY_STATUS_CRITICAL;
-+      }
-+      info->battery_flag = info->battery_status;
-+
-+      /* time */
-+
-+      info->units = APM_UNITS_MINS;
-+
-+      if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
-+              if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
-+                      if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
-+                              info->time = calculate_time(status.intval);
-+                      else
-+                              info->time = time_to_full.intval / 60;
-+              }
-+      }
-+      else {
-+              if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
-+                      if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
-+                              info->time = calculate_time(status.intval);
-+                      else
-+                              info->time = time_to_empty.intval / 60;
-+              }
-+      }
-+
-+      up(&power_supply_class->sem);
-+      return;
-+}
-+
-+static int __init apm_battery_init(void)
-+{
-+      printk(KERN_INFO "APM Battery Driver\n");
-+
-+      apm_get_power_status = apm_battery_apm_get_power_status;
-+      return 0;
-+}
-+
-+static void __exit apm_battery_exit(void)
-+{
-+      apm_get_power_status = NULL;
-+      return;
-+}
-+
-+module_init(apm_battery_init);
-+module_exit(apm_battery_exit);
-+
-+MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
-+MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/drivers/power/ds2760_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/ds2760_battery.c        2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,475 @@
-+/*
-+ * Driver for batteries with DS2760 chips inside.
-+ *
-+ * Copyright (c) 2007 Anton Vorontsov
-+ *               2004-2007 Matt Reimer
-+ *               2004 Szabolcs Gyurko
-+ *
-+ * Use consistent with the GNU GPL is permitted,
-+ * provided that this copyright notice is
-+ * preserved in its entirety in all copies and derived works.
-+ *
-+ * Author:  Anton Vorontsov <cbou@mail.ru>
-+ *          February 2007
-+ *
-+ *          Matt Reimer <mreimer@vpop.net>
-+ *          April 2004, 2005, 2007
-+ *
-+ *          Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
-+ *          September 2004
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/param.h>
-+#include <linux/jiffies.h>
-+#include <linux/workqueue.h>
-+#include <linux/pm.h>
-+#include <linux/platform_device.h>
-+#include <linux/power_supply.h>
-+
-+#include "../w1/w1.h"
-+#include "../w1/slaves/w1_ds2760.h"
-+
-+struct ds2760_device_info {
-+      struct device *dev;
-+
-+      /* DS2760 data, valid after calling ds2760_battery_read_status() */
-+      unsigned long update_time;      /* jiffies when data read */
-+      char raw[DS2760_DATA_SIZE];     /* raw DS2760 data */
-+      int voltage_raw;                /* units of 4.88 mV */
-+      int voltage_uV;                 /* units of uV */
-+      int current_raw;                /* units of 0.625 mA */
-+      int current_uA;                 /* units of uA */
-+      int accum_current_raw;          /* units of 0.25 mAh */
-+      int accum_current_uAh;          /* units of uAh */
-+      int temp_raw;                   /* units of 0.125 C */
-+      int temp_C;                     /* units of 0.1 C */
-+      int rated_capacity;             /* units of uAh */
-+      int rem_capacity;               /* percentage */
-+      int full_active_uAh;            /* units of uAh */
-+      int empty_uAh;                  /* units of uAh */
-+      int life_sec;                   /* units of seconds */
-+      int charge_status;              /* POWER_SUPPLY_STATUS_* */
-+
-+      int full_counter;
-+      struct power_supply bat;
-+      struct device *w1_dev;
-+      struct workqueue_struct *monitor_wqueue;
-+      struct delayed_work monitor_work;
-+};
-+
-+static unsigned int cache_time = 1000;
-+module_param(cache_time, uint, 0644);
-+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
-+
-+/* Some batteries have their rated capacity stored a N * 10 mAh, while
-+ * others use an index into this table. */
-+static int rated_capacities[] = {
-+      0,
-+      920,        /* Samsung */
-+      920,        /* BYD */
-+      920,        /* Lishen */
-+      920,        /* NEC */
-+      1440,       /* Samsung */
-+      1440,       /* BYD */
-+      1440,       /* Lishen */
-+      1440,       /* NEC */
-+      2880,       /* Samsung */
-+      2880,       /* BYD */
-+      2880,       /* Lishen */
-+      2880        /* NEC */
-+};
-+
-+/* array is level at temps 0C, 10C, 20C, 30C, 40C
-+ * temp is in Celsius */
-+static int battery_interpolate(int array[], int temp)
-+{
-+      int index, dt;
-+
-+      if (temp <= 0)
-+              return array[0];
-+      if (temp >= 40)
-+              return array[4];
-+
-+      index = temp / 10;
-+      dt    = temp % 10;
-+
-+      return array[index] + (((array[index + 1] - array[index]) * dt) / 10);
-+}
-+
-+static int ds2760_battery_read_status(struct ds2760_device_info *di)
-+{
-+      int ret, i, start, count, scale[5];
-+
-+      if (di->update_time && time_before(jiffies, di->update_time +
-+                                         msecs_to_jiffies(cache_time)))
-+              return 0;
-+
-+      /* The first time we read the entire contents of SRAM/EEPROM,
-+       * but after that we just read the interesting bits that change. */
-+      if (di->update_time == 0) {
-+              start = 0;
-+              count = DS2760_DATA_SIZE;
-+      }
-+      else {
-+              start = DS2760_VOLTAGE_MSB;
-+              count = DS2760_TEMP_LSB - start + 1;
-+      }
-+
-+      ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count);
-+      if (ret != count) {
-+              dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n",
-+                       di->w1_dev);
-+              return 1;
-+      }
-+
-+      di->update_time = jiffies;
-+
-+      /* DS2760 reports voltage in units of 4.88mV, but the battery class
-+       * reports in units of uV, so convert by multiplying by 4880. */
-+      di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) |
-+                        (di->raw[DS2760_VOLTAGE_LSB] >> 5);
-+      di->voltage_uV = di->voltage_raw * 4880;
-+
-+      /* DS2760 reports current in signed units of 0.625mA, but the battery
-+       * class reports in units of uA, so convert by multiplying by 625. */
-+      di->current_raw =
-+          (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) |
-+                        (di->raw[DS2760_CURRENT_LSB] >> 3);
-+      di->current_uA = di->current_raw * 625;
-+
-+      /* DS2760 reports accumulated current in signed units of 0.25mAh. */
-+      di->accum_current_raw =
-+          (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) |
-+                         di->raw[DS2760_CURRENT_ACCUM_LSB];
-+      di->accum_current_uAh = di->accum_current_raw * 250;
-+
-+      /* DS2760 reports temperature in signed units of 0.125C, but the
-+       * battery class reports in units of 1/10 C, so we convert by
-+       * multiplying by .125 * 10 = 1.25. */
-+      di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) |
-+                                   (di->raw[DS2760_TEMP_LSB] >> 5);
-+      di->temp_C = di->temp_raw + (di->temp_raw / 4);
-+
-+      /* At least some battery monitors (e.g. HP iPAQ) store the battery's
-+       * maximum rated capacity. */
-+      if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities))
-+              di->rated_capacity = rated_capacities[
-+                      (unsigned int)di->raw[DS2760_RATED_CAPACITY]];
-+      else
-+              di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10;
-+
-+      di->rated_capacity *= 1000; /* convert to uAh */
-+
-+      /* Calculate the full level at the present temperature. */
-+      di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
-+                            di->raw[DS2760_ACTIVE_FULL + 1];
-+
-+      scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 |
-+                 di->raw[DS2760_ACTIVE_FULL + 1];
-+      for (i = 1; i < 5; i++)
-+              scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
-+
-+      di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
-+      di->full_active_uAh *= 1000; /* convert to uAh */
-+
-+      /* Calculate the empty level at the present temperature. */
-+      scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4];
-+      for (i = 3; i >= 0; i--)
-+              scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i];
-+
-+      di->empty_uAh = battery_interpolate(scale, di->temp_C / 10);
-+      di->empty_uAh *= 1000; /* convert to uAh */
-+
-+      /* From Maxim Application Note 131: remaining capacity =
-+       * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */
-+      di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) /
-+                          (di->full_active_uAh - di->empty_uAh);
-+
-+      if (di->rem_capacity < 0)
-+              di->rem_capacity = 0;
-+      if (di->rem_capacity > 100)
-+              di->rem_capacity = 100;
-+
-+      if (di->current_uA)
-+              di->life_sec = -((di->accum_current_uAh - di->empty_uAh) *
-+                               3600L) / di->current_uA;
-+      else
-+              di->life_sec = 0;
-+
-+      return 0;
-+}
-+
-+static void ds2760_battery_update_status(struct ds2760_device_info *di)
-+{
-+      int old_charge_status = di->charge_status;
-+
-+      ds2760_battery_read_status(di);
-+
-+      if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN)
-+              di->full_counter = 0;
-+
-+      if (power_supply_am_i_supplied(&di->bat)) {
-+              if (di->current_uA > 10000) {
-+                      di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
-+                      di->full_counter = 0;
-+              }
-+              else if (di->current_uA < -5000) {
-+                      if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING)
-+                              dev_notice(di->dev, "not enough power to "
-+                                         "charge\n");
-+                      di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-+                      di->full_counter = 0;
-+              }
-+              else if (di->current_uA < 10000 &&
-+                          di->charge_status != POWER_SUPPLY_STATUS_FULL) {
-+
-+                      /* Don't consider the battery to be full unless
-+                       * we've seen the current < 10 mA at least two
-+                       * consecutive times. */
-+
-+                      di->full_counter++;
-+
-+                      if (di->full_counter < 2)
-+                              di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
-+                      else {
-+                              unsigned char acr[2];
-+                              int acr_val;
-+
-+                              /* acr is in units of 0.25 mAh */
-+                              acr_val = di->full_active_uAh * 4L / 1000;
-+
-+                              acr[0] = acr_val >> 8;
-+                              acr[1] = acr_val & 0xff;
-+
-+                              if (w1_ds2760_write(di->w1_dev, acr,
-+                                  DS2760_CURRENT_ACCUM_MSB, 2) < 2)
-+                                      dev_warn(di->dev,
-+                                               "ACR reset failed\n");
-+
-+                              di->charge_status = POWER_SUPPLY_STATUS_FULL;
-+                      }
-+              }
-+      }
-+      else {
-+              di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
-+              di->full_counter = 0;
-+      }
-+
-+      if (di->charge_status != old_charge_status)
-+              power_supply_changed(&di->bat);
-+
-+      return;
-+}
-+
-+static void ds2760_battery_work(struct work_struct *work)
-+{
-+      struct ds2760_device_info *di = container_of(work,
-+              struct ds2760_device_info, monitor_work.work);
-+      const int interval = HZ * 60;
-+
-+      dev_dbg(di->dev, "%s\n", __FUNCTION__);
-+
-+      ds2760_battery_update_status(di);
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
-+
-+      return;
-+}
-+
-+#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \
-+                                              bat);
-+
-+static void ds2760_battery_external_power_changed(struct power_supply *psy)
-+{
-+      struct ds2760_device_info *di = to_ds2760_device_info(psy);
-+
-+      dev_dbg(di->dev, "%s\n", __FUNCTION__);
-+
-+      cancel_delayed_work(&di->monitor_work);
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
-+
-+      return;
-+}
-+
-+static int ds2760_battery_get_property(struct power_supply *psy,
-+                                       enum power_supply_property psp,
-+                                       union power_supply_propval *val)
-+{
-+      struct ds2760_device_info *di = to_ds2760_device_info(psy);
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              val->intval = di->charge_status;
-+              return 0;
-+      default:
-+              break;
-+      }
-+
-+      ds2760_battery_read_status(di);
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+              val->intval = di->voltage_uV;
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_NOW:
-+              val->intval = di->current_uA;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-+              val->intval = di->rated_capacity;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_FULL:
-+              val->intval = di->full_active_uAh;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_EMPTY:
-+              val->intval = di->empty_uAh;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_NOW:
-+              val->intval = di->accum_current_uAh;
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = di->temp_C;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property ds2760_battery_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+      POWER_SUPPLY_PROP_CURRENT_NOW,
-+      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+      POWER_SUPPLY_PROP_CHARGE_FULL,
-+      POWER_SUPPLY_PROP_CHARGE_EMPTY,
-+      POWER_SUPPLY_PROP_CHARGE_NOW,
-+      POWER_SUPPLY_PROP_TEMP,
-+};
-+
-+static int ds2760_battery_probe(struct platform_device *pdev)
-+{
-+      int retval = 0;
-+      struct ds2760_device_info *di;
-+      struct ds2760_platform_data *pdata;
-+
-+      di = kzalloc(sizeof(*di), GFP_KERNEL);
-+      if (!di) {
-+              retval = -ENOMEM;
-+              goto di_alloc_failed;
-+      }
-+
-+      platform_set_drvdata(pdev, di);
-+
-+      pdata = pdev->dev.platform_data;
-+      di->dev                = &pdev->dev;
-+      di->w1_dev             = pdev->dev.parent;
-+      di->bat.name           = pdev->dev.bus_id;
-+      di->bat.type           = POWER_SUPPLY_TYPE_BATTERY;
-+      di->bat.properties     = ds2760_battery_props;
-+      di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
-+      di->bat.get_property   = ds2760_battery_get_property;
-+      di->bat.external_power_changed =
-+                                ds2760_battery_external_power_changed;
-+      di->bat.use_for_apm = 1;
-+
-+      di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+      retval = power_supply_register(&pdev->dev, &di->bat);
-+      if (retval) {
-+              dev_err(di->dev, "failed to register battery");
-+              goto batt_failed;
-+      }
-+
-+      INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
-+      di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id);
-+      if (!di->monitor_wqueue) {
-+              retval = -ESRCH;
-+              goto workqueue_failed;
-+      }
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1);
-+
-+      goto success;
-+
-+workqueue_failed:
-+      power_supply_unregister(&di->bat);
-+batt_failed:
-+      kfree(di);
-+di_alloc_failed:
-+success:
-+      return retval;
-+}
-+
-+static int ds2760_battery_remove(struct platform_device *pdev)
-+{
-+      struct ds2760_device_info *di = platform_get_drvdata(pdev);
-+
-+      cancel_rearming_delayed_workqueue(di->monitor_wqueue,
-+                                        &di->monitor_work);
-+      destroy_workqueue(di->monitor_wqueue);
-+      power_supply_unregister(&di->bat);
-+
-+      return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+
-+static int ds2760_battery_suspend(struct platform_device *pdev,
-+                                  pm_message_t state)
-+{
-+      struct ds2760_device_info *di = platform_get_drvdata(pdev);
-+
-+      di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+      return 0;
-+}
-+
-+static int ds2760_battery_resume(struct platform_device *pdev)
-+{
-+      struct ds2760_device_info *di = platform_get_drvdata(pdev);
-+
-+      di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-+      power_supply_changed(&di->bat);
-+
-+      cancel_delayed_work(&di->monitor_work);
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
-+
-+      return 0;
-+}
-+
-+#else
-+
-+#define ds2760_battery_suspend NULL
-+#define ds2760_battery_resume NULL
-+
-+#endif /* CONFIG_PM */
-+
-+static struct platform_driver ds2760_battery_driver = {
-+      .driver = {
-+              .name = "ds2760-battery",
-+      },
-+      .probe    = ds2760_battery_probe,
-+      .remove   = ds2760_battery_remove,
-+      .suspend  = ds2760_battery_suspend,
-+      .resume   = ds2760_battery_resume,
-+};
-+
-+static int __init ds2760_battery_init(void)
-+{
-+      return platform_driver_register(&ds2760_battery_driver);
-+}
-+
-+static void __exit ds2760_battery_exit(void)
-+{
-+      platform_driver_unregister(&ds2760_battery_driver);
-+      return;
-+}
-+
-+module_init(ds2760_battery_init);
-+module_exit(ds2760_battery_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
-+              "Matt Reimer <mreimer@vpop.net>, "
-+              "Anton Vorontsov <cbou@mail.ru>");
-+MODULE_DESCRIPTION("ds2760 battery driver");
-Index: linux-2.6.22/drivers/power/Kconfig
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/Kconfig 2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,70 @@
-+menuconfig POWER_SUPPLY
-+      tristate "Power supply class support"
-+      help
-+        Say Y here to enable power supply class support. This allows
-+        power supply (batteries, AC, USB) monitoring by userspace
-+        via sysfs and uevent (if available) and/or APM kernel interface
-+        (if selected below).
-+
-+if POWER_SUPPLY
-+
-+config POWER_SUPPLY_DEBUG
-+      bool "Power supply debug"
-+      help
-+        Say Y here to enable debugging messages for power supply class
-+        and drivers.
-+
-+config PDA_POWER
-+      tristate "Generic PDA/phone power driver"
-+      help
-+        Say Y here to enable generic power driver for PDAs and phones with
-+        one or two external power supplies (AC/USB) connected to main and
-+        backup batteries, and optional builtin charger.
-+
-+config APM_POWER
-+      tristate "APM emulation for class batteries"
-+      depends on APM_EMULATION
-+      help
-+        Say Y here to enable support APM status emulation using
-+        battery class devices.
-+
-+config BATTERY_DS2760
-+      tristate "DS2760 battery driver (HP iPAQ & others)"
-+      select W1
-+      select W1_SLAVE_DS2760
-+      help
-+        Say Y here to enable support for batteries with ds2760 chip.
-+
-+config BATTERY_PMU
-+      tristate "Apple PMU battery"
-+      depends on ADB_PMU
-+      help
-+        Say Y here to expose battery information on Apple machines
-+        through the generic battery class.
-+
-+config BATTERY_OLPC
-+      tristate "One Laptop Per Child battery"
-+      depends on X86_32
-+      help
-+        Say Y to enable support for the battery on the OLPC laptop.
-+
-+# drivers below are not in battery2-2.6 tree
-+
-+config ADC_BATTERY
-+      tristate "Generic ADC battery driver"
-+      depends on ADC && POWER_SUPPLY
-+      help
-+        Say Y here to enable support for battery monitoring using generic ADC device.
-+
-+config IPAQ_MICRO_BATTERY
-+      tristate "HP iPAQ Micro ASIC battery driver"
-+      depends on IPAQ_MICRO && POWER_SUPPLY
-+      help
-+        Choose this option if you want to monitor battery status on
-+        Compaq/HP iPAQ h3100 h3600
-+
-+config MCP_UCB1x00_SIMPAD_BATTERY
-+      tristate "SIMpad Battery Reading Support"
-+      depends on MCP_UCB1x00 && POWER_SUPPLY
-+
-+endif # POWER_SUPPLY
-Index: linux-2.6.22/drivers/power/Makefile
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/Makefile        2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,28 @@
-+power_supply-objs := power_supply_core.o
-+
-+ifeq ($(CONFIG_SYSFS),y)
-+power_supply-objs += power_supply_sysfs.o
-+endif
-+
-+ifeq ($(CONFIG_LEDS_TRIGGERS),y)
-+power_supply-objs += power_supply_leds.o
-+endif
-+
-+ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y)
-+EXTRA_CFLAGS += -DDEBUG
-+endif
-+
-+obj-$(CONFIG_POWER_SUPPLY)         += power_supply.o
-+
-+obj-$(CONFIG_PDA_POWER)            += pda_power.o
-+obj-$(CONFIG_APM_POWER)            += apm_power.o
-+
-+obj-$(CONFIG_BATTERY_DS2760)       += ds2760_battery.o
-+obj-$(CONFIG_BATTERY_PMU)          += pmu_battery.o
-+obj-$(CONFIG_BATTERY_OLPC)         += olpc_battery.o
-+
-+# drivers below are not in battery2-2.6 tree
-+
-+obj-$(CONFIG_ADC_BATTERY)          += adc_battery.o
-+obj-$(CONFIG_IPAQ_MICRO_BATTERY)   += micro_battery.o
-+obj-$(CONFIG_MCP_UCB1x00_SIMPAD_BATTERY) += simpad-battery.o
-Index: linux-2.6.22/drivers/power/micro_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/micro_battery.c 2007-08-23 12:25:20.000000000 +0200
-@@ -0,0 +1,257 @@
-+/*
-+ * 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.
-+ *
-+ * h3600 atmel micro companion support, battery subdevice
-+ * based on previous kernel 2.4 version
-+ * Author : Alessandro Gardich <gremlin@gremlin.it>
-+ *
-+ */
-+
-+
-+#include <linux/module.h>
-+#include <linux/version.h>
-+
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/pm.h>
-+#include <linux/sysctl.h>
-+#include <linux/proc_fs.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/power_supply.h>
-+#include <linux/platform_device.h>
-+#include <linux/timer.h>
-+
-+#include <asm/arch/hardware.h>
-+
-+#include <asm/arch/h3600.h>
-+#include <asm/arch/SA-1100.h>
-+
-+#include <asm/hardware/micro.h>
-+
-+#define BATT_PERIOD 10*HZ
-+
-+#define H3600_BATT_STATUS_HIGH         0x01
-+#define H3600_BATT_STATUS_LOW          0x02
-+#define H3600_BATT_STATUS_CRITICAL     0x04
-+#define H3600_BATT_STATUS_CHARGING     0x08
-+#define H3600_BATT_STATUS_CHARGEMAIN   0x10
-+#define H3600_BATT_STATUS_DEAD         0x20 /* Battery will not charge */
-+#define H3600_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */
-+#define H3600_BATT_STATUS_FULL         0x40 /* Battery fully charged (and connected to AC) */
-+#define H3600_BATT_STATUS_NOBATTERY    0x80
-+#define H3600_BATT_STATUS_UNKNOWN      0xff
-+
-+
-+//static struct power_supply_dev *micro_battery;
-+
-+static micro_private_t *p_micro;
-+
-+struct timer_list batt_timer;
-+
-+struct {
-+      int ac;
-+      int update_time;
-+      int chemistry;
-+      int voltage;
-+      int temperature;
-+      int flag;
-+} micro_battery;
-+
-+static void micro_battery_receive (int len, unsigned char *data) {
-+      if (0) {
-+              printk(KERN_ERR "h3600_battery - AC = %02x\n", data[0]);
-+              printk(KERN_ERR "h3600_battery - BAT1 chemistry = %02x\n", data[1]);
-+              printk(KERN_ERR "h3600_battery - BAT1 voltage = %d %02x%02x\n", (data[3]<<8)+data[2], data[2], data[3]);
-+              printk(KERN_ERR "h3600_battery - BAT1 status = %02x\n", data[4]);
-+      }
-+
-+      micro_battery.ac = data[0];
-+      micro_battery.chemistry = data[1];
-+      micro_battery.voltage = ((((unsigned short)data[3]<<8)+data[2]) * 5000L ) * 1000 / 1024;
-+      micro_battery.flag = data[4];
-+
-+      if (len == 9) {
-+              if (0) {
-+                      printk(KERN_ERR "h3600_battery - BAT2 chemistry = %02x\n", data[5]);
-+                      printk(KERN_ERR "h3600_battery - BAT2 voltage = %d %02x%02x\n", (data[7]<<8)+data[6], data[6], data[7]);
-+                      printk(KERN_ERR "h3600_battery - BAT2 status = %02x\n", data[8]);
-+              }
-+      }
-+}
-+
-+static void micro_temperature_receive (int len, unsigned char *data) {
-+      micro_battery.temperature = ((unsigned short)data[1]<<8)+data[0];
-+}
-+
-+void h3600_battery_read_status(unsigned long data) {
-+
-+      if (++data % 2)
-+              h3600_micro_tx_msg(0x09,0,NULL);
-+      else
-+              h3600_micro_tx_msg(0x06,0,NULL);
-+
-+      batt_timer.expires += BATT_PERIOD;
-+      batt_timer.data = data;
-+
-+      add_timer(&batt_timer);
-+}
-+
-+int get_capacity(struct power_supply *b) {
-+    switch (micro_battery.flag) {
-+    case H3600_BATT_STATUS_HIGH :     return 100; break;
-+    case H3600_BATT_STATUS_LOW :      return 50; break;
-+    case H3600_BATT_STATUS_CRITICAL : return 5; break;
-+    default: break;
-+    }
-+    return 0;
-+}
-+
-+int get_status(struct power_supply *b) {
-+
-+   if (micro_battery.flag == H3600_BATT_STATUS_UNKNOWN)
-+      return POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+   if (micro_battery.flag & H3600_BATT_STATUS_FULL)
-+      return POWER_SUPPLY_STATUS_FULL;
-+
-+   if ((micro_battery.flag & H3600_BATT_STATUS_CHARGING) ||
-+       (micro_battery.flag & H3600_BATT_STATUS_CHARGEMAIN))
-+      return POWER_SUPPLY_STATUS_CHARGING;
-+
-+   return POWER_SUPPLY_STATUS_DISCHARGING;
-+}
-+
-+static int micro_batt_get_property(struct power_supply *b,
-+                                   enum power_supply_property psp,
-+                                   union power_supply_propval *val)
-+{
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              val->intval = get_status(b);
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-+              val->intval = 4700000;
-+              break;
-+      case POWER_SUPPLY_PROP_CAPACITY:
-+              val->intval = get_capacity(b);
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = micro_battery.temperature;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+              val->intval = micro_battery.voltage;
-+              break;
-+      default:
-+              return -EINVAL;
-+      };
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property micro_batt_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+      POWER_SUPPLY_PROP_CAPACITY,
-+      POWER_SUPPLY_PROP_TEMP,
-+      POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+};
-+
-+static struct power_supply h3600_battery = {
-+      .name               = "main-battery",
-+      .properties         = micro_batt_props,
-+      .num_properties     = ARRAY_SIZE(micro_batt_props),
-+      .get_property       = micro_batt_get_property,
-+      .use_for_apm        = 1,
-+};
-+
-+static int micro_batt_probe (struct platform_device *pdev)
-+{
-+      if (1) printk(KERN_ERR "micro battery probe : begin\n");
-+
-+      power_supply_register(&pdev->dev, &h3600_battery);
-+
-+      { /*--- callback ---*/
-+              p_micro = platform_get_drvdata(pdev);
-+              spin_lock(p_micro->lock);
-+              p_micro->h_batt = micro_battery_receive;
-+              p_micro->h_temp = micro_temperature_receive;
-+              spin_unlock(p_micro->lock);
-+      }
-+
-+      { /*--- timer ---*/
-+              init_timer(&batt_timer);
-+              batt_timer.expires = jiffies + BATT_PERIOD;
-+              batt_timer.data = 0;
-+              batt_timer.function = h3600_battery_read_status;
-+
-+              add_timer(&batt_timer);
-+      }
-+
-+      if (1) printk(KERN_ERR "micro battery probe : end\n");
-+      return 0;
-+}
-+
-+static int micro_batt_remove (struct platform_device *pdev)
-+{
-+      power_supply_unregister(&h3600_battery);
-+      { /*--- callback ---*/
-+              init_timer(&batt_timer);
-+              p_micro->h_batt = NULL;
-+              p_micro->h_temp = NULL;
-+              spin_unlock(p_micro->lock);
-+      }
-+      { /*--- timer ---*/
-+              del_timer_sync(&batt_timer);
-+      }
-+        return 0;
-+}
-+
-+static int micro_batt_suspend ( struct platform_device *pdev, pm_message_t state)
-+{
-+      { /*--- timer ---*/
-+              del_timer(&batt_timer);
-+      }
-+      return 0;
-+}
-+
-+static int micro_batt_resume ( struct platform_device *pdev)
-+{
-+      { /*--- timer ---*/
-+              add_timer(&batt_timer);
-+      }
-+      return 0;
-+}
-+
-+struct platform_driver micro_batt_device_driver = {
-+      .driver  = {
-+              .name    = "h3600-micro-battery",
-+      },
-+      .probe   = micro_batt_probe,
-+      .remove  = micro_batt_remove,
-+      .suspend = micro_batt_suspend,
-+      .resume  = micro_batt_resume,
-+};
-+
-+static int micro_batt_init (void)
-+{
-+      return platform_driver_register(&micro_batt_device_driver);
-+}
-+
-+static void micro_batt_cleanup (void)
-+{
-+      platform_driver_unregister (&micro_batt_device_driver);
-+}
-+
-+module_init (micro_batt_init);
-+module_exit (micro_batt_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("gremlin.it");
-+MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery");
-+
-+
-Index: linux-2.6.22/drivers/power/olpc_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/olpc_battery.c  2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,302 @@
-+/*
-+ * Battery driver for One Laptop Per Child board.
-+ *
-+ *    Copyright Â© 2006  David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * 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/module.h>
-+#include <linux/err.h>
-+#include <linux/platform_device.h>
-+#include <linux/power_supply.h>
-+#include <linux/jiffies.h>
-+#include <linux/sched.h>
-+#include <asm/io.h>
-+
-+#define wBAT_VOLTAGE     0xf900  /* *9.76/32,    mV   */
-+#define wBAT_CURRENT     0xf902  /* *15.625/120, mA   */
-+#define wBAT_TEMP        0xf906  /* *256/1000,   Â°C  */
-+#define wAMB_TEMP        0xf908  /* *256/1000,   Â°C  */
-+#define SOC              0xf910  /* percentage        */
-+#define sMBAT_STATUS     0xfaa4
-+#define sBAT_PRESENT          1
-+#define sBAT_FULL             2
-+#define sBAT_DESTROY          4  /* what is this exactly? */
-+#define sBAT_LOW             32
-+#define sBAT_DISCHG          64
-+#define sMCHARGE_STATUS  0xfaa5
-+#define sBAT_CHARGE           1
-+#define sBAT_OVERTEMP         4
-+#define sBAT_NiMH             8
-+#define sPOWER_FLAG      0xfa40
-+#define ADAPTER_IN            1
-+
-+/*********************************************************************
-+ *            EC locking and access
-+ *********************************************************************/
-+
-+static int lock_ec(void)
-+{
-+      unsigned long timeo = jiffies + HZ / 20;
-+
-+      while (1) {
-+              unsigned char lock = inb(0x6c) & 0x80;
-+              if (!lock)
-+                      return 0;
-+              if (time_after(jiffies, timeo)) {
-+                      printk(KERN_ERR "olpc_battery: failed to lock EC for "
-+                             "battery access\n");
-+                      return 1;
-+              }
-+              yield();
-+      }
-+}
-+
-+static void unlock_ec(void)
-+{
-+      outb(0xff, 0x6c);
-+      return;
-+}
-+
-+static unsigned char read_ec_byte(unsigned short adr)
-+{
-+      outb(adr >> 8, 0x381);
-+      outb(adr, 0x382);
-+      return inb(0x383);
-+}
-+
-+static unsigned short read_ec_word(unsigned short adr)
-+{
-+      return (read_ec_byte(adr) << 8) | read_ec_byte(adr + 1);
-+}
-+
-+/*********************************************************************
-+ *            Power
-+ *********************************************************************/
-+
-+static int olpc_ac_get_prop(struct power_supply *psy,
-+                            enum power_supply_property psp,
-+                            union power_supply_propval *val)
-+{
-+      int ret = 0;
-+
-+      if (lock_ec())
-+              return -EIO;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_ONLINE:
-+              if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
-+                      ret = -ENODEV;
-+                      goto out;
-+              }
-+              val->intval = !!(read_ec_byte(sPOWER_FLAG) & ADAPTER_IN);
-+              break;
-+      default:
-+              ret = -EINVAL;
-+              break;
-+      }
-+out:
-+      unlock_ec();
-+      return ret;
-+}
-+
-+static enum power_supply_property olpc_ac_props[] = {
-+      POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static struct power_supply olpc_ac = {
-+      .name = "olpc-ac",
-+      .type = POWER_SUPPLY_TYPE_MAINS,
-+      .properties = olpc_ac_props,
-+      .num_properties = ARRAY_SIZE(olpc_ac_props),
-+      .get_property = olpc_ac_get_prop,
-+};
-+
-+/*********************************************************************
-+ *            Battery properties
-+ *********************************************************************/
-+
-+static int olpc_bat_get_property(struct power_supply *psy,
-+                                 enum power_supply_property psp,
-+                                 union power_supply_propval *val)
-+{
-+      int ret = 0;
-+
-+      if (lock_ec())
-+              return -EIO;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              {
-+                      int status = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+                      val->intval = read_ec_byte(sMBAT_STATUS);
-+
-+                      if (!(val->intval & sBAT_PRESENT)) {
-+                              ret = -ENODEV;
-+                              goto out;
-+                      }
-+
-+                      if (val->intval & sBAT_DISCHG)
-+                              status = POWER_SUPPLY_STATUS_DISCHARGING;
-+                      else if (val->intval & sBAT_FULL)
-+                              status = POWER_SUPPLY_STATUS_FULL;
-+
-+                      val->intval = read_ec_byte(sMCHARGE_STATUS);
-+                      if (val->intval & sBAT_CHARGE)
-+                              status = POWER_SUPPLY_STATUS_CHARGING;
-+
-+                      val->intval = status;
-+                      break;
-+              }
-+      case POWER_SUPPLY_PROP_PRESENT:
-+              val->intval = !!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT);
-+              break;
-+      case POWER_SUPPLY_PROP_HEALTH:
-+              val->intval = read_ec_byte(sMCHARGE_STATUS);
-+              if (val->intval & sBAT_OVERTEMP)
-+                      val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
-+              else
-+                      val->intval = POWER_SUPPLY_HEALTH_GOOD;
-+              break;
-+      case POWER_SUPPLY_PROP_TECHNOLOGY:
-+              val->intval = read_ec_byte(sMCHARGE_STATUS);
-+              if (val->intval & sBAT_NiMH)
-+                      val->intval = POWER_SUPPLY_TECHNOLOGY_NIMH;
-+              else
-+                      val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_AVG:
-+              val->intval = read_ec_byte(wBAT_VOLTAGE) * 9760L / 32;
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_AVG:
-+              val->intval = read_ec_byte(wBAT_CURRENT) * 15625L / 120;
-+              break;
-+      case POWER_SUPPLY_PROP_CAPACITY:
-+              val->intval = read_ec_byte(SOC);
-+              break;
-+      case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
-+              val->intval = read_ec_byte(sMBAT_STATUS);
-+              if (val->intval & sBAT_FULL)
-+                      val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-+              else if (val->intval & sBAT_LOW)
-+                      val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
-+              else
-+                      val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = read_ec_byte(wBAT_TEMP) * 256 / 100;
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP_AMBIENT:
-+              val->intval = read_ec_byte(wAMB_TEMP) * 256 / 100;
-+              break;
-+      default:
-+              ret = -EINVAL;
-+              break;
-+      }
-+
-+out:
-+      unlock_ec();
-+      return ret;
-+}
-+
-+static enum power_supply_property olpc_bat_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_PRESENT,
-+      POWER_SUPPLY_PROP_HEALTH,
-+      POWER_SUPPLY_PROP_TECHNOLOGY,
-+      POWER_SUPPLY_PROP_VOLTAGE_AVG,
-+      POWER_SUPPLY_PROP_CURRENT_AVG,
-+      POWER_SUPPLY_PROP_CAPACITY,
-+      POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-+      POWER_SUPPLY_PROP_TEMP,
-+      POWER_SUPPLY_PROP_TEMP_AMBIENT,
-+};
-+
-+/*********************************************************************
-+ *            Initialisation
-+ *********************************************************************/
-+
-+static struct platform_device *bat_pdev;
-+
-+static struct power_supply olpc_bat = {
-+      .properties = olpc_bat_props,
-+      .num_properties = ARRAY_SIZE(olpc_bat_props),
-+      .get_property = olpc_bat_get_property,
-+      .use_for_apm = 1,
-+};
-+
-+static int __init olpc_bat_init(void)
-+{
-+      int ret = 0;
-+      unsigned short tmp;
-+
-+      if (!request_region(0x380, 4, "olpc-battery")) {
-+              ret = -EIO;
-+              goto region_failed;
-+      }
-+
-+      if (lock_ec()) {
-+              ret = -EIO;
-+              goto lock_failed;
-+      }
-+
-+      tmp = read_ec_word(0xfe92);
-+      unlock_ec();
-+
-+      if (tmp != 0x380) {
-+              /* Doesn't look like OLPC EC */
-+              ret = -ENODEV;
-+              goto not_olpc_ec;
-+      }
-+
-+      bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
-+      if (IS_ERR(bat_pdev)) {
-+              ret = PTR_ERR(bat_pdev);
-+              goto pdev_failed;
-+      }
-+
-+      ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
-+      if (ret)
-+              goto ac_failed;
-+
-+      olpc_bat.name = bat_pdev->name;
-+
-+      ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
-+      if (ret)
-+              goto battery_failed;
-+
-+      goto success;
-+
-+battery_failed:
-+      power_supply_unregister(&olpc_ac);
-+ac_failed:
-+      platform_device_unregister(bat_pdev);
-+pdev_failed:
-+not_olpc_ec:
-+lock_failed:
-+      release_region(0x380, 4);
-+region_failed:
-+success:
-+      return ret;
-+}
-+
-+static void __exit olpc_bat_exit(void)
-+{
-+      power_supply_unregister(&olpc_bat);
-+      power_supply_unregister(&olpc_ac);
-+      platform_device_unregister(bat_pdev);
-+      release_region(0x380, 4);
-+      return;
-+}
-+
-+module_init(olpc_bat_init);
-+module_exit(olpc_bat_exit);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Battery driver for One Laptop Per Child "
-+                   "($100 laptop) board.");
-Index: linux-2.6.22/drivers/power/pda_power.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/pda_power.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,263 @@
-+/*
-+ * Common power driver for PDAs and phones with one or two external
-+ * power supplies (AC/USB) connected to main and backup batteries,
-+ * and optional builtin charger.
-+ *
-+ * Copyright 2007 Anton Vorontsov <cbou@mail.ru>
-+ *
-+ * 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/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/interrupt.h>
-+#include <linux/power_supply.h>
-+#include <linux/pda_power.h>
-+#include <linux/timer.h>
-+#include <linux/jiffies.h>
-+
-+static inline unsigned int get_irq_flags(struct resource *res)
-+{
-+      unsigned int flags = IRQF_DISABLED | IRQF_SHARED;
-+
-+      flags |= res->flags & IRQF_TRIGGER_MASK;
-+
-+      return flags;
-+}
-+
-+static struct device *dev;
-+static struct pda_power_pdata *pdata;
-+static struct resource *ac_irq, *usb_irq;
-+static struct timer_list charger_timer;
-+static struct timer_list supply_timer;
-+
-+static int pda_power_get_property(struct power_supply *psy,
-+                                  enum power_supply_property psp,
-+                                  union power_supply_propval *val)
-+{
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_ONLINE:
-+              if (psy->type == POWER_SUPPLY_TYPE_MAINS)
-+                      val->intval = pdata->is_ac_online ?
-+                                    pdata->is_ac_online() : 0;
-+              else
-+                      val->intval = pdata->is_usb_online ?
-+                                    pdata->is_usb_online() : 0;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+      return 0;
-+}
-+
-+static enum power_supply_property pda_power_props[] = {
-+      POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static char *pda_power_supplied_to[] = {
-+      "main-battery",
-+      "backup-battery",
-+};
-+
-+static struct power_supply pda_power_supplies[] = {
-+      {
-+              .name = "ac",
-+              .type = POWER_SUPPLY_TYPE_MAINS,
-+              .supplied_to = pda_power_supplied_to,
-+              .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
-+              .properties = pda_power_props,
-+              .num_properties = ARRAY_SIZE(pda_power_props),
-+              .get_property = pda_power_get_property,
-+      },
-+      {
-+              .name = "usb",
-+              .type = POWER_SUPPLY_TYPE_USB,
-+              .supplied_to = pda_power_supplied_to,
-+              .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
-+              .properties = pda_power_props,
-+              .num_properties = ARRAY_SIZE(pda_power_props),
-+              .get_property = pda_power_get_property,
-+      },
-+};
-+
-+static void update_charger(void)
-+{
-+      if (!pdata->set_charge)
-+              return;
-+
-+      if (pdata->is_ac_online && pdata->is_ac_online()) {
-+              dev_dbg(dev, "charger on (AC)\n");
-+              pdata->set_charge(PDA_POWER_CHARGE_AC);
-+      }
-+      else if (pdata->is_usb_online && pdata->is_usb_online()) {
-+              dev_dbg(dev, "charger on (USB)\n");
-+              pdata->set_charge(PDA_POWER_CHARGE_USB);
-+      }
-+      else {
-+              dev_dbg(dev, "charger off\n");
-+              pdata->set_charge(0);
-+      }
-+
-+      return;
-+}
-+
-+static void supply_timer_func(unsigned long irq)
-+{
-+      if (ac_irq && irq == ac_irq->start)
-+              power_supply_changed(&pda_power_supplies[0]);
-+      else if (usb_irq && irq == usb_irq->start)
-+              power_supply_changed(&pda_power_supplies[1]);
-+      return;
-+}
-+
-+static void charger_timer_func(unsigned long irq)
-+{
-+      update_charger();
-+
-+      /* Okay, charger set. Now wait a bit before notifying supplicants,
-+       * charge power should stabilize. */
-+      supply_timer.data = irq;
-+      mod_timer(&supply_timer,
-+                jiffies + msecs_to_jiffies(pdata->wait_for_charger));
-+      return;
-+}
-+
-+static irqreturn_t power_changed_isr(int irq, void *unused)
-+{
-+      /* Wait a bit before reading ac/usb line status and setting charger,
-+       * because ac/usb status readings may lag from irq. */
-+      charger_timer.data = irq;
-+      mod_timer(&charger_timer,
-+                jiffies + msecs_to_jiffies(pdata->wait_for_status));
-+      return IRQ_HANDLED;
-+}
-+
-+static int pda_power_probe(struct platform_device *pdev)
-+{
-+      int ret = 0;
-+
-+      dev = &pdev->dev;
-+
-+      if (pdev->id != -1) {
-+              dev_err(dev, "it's meaningless to register several "
-+                      "pda_powers, use id = -1\n");
-+              ret = -EINVAL;
-+              goto wrongid;
-+      }
-+
-+      pdata = pdev->dev.platform_data;
-+
-+      update_charger();
-+
-+      if (!pdata->wait_for_status)
-+              pdata->wait_for_status = 500;
-+
-+      if (!pdata->wait_for_charger)
-+              pdata->wait_for_charger = 500;
-+
-+      setup_timer(&charger_timer, charger_timer_func, 0);
-+      setup_timer(&supply_timer, supply_timer_func, 0);
-+
-+      ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
-+      usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
-+      if (!ac_irq && !usb_irq) {
-+              dev_err(dev, "no ac/usb irq specified\n");
-+              ret = -ENODEV;
-+              goto noirqs;
-+      }
-+
-+      if (pdata->supplied_to) {
-+              pda_power_supplies[0].supplied_to = pdata->supplied_to;
-+              pda_power_supplies[1].supplied_to = pdata->supplied_to;
-+              pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
-+              pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
-+      }
-+
-+      ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
-+      if (ret) {
-+              dev_err(dev, "failed to register %s power supply\n",
-+                      pda_power_supplies[0].name);
-+              goto supply0_failed;
-+      }
-+
-+      ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
-+      if (ret) {
-+              dev_err(dev, "failed to register %s power supply\n",
-+                      pda_power_supplies[1].name);
-+              goto supply1_failed;
-+      }
-+
-+      if (ac_irq) {
-+              ret = request_irq(ac_irq->start, power_changed_isr,
-+                                get_irq_flags(ac_irq), ac_irq->name,
-+                                &pda_power_supplies[0]);
-+              if (ret) {
-+                      dev_err(dev, "request ac irq failed\n");
-+                      goto ac_irq_failed;
-+              }
-+      }
-+
-+      if (usb_irq) {
-+              ret = request_irq(usb_irq->start, power_changed_isr,
-+                                get_irq_flags(usb_irq), usb_irq->name,
-+                                &pda_power_supplies[1]);
-+              if (ret) {
-+                      dev_err(dev, "request usb irq failed\n");
-+                      goto usb_irq_failed;
-+              }
-+      }
-+
-+      goto success;
-+
-+usb_irq_failed:
-+      if (ac_irq)
-+              free_irq(ac_irq->start, &pda_power_supplies[0]);
-+ac_irq_failed:
-+      power_supply_unregister(&pda_power_supplies[1]);
-+supply1_failed:
-+      power_supply_unregister(&pda_power_supplies[0]);
-+supply0_failed:
-+noirqs:
-+wrongid:
-+success:
-+      return ret;
-+}
-+
-+static int pda_power_remove(struct platform_device *pdev)
-+{
-+      if (usb_irq)
-+              free_irq(usb_irq->start, &pda_power_supplies[1]);
-+      if (ac_irq)
-+              free_irq(ac_irq->start, &pda_power_supplies[0]);
-+      del_timer_sync(&charger_timer);
-+      del_timer_sync(&supply_timer);
-+      power_supply_unregister(&pda_power_supplies[1]);
-+      power_supply_unregister(&pda_power_supplies[0]);
-+      return 0;
-+}
-+
-+static struct platform_driver pda_power_pdrv = {
-+      .driver = {
-+              .name = "pda-power",
-+      },
-+      .probe = pda_power_probe,
-+      .remove = pda_power_remove,
-+};
-+
-+static int __init pda_power_init(void)
-+{
-+      return platform_driver_register(&pda_power_pdrv);
-+}
-+
-+static void __exit pda_power_exit(void)
-+{
-+      platform_driver_unregister(&pda_power_pdrv);
-+      return;
-+}
-+
-+module_init(pda_power_init);
-+module_exit(pda_power_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
-Index: linux-2.6.22/drivers/power/pmu_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/pmu_battery.c   2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,215 @@
-+/*
-+ * Battery class driver for Apple PMU
-+ *
-+ *    Copyright Â© 2006  David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * 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/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/power_supply.h>
-+#include <linux/adb.h>
-+#include <linux/pmu.h>
-+
-+static struct pmu_battery_dev {
-+      struct power_supply bat;
-+      struct pmu_battery_info *pbi;
-+      char name[16];
-+      int propval;
-+} *pbats[PMU_MAX_BATTERIES];
-+
-+#define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
-+
-+/*********************************************************************
-+ *            Power
-+ *********************************************************************/
-+
-+static int pmu_get_ac_prop(struct power_supply *psy,
-+                           enum power_supply_property psp,
-+                           union power_supply_propval *val)
-+{
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_ONLINE:
-+              val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
-+                            (pmu_battery_count == 0);
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property pmu_ac_props[] = {
-+      POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static struct power_supply pmu_ac = {
-+      .name = "pmu-ac",
-+      .type = POWER_SUPPLY_TYPE_MAINS,
-+      .properties = pmu_ac_props,
-+      .num_properties = ARRAY_SIZE(pmu_ac_props),
-+      .get_property = pmu_get_ac_prop,
-+};
-+
-+/*********************************************************************
-+ *            Battery properties
-+ *********************************************************************/
-+
-+static char *pmu_batt_types[] = {
-+      "Smart", "Comet", "Hooper", "Unknown"
-+};
-+
-+static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
-+{
-+      switch (pbi->flags & PMU_BATT_TYPE_MASK) {
-+      case PMU_BATT_TYPE_SMART:
-+              return pmu_batt_types[0];
-+      case PMU_BATT_TYPE_COMET:
-+              return pmu_batt_types[1];
-+      case PMU_BATT_TYPE_HOOPER:
-+              return pmu_batt_types[2];
-+      default: break;
-+      }
-+      return pmu_batt_types[3];
-+}
-+
-+static int pmu_bat_get_property(struct power_supply *psy,
-+                                enum power_supply_property psp,
-+                                union power_supply_propval *val)
-+{
-+      struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
-+      struct pmu_battery_info *pbi = pbat->pbi;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              if (pbi->flags & PMU_BATT_CHARGING)
-+                      val->intval = POWER_SUPPLY_STATUS_CHARGING;
-+              else
-+                      val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-+              break;
-+      case POWER_SUPPLY_PROP_PRESENT:
-+              val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
-+              break;
-+      case POWER_SUPPLY_PROP_MODEL_NAME:
-+              val->strval = pmu_bat_get_model_name(pbi);
-+              break;
-+      case POWER_SUPPLY_PROP_ENERGY_AVG:
-+              val->intval = pbi->charge     * 1000; /* mWh -> ÂµWh */
-+              break;
-+      case POWER_SUPPLY_PROP_ENERGY_FULL:
-+              val->intval = pbi->max_charge * 1000; /* mWh -> ÂµWh */
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_AVG:
-+              val->intval = pbi->amperage   * 1000; /* mA -> ÂµA */
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_AVG:
-+              val->intval = pbi->voltage    * 1000; /* mV -> ÂµV */
-+              break;
-+      case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
-+              val->intval = pbi->time_remaining;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property pmu_bat_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_PRESENT,
-+      POWER_SUPPLY_PROP_MODEL_NAME,
-+      POWER_SUPPLY_PROP_ENERGY_AVG,
-+      POWER_SUPPLY_PROP_ENERGY_FULL,
-+      POWER_SUPPLY_PROP_CURRENT_AVG,
-+      POWER_SUPPLY_PROP_VOLTAGE_AVG,
-+      POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
-+};
-+
-+/*********************************************************************
-+ *            Initialisation
-+ *********************************************************************/
-+
-+static struct platform_device *bat_pdev;
-+
-+static int __init pmu_bat_init(void)
-+{
-+      int ret;
-+      int i;
-+
-+      bat_pdev = platform_device_register_simple("pmu-battery",
-+                                                 0, NULL, 0);
-+      if (IS_ERR(bat_pdev)) {
-+              ret = PTR_ERR(bat_pdev);
-+              goto pdev_register_failed;
-+      }
-+
-+      ret = power_supply_register(&bat_pdev->dev, &pmu_ac);
-+      if (ret)
-+              goto ac_register_failed;
-+
-+      for (i = 0; i < pmu_battery_count; i++) {
-+              struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
-+                                                     GFP_KERNEL);
-+              if (!pbat)
-+                      break;
-+
-+              sprintf(pbat->name, "PMU battery %d", i);
-+              pbat->bat.name = pbat->name;
-+              pbat->bat.properties = pmu_bat_props;
-+              pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
-+              pbat->bat.get_property = pmu_bat_get_property;
-+              pbat->pbi = &pmu_batteries[i];
-+
-+              ret = power_supply_register(&bat_pdev->dev, &pbat->bat);
-+              if (ret) {
-+                      kfree(pbat);
-+                      goto battery_register_failed;
-+              }
-+              pbats[i] = pbat;
-+      }
-+
-+      goto success;
-+
-+battery_register_failed:
-+      while (i--) {
-+              if (!pbats[i])
-+                      continue;
-+              power_supply_unregister(&pbats[i]->bat);
-+              kfree(pbats[i]);
-+      }
-+      power_supply_unregister(&pmu_ac);
-+ac_register_failed:
-+      platform_device_unregister(bat_pdev);
-+pdev_register_failed:
-+success:
-+      return ret;
-+}
-+
-+static void __exit pmu_bat_exit(void)
-+{
-+      int i;
-+
-+      for (i = 0; i < PMU_MAX_BATTERIES; i++) {
-+              if (!pbats[i])
-+                      continue;
-+              power_supply_unregister(&pbats[i]->bat);
-+              kfree(pbats[i]);
-+      }
-+      power_supply_unregister(&pmu_ac);
-+      platform_device_unregister(bat_pdev);
-+
-+      return;
-+}
-+
-+module_init(pmu_bat_init);
-+module_exit(pmu_bat_exit);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("PMU battery driver");
-Index: linux-2.6.22/drivers/power/power_supply_core.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply_core.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,168 @@
-+/*
-+ *  Universal power supply monitor class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/err.h>
-+#include <linux/power_supply.h>
-+#include "power_supply.h"
-+
-+struct class *power_supply_class;
-+
-+static void power_supply_changed_work(struct work_struct *work)
-+{
-+      struct power_supply *psy = container_of(work, struct power_supply,
-+                                              changed_work);
-+      int i;
-+
-+      dev_dbg(psy->dev, "%s\n", __FUNCTION__);
-+
-+      for (i = 0; i < psy->num_supplicants; i++) {
-+              struct device *dev;
-+
-+              down(&power_supply_class->sem);
-+              list_for_each_entry(dev, &power_supply_class->devices, node) {
-+                      struct power_supply *pst = dev_get_drvdata(dev);
-+
-+                      if (!strcmp(psy->supplied_to[i], pst->name)) {
-+                              if (pst->external_power_changed)
-+                                      pst->external_power_changed(pst);
-+                      }
-+              }
-+              up(&power_supply_class->sem);
-+      }
-+
-+      power_supply_update_leds(psy);
-+
-+      kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
-+
-+      return;
-+}
-+
-+void power_supply_changed(struct power_supply *psy)
-+{
-+      dev_dbg(psy->dev, "%s\n", __FUNCTION__);
-+
-+      schedule_work(&psy->changed_work);
-+
-+      return;
-+}
-+
-+int power_supply_am_i_supplied(struct power_supply *psy)
-+{
-+      union power_supply_propval ret = {0,};
-+      struct device *dev;
-+
-+      down(&power_supply_class->sem);
-+      list_for_each_entry(dev, &power_supply_class->devices, node) {
-+              struct power_supply *epsy = dev_get_drvdata(dev);
-+              int i;
-+
-+              for (i = 0; i < epsy->num_supplicants; i++) {
-+                      if (!strcmp(epsy->supplied_to[i], psy->name)) {
-+                              if (epsy->get_property(epsy,
-+                                        POWER_SUPPLY_PROP_ONLINE, &ret))
-+                                      continue;
-+                              if (ret.intval)
-+                                      goto out;
-+                      }
-+              }
-+      }
-+out:
-+      up(&power_supply_class->sem);
-+
-+      dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
-+
-+      return ret.intval;
-+}
-+
-+int power_supply_register(struct device *parent, struct power_supply *psy)
-+{
-+      int rc = 0;
-+
-+      psy->dev = device_create(power_supply_class, parent, 0,
-+                               "%s", psy->name);
-+      if (IS_ERR(psy->dev)) {
-+              rc = PTR_ERR(psy->dev);
-+              goto dev_create_failed;
-+      }
-+
-+      dev_set_drvdata(psy->dev, psy);
-+
-+      INIT_WORK(&psy->changed_work, power_supply_changed_work);
-+
-+      rc = power_supply_create_attrs(psy);
-+      if (rc)
-+              goto create_attrs_failed;
-+
-+      rc = power_supply_create_triggers(psy);
-+      if (rc)
-+              goto create_triggers_failed;
-+
-+      power_supply_changed(psy);
-+
-+      goto success;
-+
-+create_triggers_failed:
-+      power_supply_remove_attrs(psy);
-+create_attrs_failed:
-+      device_unregister(psy->dev);
-+dev_create_failed:
-+success:
-+      return rc;
-+}
-+
-+void power_supply_unregister(struct power_supply *psy)
-+{
-+      flush_scheduled_work();
-+      power_supply_remove_triggers(psy);
-+      power_supply_remove_attrs(psy);
-+      device_unregister(psy->dev);
-+      return;
-+}
-+
-+static int __init power_supply_class_init(void)
-+{
-+      power_supply_class = class_create(THIS_MODULE, "power_supply");
-+
-+      if (IS_ERR(power_supply_class))
-+              return PTR_ERR(power_supply_class);
-+
-+      power_supply_class->dev_uevent = power_supply_uevent;
-+
-+      return 0;
-+}
-+
-+static void __exit power_supply_class_exit(void)
-+{
-+      class_destroy(power_supply_class);
-+      return;
-+}
-+
-+EXPORT_SYMBOL_GPL(power_supply_changed);
-+EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
-+EXPORT_SYMBOL_GPL(power_supply_register);
-+EXPORT_SYMBOL_GPL(power_supply_unregister);
-+
-+/* exported for the APM Power driver, APM emulation */
-+EXPORT_SYMBOL_GPL(power_supply_class);
-+
-+subsys_initcall(power_supply_class_init);
-+module_exit(power_supply_class_exit);
-+
-+MODULE_DESCRIPTION("Universal power supply monitor class");
-+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
-+              "Szabolcs Gyurko, "
-+              "Anton Vorontsov <cbou@mail.ru>");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/drivers/power/power_supply.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply.h  2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,42 @@
-+/*
-+ *  Functions private to power supply class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#ifdef CONFIG_SYSFS
-+
-+extern int power_supply_create_attrs(struct power_supply *psy);
-+extern void power_supply_remove_attrs(struct power_supply *psy);
-+extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-+                               char *buffer, int buffer_size);
-+
-+#else
-+
-+static inline int power_supply_create_attrs(struct power_supply *psy)
-+{ return 0; }
-+static inline void power_supply_remove_attrs(struct power_supply *psy) {}
-+#define power_supply_uevent NULL
-+
-+#endif /* CONFIG_SYSFS */
-+
-+#ifdef CONFIG_LEDS_TRIGGERS
-+
-+extern void power_supply_update_leds(struct power_supply *psy);
-+extern int power_supply_create_triggers(struct power_supply *psy);
-+extern void power_supply_remove_triggers(struct power_supply *psy);
-+
-+#else
-+
-+static inline void power_supply_update_leds(struct power_supply *psy) {}
-+static inline int power_supply_create_triggers(struct power_supply *psy)
-+{ return 0; }
-+static inline void power_supply_remove_triggers(struct power_supply *psy) {}
-+
-+#endif /* CONFIG_LEDS_TRIGGERS */
-Index: linux-2.6.22/drivers/power/power_supply_leds.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply_leds.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,188 @@
-+/*
-+ *  LEDs triggers for power supply class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#include <linux/power_supply.h>
-+
-+/* If we have hwtimer trigger, then use it to blink charging LED */
-+
-+#if defined(CONFIG_LEDS_TRIGGER_HWTIMER) ||                  \
-+               (defined(CONFIG_BATTERY_MODULE) &&            \
-+                defined(CONFIG_LEDS_TRIGGER_HWTIMER_MODULE))
-+       #define led_trigger_register_charging led_trigger_register_hwtimer
-+       #define led_trigger_unregister_charging led_trigger_unregister_hwtimer
-+#else
-+       #define led_trigger_register_charging led_trigger_register_simple
-+       #define led_trigger_unregister_charging led_trigger_unregister_simple
-+#endif
-+
-+/* Battery specific LEDs triggers. */
-+
-+static void power_supply_update_bat_leds(struct power_supply *psy)
-+{
-+      union power_supply_propval status;
-+
-+      if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
-+              return;
-+
-+      dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
-+
-+      switch(status.intval) {
-+      case POWER_SUPPLY_STATUS_FULL:
-+              led_trigger_event(psy->charging_full_trig, LED_FULL);
-+              led_trigger_event(psy->charging_trig, LED_OFF);
-+              led_trigger_event(psy->full_trig, LED_FULL);
-+              break;
-+      case POWER_SUPPLY_STATUS_CHARGING:
-+              led_trigger_event(psy->charging_full_trig, LED_FULL);
-+              led_trigger_event(psy->charging_trig, LED_FULL);
-+              led_trigger_event(psy->full_trig, LED_OFF);
-+              break;
-+      default:
-+              led_trigger_event(psy->charging_full_trig, LED_OFF);
-+              led_trigger_event(psy->charging_trig, LED_OFF);
-+              led_trigger_event(psy->full_trig, LED_OFF);
-+              break;
-+      }
-+
-+      return;
-+}
-+
-+static int power_supply_create_bat_triggers(struct power_supply *psy)
-+{
-+      int rc = 0;
-+
-+      psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
-+                                sizeof("-charging-or-full"), GFP_KERNEL);
-+      if (!psy->charging_full_trig_name)
-+              goto charging_full_failed;
-+
-+      psy->charging_trig_name = kmalloc(strlen(psy->name) +
-+                                        sizeof("-charging"), GFP_KERNEL);
-+      if (!psy->charging_trig_name)
-+              goto charging_failed;
-+
-+      psy->full_trig_name = kmalloc(strlen(psy->name) +
-+                                    sizeof("-full"), GFP_KERNEL);
-+      if (!psy->full_trig_name)
-+              goto full_failed;
-+
-+      strcpy(psy->charging_full_trig_name, psy->name);
-+      strcat(psy->charging_full_trig_name, "-charging-or-full");
-+      strcpy(psy->charging_trig_name, psy->name);
-+      strcat(psy->charging_trig_name, "-charging");
-+      strcpy(psy->full_trig_name, psy->name);
-+      strcat(psy->full_trig_name, "-full");
-+
-+      led_trigger_register_simple(psy->charging_full_trig_name,
-+                                  &psy->charging_full_trig);
-+      led_trigger_register_charging(psy->charging_trig_name,
-+                                    &psy->charging_trig);
-+      led_trigger_register_simple(psy->full_trig_name,
-+                                  &psy->full_trig);
-+
-+      goto success;
-+
-+full_failed:
-+      kfree(psy->charging_trig_name);
-+charging_failed:
-+      kfree(psy->charging_full_trig_name);
-+charging_full_failed:
-+      rc = -ENOMEM;
-+success:
-+      return rc;
-+}
-+
-+static void power_supply_remove_bat_triggers(struct power_supply *psy)
-+{
-+      led_trigger_unregister_simple(psy->charging_full_trig);
-+      led_trigger_unregister_charging(psy->charging_trig);
-+      led_trigger_unregister_simple(psy->full_trig);
-+      kfree(psy->full_trig_name);
-+      kfree(psy->charging_trig_name);
-+      kfree(psy->charging_full_trig_name);
-+      return;
-+}
-+
-+/* Generated power specific LEDs triggers. */
-+
-+static void power_supply_update_gen_leds(struct power_supply *psy)
-+{
-+      union power_supply_propval online;
-+
-+      if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
-+              return;
-+
-+      dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
-+
-+      if (online.intval)
-+              led_trigger_event(psy->online_trig, LED_FULL);
-+      else
-+              led_trigger_event(psy->online_trig, LED_OFF);
-+
-+      return;
-+}
-+
-+static int power_supply_create_gen_triggers(struct power_supply *psy)
-+{
-+      int rc = 0;
-+
-+      psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
-+                                      GFP_KERNEL);
-+      if (!psy->online_trig_name)
-+              goto online_failed;
-+
-+      strcpy(psy->online_trig_name, psy->name);
-+      strcat(psy->online_trig_name, "-online");
-+
-+      led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
-+
-+      goto success;
-+
-+online_failed:
-+      rc = -ENOMEM;
-+success:
-+      return rc;
-+}
-+
-+static void power_supply_remove_gen_triggers(struct power_supply *psy)
-+{
-+      led_trigger_unregister_simple(psy->online_trig);
-+      kfree(psy->online_trig_name);
-+      return;
-+}
-+
-+/* Choice what triggers to create&update. */
-+
-+void power_supply_update_leds(struct power_supply *psy)
-+{
-+      if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
-+              power_supply_update_bat_leds(psy);
-+      else
-+              power_supply_update_gen_leds(psy);
-+      return;
-+}
-+
-+int power_supply_create_triggers(struct power_supply *psy)
-+{
-+      if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
-+              return power_supply_create_bat_triggers(psy);
-+      return power_supply_create_gen_triggers(psy);
-+}
-+
-+void power_supply_remove_triggers(struct power_supply *psy)
-+{
-+      if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
-+              power_supply_remove_bat_triggers(psy);
-+      else
-+              power_supply_remove_gen_triggers(psy);
-+      return;
-+}
-Index: linux-2.6.22/drivers/power/power_supply_sysfs.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply_sysfs.c    2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,289 @@
-+/*
-+ *  Sysfs interface for the universal power supply monitor class
-+ *
-+ *  Copyright Â©  2007  David Woodhouse <dwmw2@infradead.org>
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#include <linux/ctype.h>
-+#include <linux/power_supply.h>
-+
-+/*
-+ * This is because the name "current" breaks the device attr macro.
-+ * The "current" word resolvs to "(get_current())" so instead of
-+ * "current" "(get_current())" appears in the sysfs.
-+ *
-+ * The source of this definition is the device.h which calls __ATTR
-+ * macro in sysfs.h which calls the __stringify macro.
-+ *
-+ * Only modification that the name is not tried to be resolved
-+ * (as a macro let's say).
-+ */
-+
-+#define POWER_SUPPLY_ATTR(_name)                                        \
-+{                                                                       \
-+      .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \
-+      .show = power_supply_show_property,                             \
-+      .store = NULL,                                                  \
-+}
-+
-+static struct device_attribute power_supply_attrs[];
-+
-+static ssize_t power_supply_show_property(struct device *dev,
-+                                          struct device_attribute *attr,
-+                                          char *buf) {
-+      static char *status_text[] = {
-+              "Unknown", "Charging", "Discharging", "Not charging", "Full"
-+      };
-+      static char *health_text[] = {
-+              "Unknown", "Good", "Overheat", "Dead"
-+      };
-+      static char *technology_text[] = {
-+              "Unknown", "NiMH", "Li-ion", "Li-poly"
-+      };
-+      static char *capacity_level_text[] = {
-+              "Unknown", "Critical", "Low", "Normal", "High", "Full"
-+      };
-+      ssize_t ret;
-+      struct power_supply *psy = dev_get_drvdata(dev);
-+      const ptrdiff_t off = attr - power_supply_attrs;
-+      union power_supply_propval value;
-+
-+      ret = psy->get_property(psy, off, &value);
-+
-+      if (ret < 0) {
-+              dev_err(dev, "driver failed to report `%s' property\n",
-+                      attr->attr.name);
-+              return ret;
-+      }
-+
-+      if (off == POWER_SUPPLY_PROP_STATUS)
-+              return sprintf(buf, "%s\n", status_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_HEALTH)
-+              return sprintf(buf, "%s\n", health_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
-+              return sprintf(buf, "%s\n", technology_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
-+              return sprintf(buf, "%s\n",
-+                             capacity_level_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_MODEL_NAME)
-+              return sprintf(buf, "%s\n", value.strval);
-+
-+      return sprintf(buf, "%d\n", value.intval);
-+}
-+
-+/* Must be in the same order as POWER_SUPPLY_PROP_* */
-+static struct device_attribute power_supply_attrs[] = {
-+      /* Properties of type `int' */
-+      POWER_SUPPLY_ATTR(status),
-+      POWER_SUPPLY_ATTR(health),
-+      POWER_SUPPLY_ATTR(present),
-+      POWER_SUPPLY_ATTR(online),
-+      POWER_SUPPLY_ATTR(technology),
-+      POWER_SUPPLY_ATTR(voltage_max_design),
-+      POWER_SUPPLY_ATTR(voltage_min_design),
-+      POWER_SUPPLY_ATTR(voltage_now),
-+      POWER_SUPPLY_ATTR(voltage_avg),
-+      POWER_SUPPLY_ATTR(current_now),
-+      POWER_SUPPLY_ATTR(current_avg),
-+      POWER_SUPPLY_ATTR(charge_full_design),
-+      POWER_SUPPLY_ATTR(charge_empty_design),
-+      POWER_SUPPLY_ATTR(charge_full),
-+      POWER_SUPPLY_ATTR(charge_empty),
-+      POWER_SUPPLY_ATTR(charge_now),
-+      POWER_SUPPLY_ATTR(charge_avg),
-+      POWER_SUPPLY_ATTR(energy_full_design),
-+      POWER_SUPPLY_ATTR(energy_empty_design),
-+      POWER_SUPPLY_ATTR(energy_full),
-+      POWER_SUPPLY_ATTR(energy_empty),
-+      POWER_SUPPLY_ATTR(energy_now),
-+      POWER_SUPPLY_ATTR(energy_avg),
-+      POWER_SUPPLY_ATTR(capacity),
-+      POWER_SUPPLY_ATTR(capacity_level),
-+      POWER_SUPPLY_ATTR(temp),
-+      POWER_SUPPLY_ATTR(temp_ambient),
-+      POWER_SUPPLY_ATTR(time_to_empty_now),
-+      POWER_SUPPLY_ATTR(time_to_empty_avg),
-+      POWER_SUPPLY_ATTR(time_to_full_now),
-+      POWER_SUPPLY_ATTR(time_to_full_avg),
-+      /* Properties of type `const char *' */
-+      POWER_SUPPLY_ATTR(model_name),
-+};
-+
-+static ssize_t power_supply_show_static_attrs(struct device *dev,
-+                                              struct device_attribute *attr,
-+                                              char *buf) {
-+      static char *type_text[] = { "Battery", "UPS", "Mains", "USB" };
-+      struct power_supply *psy = dev_get_drvdata(dev);
-+
-+      return sprintf(buf, "%s\n", type_text[psy->type]);
-+}
-+
-+static struct device_attribute power_supply_static_attrs[] = {
-+      __ATTR(type, 0444, power_supply_show_static_attrs, NULL),
-+};
-+
-+int power_supply_create_attrs(struct power_supply *psy)
-+{
-+      int rc = 0;
-+      int i, j;
-+
-+      for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
-+              rc = device_create_file(psy->dev,
-+                          &power_supply_static_attrs[i]);
-+              if (rc)
-+                      goto statics_failed;
-+      }
-+
-+      for (j = 0; j < psy->num_properties; j++) {
-+              rc = device_create_file(psy->dev,
-+                          &power_supply_attrs[psy->properties[j]]);
-+              if (rc)
-+                      goto dynamics_failed;
-+      }
-+
-+      goto succeed;
-+
-+dynamics_failed:
-+      while (j--)
-+              device_remove_file(psy->dev,
-+                         &power_supply_attrs[psy->properties[j]]);
-+statics_failed:
-+      while (i--)
-+              device_remove_file(psy->dev,
-+                         &power_supply_static_attrs[psy->properties[i]]);
-+succeed:
-+      return rc;
-+}
-+
-+void power_supply_remove_attrs(struct power_supply *psy)
-+{
-+      int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
-+              device_remove_file(psy->dev,
-+                          &power_supply_static_attrs[i]);
-+
-+      for (i = 0; i < psy->num_properties; i++)
-+              device_remove_file(psy->dev,
-+                          &power_supply_attrs[psy->properties[i]]);
-+
-+      return;
-+}
-+
-+static char *kstruprdup(const char *str, gfp_t gfp)
-+{
-+      char *ret, *ustr;
-+
-+      ustr = ret = kmalloc(strlen(str) + 1, gfp);
-+
-+      if (!ret)
-+              return NULL;
-+
-+      while (*str)
-+              *ustr++ = toupper(*str++);
-+
-+      *ustr = 0;
-+
-+      return ret;
-+}
-+
-+int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-+                        char *buffer, int buffer_size)
-+{
-+      struct power_supply *psy = dev_get_drvdata(dev);
-+      int i = 0, length = 0, ret = 0, j;
-+      char *prop_buf;
-+      char *attrname;
-+
-+      dev_dbg(dev, "uevent\n");
-+
-+      if (!psy) {
-+              dev_dbg(dev, "No power supply yet\n");
-+              return ret;
-+      }
-+
-+      dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
-+
-+      ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                           &length, "POWER_SUPPLY_NAME=%s", psy->name);
-+      if (ret)
-+              return ret;
-+
-+      prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
-+      if (!prop_buf)
-+              return -ENOMEM;
-+
-+      for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
-+              struct device_attribute *attr;
-+              char *line;
-+
-+              attr = &power_supply_static_attrs[j];
-+
-+              ret = power_supply_show_static_attrs(dev, attr, prop_buf);
-+              if (ret < 0)
-+                      goto out;
-+
-+              line = strchr(prop_buf, '\n');
-+              if (line)
-+                      *line = 0;
-+
-+              attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
-+              if (!attrname) {
-+                      ret = -ENOMEM;
-+                      goto out;
-+              }
-+
-+              dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
-+
-+              ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                                   &length, "POWER_SUPPLY_%s=%s",
-+                                   attrname, prop_buf);
-+              kfree(attrname);
-+              if (ret)
-+                      goto out;
-+      }
-+
-+      dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
-+
-+      for (j = 0; j < psy->num_properties; j++) {
-+              struct device_attribute *attr;
-+              char *line;
-+
-+              attr = &power_supply_attrs[psy->properties[j]];
-+
-+              ret = power_supply_show_property(dev, attr, prop_buf);
-+              if (ret < 0)
-+                      goto out;
-+
-+              line = strchr(prop_buf, '\n');
-+              if (line)
-+                      *line = 0;
-+
-+              attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
-+              if (!attrname) {
-+                      ret = -ENOMEM;
-+                      goto out;
-+              }
-+
-+              dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
-+
-+              ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                                   &length, "POWER_SUPPLY_%s=%s",
-+                                   attrname, prop_buf);
-+              kfree(attrname);
-+              if (ret)
-+                      goto out;
-+      }
-+
-+out:
-+      free_page((unsigned long)prop_buf);
-+
-+      return ret;
-+}
-Index: linux-2.6.22/drivers/power/simpad-battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/simpad-battery.c        2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,242 @@
-+/*
-+ *  linux/drivers/misc/simpad-battery.c
-+ *
-+ *  Copyright (C) 2005 Holger Hans Peter Freyther
-+ *  Copyright (C) 2001 Juergen Messerer
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is
-+ * unsupported for now.
-+ *
-+ */
-+
-+#include <linux/battery.h>
-+#include <asm/dma.h>
-+#include "ucb1x00.h"
-+
-+
-+/*
-+ * Conversion from AD -> mV
-+ * 7.5V = 1023   7.3313mV/Digit
-+ *
-+ * 400 Units == 9.7V
-+ * a     = ADC value
-+ * 21    = ADC error
-+ * 12600 = Divident to get 2*7.3242
-+ * 860   = Divider to get 2*7.3242
-+ * 170   = Voltagedrop over
-+ */
-+#define CALIBRATE_BATTERY(a)   ((((a + 21)*12600)/860) + 170)
-+
-+/*
-+ * We have two types of batteries a small and a large one
-+ * To get the right value we to distinguish between those two
-+ * 450 Units == 15 V
-+ */
-+#define CALIBRATE_SUPPLY(a)   (((a) * 1500) / 45)
-+#define MIN_SUPPLY            12000 /* Less then 12V means no powersupply */
-+
-+/*
-+ * Charging Current
-+ * if value is >= 50 then charging is on
-+ */
-+#define CALIBRATE_CHARGING(a)    (((a)* 1000)/(152/4)))
-+
-+struct simpad_battery_t {
-+      struct battery  battery;
-+      struct ucb1x00* ucb;
-+
-+        /*
-+       * Variables for the values to one time support
-+       * T-Sinuspad as well
-+       */
-+      int min_voltage;
-+      int min_current;
-+      int min_charge;
-+
-+      int max_voltage;
-+      int max_current;
-+      int max_charge;
-+
-+      int min_supply;
-+      int charging_led_label;
-+      int charging_max_label;
-+      int batt_full;
-+      int batt_low;
-+      int batt_critical;
-+      int batt_empty;
-+};
-+
-+static int simpad_get_min_voltage(struct battery* _battery )
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return  battery->min_voltage;
-+}
-+
-+static int simpad_get_min_current(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->min_current;
-+}
-+
-+static int simpad_get_min_charge(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->min_charge;
-+}
-+
-+static int simpad_get_max_voltage(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->max_voltage;
-+}
-+
-+static int simpad_get_max_current(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->max_current;
-+}
-+
-+static int simpad_get_max_charge(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->max_charge;
-+}
-+
-+static int simpad_get_temp(struct battery* _battery)
-+{
-+      return 0;
-+}
-+
-+static int simpad_get_voltage(struct battery* _battery)
-+{
-+      int val;
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+
-+
-+      ucb1x00_adc_enable(battery->ucb);
-+      val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD1, UCB_NOSYNC);
-+      ucb1x00_adc_disable(battery->ucb);
-+
-+      return CALIBRATE_BATTERY(val);
-+}
-+
-+static int simpad_get_current(struct battery* _battery)
-+{
-+      int val;
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+
-+      ucb1x00_adc_enable(battery->ucb);
-+      val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD3, UCB_NOSYNC);
-+      ucb1x00_adc_disable(battery->ucb);
-+
-+      return val;
-+}
-+
-+static int simpad_get_charge(struct battery* _battery)
-+{
-+      int val;
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+
-+      ucb1x00_adc_enable(battery->ucb);
-+      val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD2, UCB_NOSYNC);
-+      ucb1x00_adc_disable(battery->ucb);
-+
-+      return CALIBRATE_SUPPLY(val);
-+
-+}
-+
-+static int simpad_get_status(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)(_battery);
-+      int vcharger = simpad_get_voltage(_battery);
-+      int icharger = simpad_get_current(_battery);
-+
-+      int status = BATTERY_STATUS_UNKNOWN;
-+      if(icharger > battery->charging_led_label)
-+              status = BATTERY_STATUS_CHARGING;
-+      else if(vcharger > battery->min_supply)
-+              status = BATTERY_STATUS_NOT_CHARGING;
-+      else
-+              status = BATTERY_STATUS_DISCHARGING;
-+
-+      return status;
-+}
-+
-+static struct simpad_battery_t simpad_battery  = {
-+      .battery = {
-+              .get_min_voltage = simpad_get_min_voltage,
-+              .get_min_current = simpad_get_min_current,
-+              .get_min_charge  = simpad_get_min_charge,
-+              .get_max_voltage = simpad_get_max_voltage,
-+              .get_max_current = simpad_get_max_current,
-+              .get_max_charge  = simpad_get_max_charge,
-+              .get_temp        = simpad_get_temp,
-+              .get_voltage     = simpad_get_voltage,
-+              .get_current     = simpad_get_current,
-+              .get_charge      = simpad_get_charge,
-+              .get_status      = simpad_get_status,
-+      },
-+      .min_voltage = 0,
-+      .min_current = 0,
-+      .min_charge  = 0,
-+      .max_voltage = 0,
-+      .max_current = 0,
-+      .max_charge  = 0,
-+
-+      .min_supply         = 1200,
-+      .charging_led_label = 18,
-+      .charging_max_label = 265,
-+      .batt_full          = 8300,
-+      .batt_low           = 7300,
-+      .batt_critical      = 6800,
-+      .batt_empty         = 6500,
-+};
-+
-+
-+
-+/*
-+ * UCB glue code
-+ */
-+static int ucb1x00_battery_add(struct class_device *dev)
-+{
-+      struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+      simpad_battery.ucb  = ucb;
-+
-+      battery_class_register(&simpad_battery.battery);
-+
-+      return 0;
-+}
-+
-+static void ucb1x00_battery_remove(struct class_device *dev)
-+{
-+      return battery_class_unregister(&simpad_battery.battery);
-+}
-+
-+
-+static struct ucb1x00_class_interface ucb1x00_battery_interface = {
-+      .interface   = {
-+              .add    = ucb1x00_battery_add,
-+              .remove = ucb1x00_battery_remove,
-+      },
-+};
-+
-+
-+static int __init battery_register(void)
-+{
-+      return ucb1x00_register_interface(&ucb1x00_battery_interface);
-+}
-+
-+static void __exit battery_unregister(void)
-+{
-+      ucb1x00_unregister_interface(&ucb1x00_battery_interface);
-+}
-+
-+module_init(battery_register);
-+module_exit(battery_unregister);
-+
-+MODULE_AUTHOR("Holger Hans Peter Freyther");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/arch/arm/Kconfig
-===================================================================
---- linux-2.6.22.orig/arch/arm/Kconfig 2007-08-23 12:17:42.000000000 +0200
-+++ linux-2.6.22/arch/arm/Kconfig      2007-08-23 12:22:28.000000000 +0200
-@@ -1016,6 +1016,8 @@
- source "drivers/w1/Kconfig"
-+source "drivers/power/Kconfig"
-+
- source "drivers/hwmon/Kconfig"
- #source "drivers/l3/Kconfig"
-Index: linux-2.6.22/drivers/Kconfig
-===================================================================
---- linux-2.6.22.orig/drivers/Kconfig  2007-08-23 12:21:27.000000000 +0200
-+++ linux-2.6.22/drivers/Kconfig       2007-08-23 12:22:03.000000000 +0200
-@@ -54,6 +54,8 @@
- source "drivers/w1/Kconfig"
-+source "drivers/power/Kconfig"
-+
- source "drivers/hwmon/Kconfig"
- source "drivers/mfd/Kconfig"
-Index: linux-2.6.22/drivers/Makefile
-===================================================================
---- linux-2.6.22.orig/drivers/Makefile 2007-08-23 12:33:58.000000000 +0200
-+++ linux-2.6.22/drivers/Makefile      2007-08-23 12:34:34.000000000 +0200
-@@ -61,6 +61,7 @@
- obj-$(CONFIG_RTC_LIB)         += rtc/
- obj-y                         += i2c/
- obj-$(CONFIG_W1)              += w1/
-+obj-$(CONFIG_POWER_SUPPLY)    += power/
- obj-$(CONFIG_HWMON)           += hwmon/
- obj-$(CONFIG_PHONE)           += telephony/
- obj-$(CONFIG_MD)              += md/
-Index: linux-2.6.22/include/linux/power_supply.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/include/linux/power_supply.h  2007-08-23 12:37:10.000000000 +0200
-@@ -0,0 +1,175 @@
-+/*
-+ *  Universal power supply monitor class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#ifndef __LINUX_POWER_SUPPLY_H__
-+#define __LINUX_POWER_SUPPLY_H__
-+
-+#include <linux/device.h>
-+#include <linux/workqueue.h>
-+#include <linux/leds.h>
-+
-+/*
-+ * All voltages, currents, charges, energies, time and temperatures in uV,
-+ * uA, uAh, uWh, seconds and tenths of degree Celsius unless otherwise
-+ * stated. It's driver's job to convert its raw values to units in which
-+ * this class operates.
-+ */
-+
-+/*
-+ * For systems where the charger determines the maximum battery capacity
-+ * the min and max fields should be used to present these values to user
-+ * space. Unused/unknown fields will not appear in sysfs.
-+ */
-+
-+enum {
-+      POWER_SUPPLY_STATUS_UNKNOWN = 0,
-+      POWER_SUPPLY_STATUS_CHARGING,
-+      POWER_SUPPLY_STATUS_DISCHARGING,
-+      POWER_SUPPLY_STATUS_NOT_CHARGING,
-+      POWER_SUPPLY_STATUS_FULL,
-+};
-+
-+enum {
-+      POWER_SUPPLY_HEALTH_UNKNOWN = 0,
-+      POWER_SUPPLY_HEALTH_GOOD,
-+      POWER_SUPPLY_HEALTH_OVERHEAT,
-+      POWER_SUPPLY_HEALTH_DEAD,
-+};
-+
-+enum {
-+      POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,
-+      POWER_SUPPLY_TECHNOLOGY_NIMH,
-+      POWER_SUPPLY_TECHNOLOGY_LION,
-+      POWER_SUPPLY_TECHNOLOGY_LIPO,
-+};
-+
-+enum {
-+      POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
-+      POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
-+      POWER_SUPPLY_CAPACITY_LEVEL_LOW,
-+      POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
-+      POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
-+      POWER_SUPPLY_CAPACITY_LEVEL_FULL,
-+};
-+
-+enum power_supply_property {
-+      /* Properties of type `int' */
-+      POWER_SUPPLY_PROP_STATUS = 0,
-+      POWER_SUPPLY_PROP_HEALTH,
-+      POWER_SUPPLY_PROP_PRESENT,
-+      POWER_SUPPLY_PROP_ONLINE,
-+      POWER_SUPPLY_PROP_TECHNOLOGY,
-+      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-+      POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+      POWER_SUPPLY_PROP_VOLTAGE_AVG,
-+      POWER_SUPPLY_PROP_CURRENT_NOW,
-+      POWER_SUPPLY_PROP_CURRENT_AVG,
-+      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+      POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
-+      POWER_SUPPLY_PROP_CHARGE_FULL,
-+      POWER_SUPPLY_PROP_CHARGE_EMPTY,
-+      POWER_SUPPLY_PROP_CHARGE_NOW,
-+      POWER_SUPPLY_PROP_CHARGE_AVG,
-+      POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
-+      POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
-+      POWER_SUPPLY_PROP_ENERGY_FULL,
-+      POWER_SUPPLY_PROP_ENERGY_EMPTY,
-+      POWER_SUPPLY_PROP_ENERGY_NOW,
-+      POWER_SUPPLY_PROP_ENERGY_AVG,
-+      POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
-+      POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-+      POWER_SUPPLY_PROP_TEMP,
-+      POWER_SUPPLY_PROP_TEMP_AMBIENT,
-+      POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-+      POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
-+      POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
-+      POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
-+      /* Properties of type `const char *' */
-+      POWER_SUPPLY_PROP_MODEL_NAME,
-+};
-+
-+enum power_supply_type {
-+      POWER_SUPPLY_TYPE_BATTERY = 0,
-+      POWER_SUPPLY_TYPE_UPS,
-+      POWER_SUPPLY_TYPE_MAINS,
-+      POWER_SUPPLY_TYPE_USB,
-+};
-+
-+union power_supply_propval {
-+      int intval;
-+      const char *strval;
-+};
-+
-+struct power_supply {
-+      const char *name;
-+      enum power_supply_type type;
-+      enum power_supply_property *properties;
-+      size_t num_properties;
-+
-+      char **supplied_to;
-+      size_t num_supplicants;
-+
-+      int (*get_property)(struct power_supply *psy,
-+                          enum power_supply_property psp,
-+                          union power_supply_propval *val);
-+      void (*external_power_changed)(struct power_supply *psy);
-+
-+      /* For APM emulation, think legacy userspace. */
-+      int use_for_apm;
-+
-+      /* private */
-+      struct device *dev;
-+      struct work_struct changed_work;
-+
-+#ifdef CONFIG_LEDS_TRIGGERS
-+      struct led_trigger *charging_full_trig;
-+      char *charging_full_trig_name;
-+      struct led_trigger *charging_trig;
-+      char *charging_trig_name;
-+      struct led_trigger *full_trig;
-+      char *full_trig_name;
-+      struct led_trigger *online_trig;
-+      char *online_trig_name;
-+#endif
-+};
-+
-+/*
-+ * This is recommended structure to specify static power supply parameters.
-+ * Generic one, parametrizable for different power supplies. Power supply
-+ * class itself does not use it, but that's what implementing most platform
-+ * drivers, should try reuse for consistency.
-+ */
-+
-+struct power_supply_info {
-+      const char *name;
-+      int technology;
-+      int voltage_max_design;
-+      int voltage_min_design;
-+      int charge_full_design;
-+      int charge_empty_design;
-+      int energy_full_design;
-+      int energy_empty_design;
-+      int use_for_apm;
-+};
-+
-+extern void power_supply_changed(struct power_supply *psy);
-+extern int power_supply_am_i_supplied(struct power_supply *psy);
-+
-+extern int power_supply_register(struct device *parent,
-+                                 struct power_supply *psy);
-+extern void power_supply_unregister(struct power_supply *psy);
-+
-+/* For APM emulation, think legacy userspace. */
-+extern struct class *power_supply_class;
-+
-+#endif /* __LINUX_POWER_SUPPLY_H__ */
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pxa27x_overlay-r8.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pxa27x_overlay-r8.patch
deleted file mode 100644 (file)
index 693ad20..0000000
+++ /dev/null
@@ -1,2427 +0,0 @@
- 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-rc8/squashfs3.0-2.6.15.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.0-2.6.15.patch
deleted file mode 100644 (file)
index a210afc..0000000
+++ /dev/null
@@ -1,4189 +0,0 @@
- fs/Kconfig                     |   65 +
- fs/Makefile                    |    1 
- fs/squashfs/Makefile           |    7 
- fs/squashfs/inode.c            | 2122 +++++++++++++++++++++++++++++++++++++++++
- fs/squashfs/squashfs.h         |   86 +
- fs/squashfs/squashfs2_0.c      |  757 ++++++++++++++
- include/linux/squashfs_fs.h    |  911 +++++++++++++++++
- include/linux/squashfs_fs_i.h  |   45 
- include/linux/squashfs_fs_sb.h |   74 +
- init/do_mounts_rd.c            |   13 
- 10 files changed, 4081 insertions(+)
-
-Index: linux-2.6.22/fs/Kconfig
-===================================================================
---- linux-2.6.22.orig/fs/Kconfig       2007-08-28 21:56:32.000000000 +0100
-+++ linux-2.6.22/fs/Kconfig    2007-08-28 21:56:34.000000000 +0100
-@@ -1394,6 +1394,71 @@ config CRAMFS
-         If unsure, say N.
-+config SQUASHFS
-+      tristate "SquashFS 3.0 - Squashed file system support"
-+      select ZLIB_INFLATE
-+      help
-+        Saying Y here includes support for SquashFS 3.0 (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.0 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
-Index: linux-2.6.22/fs/Makefile
-===================================================================
---- linux-2.6.22.orig/fs/Makefile      2007-08-28 21:54:14.000000000 +0100
-+++ linux-2.6.22/fs/Makefile   2007-08-28 21:56:34.000000000 +0100
-@@ -72,6 +72,7 @@ obj-$(CONFIG_JBD)            += jbd/
- obj-$(CONFIG_JBD2)            += jbd2/
- obj-$(CONFIG_EXT2_FS)         += ext2/
- obj-$(CONFIG_CRAMFS)          += cramfs/
-+obj-$(CONFIG_SQUASHFS)                += squashfs/
- obj-$(CONFIG_RAMFS)           += ramfs/
- obj-$(CONFIG_HUGETLBFS)               += hugetlbfs/
- obj-$(CONFIG_CODA_FS)         += coda/
-Index: linux-2.6.22/fs/squashfs/inode.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/fs/squashfs/inode.c   2007-08-28 22:12:03.000000000 +0100
-@@ -0,0 +1,2122 @@
-+/*
-+ * Squashfs - a compressed read only filesystem for Linux
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
-+ * 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/types.h>
-+#include <linux/squashfs_fs.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/fs.h>
-+#include <linux/smp_lock.h>
-+#include <linux/slab.h>
-+#include <linux/squashfs_fs_sb.h>
-+#include <linux/squashfs_fs_i.h>
-+#include <linux/buffer_head.h>
-+#include <linux/vfs.h>
-+#include <linux/init.h>
-+#include <linux/dcache.h>
-+#include <linux/wait.h>
-+#include <linux/zlib.h>
-+#include <linux/blkdev.h>
-+#include <linux/vmalloc.h>
-+#include <asm/uaccess.h>
-+#include <asm/semaphore.h>
-+
-+#include "squashfs.h"
-+
-+static void squashfs_put_super(struct super_block *);
-+static int squashfs_statfs(struct dentry *, struct kstatfs *);
-+static int squashfs_symlink_readpage(struct file *file, struct page *page);
-+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 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 dentry *squashfs_lookup(struct inode *, struct dentry *,
-+                              struct nameidata *);
-+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
-+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_get_sb(struct file_system_type *, int,
-+                              const char *, void *, struct vfsmount *);
-+
-+
-+static z_stream stream;
-+
-+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 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_ops = {
-+      .alloc_inode = squashfs_alloc_inode,
-+      .destroy_inode = squashfs_destroy_inode,
-+      .statfs = squashfs_statfs,
-+      .put_super = squashfs_put_super,
-+};
-+
-+SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
-+      .readpage = squashfs_symlink_readpage
-+};
-+
-+SQSH_EXTERN struct address_space_operations squashfs_aops = {
-+      .readpage = squashfs_readpage
-+};
-+
-+SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
-+      .readpage = squashfs_readpage4K
-+};
-+
-+static 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)
-+{
-+      struct squashfs_sb_info *msblk = s->s_fs_info;
-+      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;
-+      char *c_buffer;
-+      unsigned int compressed;
-+      unsigned int c_byte = length;
-+
-+      if (c_byte) {
-+              bytes = msblk->devblksize - offset;
-+              compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
-+              c_buffer = compressed ? msblk->read_data : buffer;
-+              c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
-+
-+              TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
-+                                      ? "" : "un", (unsigned int) c_byte);
-+
-+              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 (!(bh[0] = get_block_length(s, &cur_index, &offset,
-+                                                              &c_byte)))
-+                      goto read_failure;
-+
-+              bytes = msblk->devblksize - offset;
-+              compressed = SQUASHFS_COMPRESSED(c_byte);
-+              c_buffer = compressed ? msblk->read_data : buffer;
-+              c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
-+
-+              TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
-+                                      ? "" : "un", (unsigned int) c_byte);
-+
-+              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)
-+              down(&msblk->read_data_mutex);
-+
-+      for (bytes = 0, k = 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 block_release;
-+              memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
-+              bytes += avail_bytes;
-+              offset = 0;
-+              brelse(bh[k]);
-+      }
-+
-+      /*
-+       * uncompress block
-+       */
-+      if (compressed) {
-+              int zlib_err;
-+
-+              stream.next_in = c_buffer;
-+              stream.avail_in = c_byte;
-+              stream.next_out = buffer;
-+              stream.avail_out = msblk->read_size;
-+
-+              if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
-+                              ((zlib_err = zlib_inflate(&stream, Z_FINISH))
-+                               != Z_STREAM_END) || ((zlib_err =
-+                              zlib_inflateEnd(&stream)) != Z_OK)) {
-+                      ERROR("zlib_fs returned unexpected result 0x%x\n",
-+                              zlib_err);
-+                      bytes = 0;
-+              } else
-+                      bytes = stream.total_out;
-+              
-+              up(&msblk->read_data_mutex);
-+      }
-+
-+      if (next_index)
-+              *next_index = index + c_byte + (length ? 0 :
-+                              (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
-+                               ? 3 : 2));
-+      return bytes;
-+
-+block_release:
-+      while (--b >= 0)
-+              brelse(bh[b]);
-+
-+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; 
-+              
-+              down(&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);
-+                              up(&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");
-+                                      up(&msblk->block_cache_mutex);
-+                                      goto out;
-+                              }
-+                      }
-+      
-+                      msblk->block_cache[i].block = SQUASHFS_USED_BLK;
-+                      up(&msblk->block_cache_mutex);
-+
-+                      if (!(msblk->block_cache[i].length =
-+                                              squashfs_read_data(s,
-+                                              msblk->block_cache[i].data,
-+                                              block, 0, &next_index))) {
-+                              ERROR("Unable to read cache block [%llx:%x]\n",
-+                                              block, offset);
-+                              goto out;
-+                      }
-+
-+                      down(&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) {
-+                      up(&msblk->block_cache_mutex);
-+                      continue;
-+              }
-+
-+              if ((bytes = msblk->block_cache[i].length - offset) >= 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;
-+                      }
-+                      up(&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;
-+                      up(&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)
-+{
-+      down(&msblk->fragment_mutex);
-+      fragment->locked --;
-+      wake_up(&msblk->fragment_wait_queue);
-+      up(&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, nf;
-+      struct squashfs_sb_info *msblk = s->s_fs_info;
-+
-+      while ( 1 ) {
-+              down(&msblk->fragment_mutex);
-+
-+              for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
-+                              msblk->fragment[i].block != start_block; i++);
-+
-+              if (i == SQUASHFS_CACHED_FRAGMENTS) {
-+                      nf = (msblk->next_fragment + 1) % 
-+                              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);
-+                              up(&msblk->fragment_mutex);
-+                              schedule();
-+                              set_current_state(TASK_RUNNING);
-+                              remove_wait_queue(&msblk->fragment_wait_queue,
-+                                                                      &wait);
-+                              continue;
-+                      }
-+                      msblk->next_fragment = nf;
-+                      
-+                      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");
-+                                      up(&msblk->fragment_mutex);
-+                                      goto out;
-+                              }
-+
-+                      msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
-+                      msblk->fragment[i].locked = 1;
-+                      up(&msblk->fragment_mutex);
-+
-+                      if (!(msblk->fragment[i].length = squashfs_read_data(s,
-+                                              msblk->fragment[i].data,
-+                                              start_block, length, NULL))) {
-+                              ERROR("Unable to read fragment cache block "
-+                                                      "[%llx]\n", start_block);
-+                              msblk->fragment[i].locked = 0;
-+                              goto out;
-+                      }
-+
-+                      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);
-+                      break;
-+              }
-+
-+              msblk->fragment[i].locked++;
-+              up(&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 struct inode *squashfs_new_inode(struct super_block *s,
-+              struct squashfs_base_inode_header *inodeb)
-+{
-+      struct squashfs_sb_info *msblk = s->s_fs_info;
-+      struct inode *i = new_inode(s);
-+
-+      if (i) {
-+              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];
-+      }
-+
-+      return i;
-+}
-+
-+
-+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
-+{
-+      struct inode *i;
-+      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_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(inodeb, sinodeb,
-+                                      sizeof(*sinodeb));
-+      } else
-+              if (!squashfs_get_cached_block(s, (char *) inodeb, block,
-+                                      offset, sizeof(*inodeb), &next_block,
-+                                      &next_offset))
-+                      goto failed_read;
-+
-+      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;
-+                              
-+                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+                              
-+                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if ((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if ((i = squashfs_new_inode(s, inodeb)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+      }
-+      
-+      insert_inode_hash(i);
-+      return i;
-+
-+failed_read:
-+      ERROR("Unable to read inode [%llx:%x]\n", block, offset);
-+
-+failed_read1:
-+      return NULL;
-+}
-+
-+
-+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;
-+
-+      /* Allocate fragment index table */
-+      if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
-+                                      (sblk->fragments), GFP_KERNEL))) {
-+              ERROR("Failed to allocate uid/gid table\n");
-+              return 0;
-+      }
-+   
-+      if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
-+                                      !squashfs_read_data(s, (char *)
-+                                      msblk->fragment_index,
-+                                      sblk->fragment_table_start,
-+                                      SQUASHFS_FRAGMENT_INDEX_BYTES
-+                                      (sblk->fragments) |
-+                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
-+              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->iget = squashfs_iget;
-+      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;
-+      sblk = &msblk->sblk;
-+      
-+      msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
-+      msblk->devblksize_log2 = ffz(~msblk->devblksize);
-+
-+      init_MUTEX(&msblk->read_data_mutex);
-+      init_MUTEX(&msblk->read_page_mutex);
-+      init_MUTEX(&msblk->block_cache_mutex);
-+      init_MUTEX(&msblk->fragment_mutex);
-+      init_MUTEX(&msblk->meta_index_mutex);
-+      
-+      init_waitqueue_head(&msblk->waitq);
-+      init_waitqueue_head(&msblk->fragment_wait_queue);
-+
-+      if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
-+                                      sizeof(struct squashfs_super_block) |
-+                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
-+              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;
-+
-+      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_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_data block */
-+      msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
-+                                      SQUASHFS_METADATA_SIZE :
-+                                      sblk->block_size;
-+
-+      if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
-+              ERROR("Failed to allocate read_data block\n");
-+              goto failed_mount;
-+      }
-+
-+      /* 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)) {
-+                      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)) {
-+                      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 fragment index table */
-+      if (msblk->read_fragment_index_table(s) == 0)
-+              goto failed_mount;
-+
-+allocate_root:
-+      if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
-+              goto failed_mount;
-+
-+      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->fragment_index);
-+      kfree(msblk->fragment);
-+      kfree(msblk->uid);
-+      kfree(msblk->read_page);
-+      kfree(msblk->read_data);
-+      kfree(msblk->block_cache);
-+      kfree(msblk->fragment_index_2);
-+      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 super_block *s = dentry->d_sb;
-+      struct squashfs_sb_info *msblk = s->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);
-+      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;
-+
-+      down(&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:
-+      up(&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;
-+
-+      down(&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:
-+      up(&msblk->meta_index_mutex);
-+      return meta;
-+}
-+
-+
-+void release_meta_index(struct inode *inode, struct meta_index *meta)
-+{
-+      meta->locked = 0;
-+}
-+
-+
-+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 {
-+                      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[SIZE];
-+      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 (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;
-+
-+              down(&msblk->read_page_mutex);
-+              
-+              if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
-+                                      block, bsize, NULL))) {
-+                      ERROR("Unable to read page, block %llx, size %x\n", block,
-+                                      bsize);
-+                      up(&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 available_bytes = (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, available_bytes);
-+
-+              if (i == page->index)  {
-+                      pageaddr = kmap_atomic(page, KM_USER0);
-+                      memcpy(pageaddr, data_ptr + byte_offset,
-+                                      available_bytes);
-+                      memset(pageaddr + available_bytes, 0,
-+                                      PAGE_CACHE_SIZE - available_bytes);
-+                      kunmap_atomic(pageaddr, KM_USER0);
-+                      flush_dcache_page(page);
-+                      SetPageUptodate(page);
-+                      unlock_page(page);
-+              } else if ((push_page =
-+                              grab_cache_page_nowait(page->mapping, i))) {
-+                      pageaddr = kmap_atomic(push_page, KM_USER0);
-+
-+                      memcpy(pageaddr, data_ptr + byte_offset,
-+                                      available_bytes);
-+                      memset(pageaddr + available_bytes, 0,
-+                                      PAGE_CACHE_SIZE - available_bytes);
-+                      kunmap_atomic(pageaddr, KM_USER0);
-+                      flush_dcache_page(push_page);
-+                      SetPageUptodate(push_page);
-+                      unlock_page(push_page);
-+                      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))
-+              up(&msblk->read_page_mutex);
-+      else
-+              release_cached_fragment(msblk, fragment);
-+
-+      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);
-+
-+      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[SIZE];
-+      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)) {
-+              pageaddr = kmap_atomic(page, KM_USER0);
-+              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);
-+
-+              down(&msblk->read_page_mutex);
-+              bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
-+                                      bsize, NULL);
-+              pageaddr = kmap_atomic(page, KM_USER0);
-+              if (bytes)
-+                      memcpy(pageaddr, msblk->read_page, bytes);
-+              else
-+                      ERROR("Unable to read page, block %llx, size %x\n",
-+                                      block, bsize);
-+              up(&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);
-+              pageaddr = kmap_atomic(page, KM_USER0);
-+              if (fragment) {
-+                      bytes = i_size_read(inode) & (sblk->block_size - 1);
-+                      memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
-+                                      u.s1.fragment_offset, bytes);
-+                      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:
-+      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
-+      kunmap_atomic(pageaddr, KM_USER0);
-+      flush_dcache_page(page);
-+      SetPageUptodate(page);
-+      unlock_page(page);
-+
-+      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;
-+      char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
-+      struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
-+      char str[SQUASHFS_NAME_LEN + 1];
-+
-+      TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
-+
-+      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;
-+      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, dirs_read = 0,
-+              dir_count;
-+      struct squashfs_dir_header dirh;
-+      char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
-+      struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
-+
-+      TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
-+
-+      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;
-+              dirs_read++;
-+      }
-+
-+      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;
-+                      dirs_read++;
-+              }
-+      }
-+
-+finish:
-+      return dirs_read;
-+
-+failed_read:
-+      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
-+              next_offset);
-+      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;
-+      char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
-+      struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
-+
-+      TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
-+
-+      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 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_loop;
-+
-+                      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 = (msblk->iget)(i->i_sb, ino);
-+
-+                              goto exit_loop;
-+                      }
-+              }
-+      }
-+
-+exit_loop:
-+      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;
-+}
-+
-+
-+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_data);
-+              kfree(sbi->read_page);
-+              kfree(sbi->uid);
-+              kfree(sbi->fragment_index);
-+              kfree(sbi->fragment_index_2);
-+              kfree(sbi->meta_index);
-+              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.0 (2006/03/15) "
-+              "Phillip Lougher\n");
-+
-+      if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
-+              ERROR("Failed to allocate zlib workspace\n");
-+              destroy_inodecache();
-+              err = -ENOMEM;
-+              goto out;
-+      }
-+
-+      if ((err = register_filesystem(&squashfs_fs_type))) {
-+              vfree(stream.workspace);
-+              destroy_inodecache();
-+      }
-+
-+out:
-+      return err;
-+}
-+
-+
-+static void __exit exit_squashfs_fs(void)
-+{
-+      vfree(stream.workspace);
-+      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;
-+
-+      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);
-+      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, a compressed read-only filesystem");
-+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
-Index: linux-2.6.22/fs/squashfs/Makefile
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/fs/squashfs/Makefile  2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,7 @@
-+#
-+# Makefile for the linux squashfs routines.
-+#
-+
-+obj-$(CONFIG_SQUASHFS) += squashfs.o
-+squashfs-y += inode.o
-+squashfs-y += squashfs2_0.o
-Index: linux-2.6.22/fs/squashfs/squashfs2_0.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/fs/squashfs/squashfs2_0.c     2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,757 @@
-+/*
-+ * Squashfs - a compressed read only filesystem for Linux
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
-+ * 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/types.h>
-+#include <linux/squashfs_fs.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/fs.h>
-+#include <linux/smp_lock.h>
-+#include <linux/slab.h>
-+#include <linux/squashfs_fs_sb.h>
-+#include <linux/squashfs_fs_i.h>
-+#include <linux/buffer_head.h>
-+#include <linux/vfs.h>
-+#include <linux/init.h>
-+#include <linux/dcache.h>
-+#include <linux/wait.h>
-+#include <linux/zlib.h>
-+#include <linux/blkdev.h>
-+#include <linux/vmalloc.h>
-+#include <asm/uaccess.h>
-+#include <asm/semaphore.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)) {
-+              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 struct inode *squashfs_new_inode(struct super_block *s,
-+              struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
-+{
-+      struct squashfs_sb_info *msblk = s->s_fs_info;
-+      struct squashfs_super_block *sblk = &msblk->sblk;
-+      struct inode *i = new_inode(s);
-+
-+      if (i) {
-+              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];
-+      }
-+
-+      return i;
-+}
-+
-+
-+static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
-+{
-+      struct inode *i;
-+      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 = SQUASHFS_MK_VFS_INODE(block
-+              - sblk->inode_table_start, offset);
-+      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;
-+
-+      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;
-+                              
-+                      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;
-+                              
-+                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+
-+                      if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
-+                              goto failed_read1;
-+
-+                      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: {
-+                      if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
-+                              goto failed_read1;
-+
-+                      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;
-+      }
-+      
-+      insert_inode_hash(i);
-+      return i;
-+
-+failed_read:
-+      ERROR("Unable to read inode [%x:%x]\n", block, offset);
-+
-+failed_read1:
-+      return NULL;
-+}
-+
-+
-+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;
-+      char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
-+      struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
-+      char str[SQUASHFS_NAME_LEN + 1];
-+
-+      TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
-+
-+      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;
-+      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, dirs_read = 0,
-+              dir_count;
-+      struct squashfs_dir_header_2 dirh;
-+      char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
-+      struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
-+
-+      TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
-+
-+      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;
-+                      dirs_read++;
-+              }
-+      }
-+
-+finish:
-+      return dirs_read;
-+
-+failed_read:
-+      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
-+              next_offset);
-+      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;
-+      char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
-+      struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
-+      int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
-+
-+      TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
-+
-+      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);
-+
-+                              TRACE("calling squashfs_iget for directory "
-+                                      "entry %s, inode %x:%x, %lld\n", name,
-+                                      dirh.start_block, dire->offset, ino);
-+
-+                              inode = (msblk->iget)(i->i_sb, ino);
-+
-+                              goto exit_loop;
-+                      }
-+              }
-+      }
-+
-+exit_loop:
-+      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->iget = squashfs_iget_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;
-+}
-Index: linux-2.6.22/fs/squashfs/squashfs.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/fs/squashfs/squashfs.h        2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,86 @@
-+/*
-+ * Squashfs - a compressed read only filesystem for Linux
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
-+ * 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);
-+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 address_space_operations squashfs_symlink_aops;
-+extern struct address_space_operations squashfs_aops;
-+extern 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
-Index: linux-2.6.22/include/linux/squashfs_fs.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/include/linux/squashfs_fs.h   2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,911 @@
-+#ifndef SQUASHFS_FS
-+#define SQUASHFS_FS
-+
-+/*
-+ * Squashfs
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
-+ * 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_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_CHECK_DATA(flags)            SQUASHFS_BIT(flags, \
-+                                              SQUASHFS_CHECK)
-+
-+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
-+              duplicate_checking)     (noi | (nod << 1) | (check_data << 2) \
-+              | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
-+              (duplicate_checking << 6))
-+
-+/* 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))
-+
-+/* 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               unused;
-+} __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            unused;
-+} __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)->unused, 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_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)
-+
-+#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
-Index: linux-2.6.22/include/linux/squashfs_fs_i.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/include/linux/squashfs_fs_i.h 2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,45 @@
-+#ifndef SQUASHFS_FS_I
-+#define SQUASHFS_FS_I
-+/*
-+ * Squashfs
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
-+ * 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
-Index: linux-2.6.22/include/linux/squashfs_fs_sb.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/include/linux/squashfs_fs_sb.h        2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,74 @@
-+#ifndef SQUASHFS_FS_SB
-+#define SQUASHFS_FS_SB
-+/*
-+ * Squashfs
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
-+ * 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;
-+      unsigned int            read_size;
-+      char                    *read_data;
-+      char                    *read_page;
-+      struct semaphore        read_data_mutex;
-+      struct semaphore        read_page_mutex;
-+      struct semaphore        block_cache_mutex;
-+      struct semaphore        fragment_mutex;
-+      struct semaphore        meta_index_mutex;
-+      wait_queue_head_t       waitq;
-+      wait_queue_head_t       fragment_wait_queue;
-+      struct meta_index       *meta_index;
-+      struct inode            *(*iget)(struct super_block *s,  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
-Index: linux-2.6.22/init/do_mounts_rd.c
-===================================================================
---- linux-2.6.22.orig/init/do_mounts_rd.c      2007-08-28 21:54:14.000000000 +0100
-+++ linux-2.6.22/init/do_mounts_rd.c   2007-08-28 21:56:34.000000000 +0100
-@@ -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 @@ static int __init crd_load(int in_fd, in
-  * numbers could not be found.
-  *
-  * We currently check for the following magic numbers:
-+ *      squashfs
-  *    minix
-  *    ext2
-  *    romfs
-@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
-       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 @@ identify_ramdisk_image(int fd, int start
-       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,15 @@ identify_ramdisk_image(int fd, int start
-               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);
-+              nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
-+              goto done;
-+      }
-+
-       /*
-        * Read block 1 to test for minix and ext2 superblock
-        */
similarity index 81%
rename from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.2-2.6.20-r0.patch
rename to meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.3.patch
index 3870b317e41b932a1dd9b035c55d70516395a052..cb9a5c49e4d871f2d159f88aadd59c588c4676d3 100644 (file)
@@ -1,25 +1,27 @@
---- linux-2.6.24-rc1.orig/fs/Kconfig
-+++ linux-2.6.24-rc1/fs/Kconfig
-@@ -1405,6 +1405,71 @@
+diff -x .gitignore -Nurp linux-2.6.24/fs/Kconfig linux-2.6.24-squashfs3.3/fs/Kconfig
+--- linux-2.6.24/fs/Kconfig    2007-10-25 17:41:45.000000000 +0100
++++ linux-2.6.24-squashfs3.3/fs/Kconfig        2007-11-01 05:06:25.000000000 +0000
+@@ -1396,6 +1396,56 @@ config CRAMFS
  
          If unsure, say N.
  
 +config SQUASHFS
-+      tristate "SquashFS 3.2 - Squashed file system support"
++      tristate "SquashFS 3.3 - 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.
++        Saying Y here includes support for SquashFS 3.3 (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 1 Mbytes (default
++        block size 128K).  SquashFS 3.3 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),
 +
 +config SQUASHFS_EMBEDDED
 +
-+      bool "Additional options for memory-constrained systems" 
++      bool "Additional option 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.
++        Saying Y here allows you to specify cache size.
 +
 +        If unsure, say N.
 +
 +
 +        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 @@
+diff -x .gitignore -Nurp linux-2.6.24/fs/Makefile linux-2.6.24-squashfs3.3/fs/Makefile
+--- linux-2.6.24/fs/Makefile   2007-10-25 17:41:45.000000000 +0100
++++ linux-2.6.24-squashfs3.3/fs/Makefile       2007-11-01 05:08:09.000000000 +0000
+@@ -72,6 +72,7 @@ obj-$(CONFIG_JBD)            += jbd/
  obj-$(CONFIG_JBD2)            += jbd2/
  obj-$(CONFIG_EXT2_FS)         += ext2/
  obj-$(CONFIG_CRAMFS)          += cramfs/
  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 @@
+diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/inode.c linux-2.6.24-squashfs3.3/fs/squashfs/inode.c
+--- linux-2.6.24/fs/squashfs/inode.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/fs/squashfs/inode.c       2007-11-01 05:05:00.000000000 +0000
+@@ -0,0 +1,2192 @@
 +/*
 + * Squashfs - a compressed read only filesystem for Linux
 + *
 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
-+ * Phillip Lougher <phillip@lougher.org.uk>
++ * Phillip Lougher <phillip@lougher.demon.co.uk>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +#include <linux/vfs.h>
 +#include <linux/vmalloc.h>
 +#include <linux/smp_lock.h>
++#include <linux/exportfs.h>
 +
 +#include "squashfs.h"
 +
++int squashfs_cached_blks;
++
 +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);
 +                              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 *);
 +      .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
 +{
 +      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];
++      struct buffer_head **bh;
 +      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;
 +
++      bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
++                                                              sizeof(struct buffer_head *), GFP_KERNEL);
++      if (bh == NULL)
++              goto read_failure;
++
 +      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);
++              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)))
++              bh[0] = sb_getblk(s, cur_index);
++              if (bh[0] == NULL)
 +                      goto block_release;
 +
 +              for (b = 1; bytes < c_byte; b++) {
-+                      if (!(bh[b] = sb_getblk(s, ++cur_index)))
++                      bh[b] = sb_getblk(s, ++cur_index);
++                      if (bh[b] == NULL)
 +                              goto block_release;
 +                      bytes += msblk->devblksize;
 +              }
 +              if (index < 0 || (index + 2) > sblk->bytes_used)
 +                      goto read_failure;
 +
-+              if (!(bh[0] = get_block_length(s, &cur_index, &offset,
-+                                                              &c_byte)))
++              bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
++              if (bh[0] == NULL)
 +                      goto read_failure;
 +
 +              bytes = msblk->devblksize - offset;
 +                      goto read_failure;
 +
 +              for (b = 1; bytes < c_byte; b++) {
-+                      if (!(bh[b] = sb_getblk(s, ++cur_index)))
++                      bh[b] = sb_getblk(s, ++cur_index);
++                      if (bh[b] == NULL)
 +                              goto block_release;
 +                      bytes += msblk->devblksize;
 +              }
 +              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;
++                      avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
++
 +                      wait_on_buffer(bh[k]);
 +                      if (!buffer_uptodate(bh[k]))
 +                              goto release_mutex;
 +                      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);
++                                      ERROR("zlib_inflateInit returned unexpected result 0x%x,"
++                                              " srclength %d\n", zlib_err, srclength);
 +                                      goto release_mutex;
 +                              }
 +
 +
 +                      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);
++                              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;
 +                      }
 +
 +
 +              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);
++                      ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
++                              " srclength %d\n", zlib_err, srclength);
 +                      goto release_mutex;
 +              }
 +              bytes = msblk->stream.total_out;
 +
 +              for(i = 0; i < b; i++) {
 +                      wait_on_buffer(bh[i]);
-+                      if(!buffer_uptodate(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;
++                      avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
++
 +                      memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
 +                      bytes += avail_bytes;
 +                      offset = 0;
 +
 +      if (next_index)
 +              *next_index = index + c_byte + (length ? 0 :
-+                              (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
-+                               ? 3 : 2));
++                              (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));
++
++      kfree(bh);
 +      return bytes;
 +
 +release_mutex:
 +
 +read_failure:
 +      ERROR("sb_bread failed reading block 0x%x\n", cur_index);
++      kfree(bh);
 +      return 0;
 +}
 +
 +
-+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer,
 +                              long long block, unsigned int offset,
 +                              int length, long long *next_block,
 +                              unsigned int *next_offset)
 +
 +      TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
 +
-+      while ( 1 ) {
-+              for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 
++      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) {
++              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)
++                      if (msblk->unused_cache_blks == 0) {
++                              mutex_unlock(&msblk->block_cache_mutex);
++                              wait_event(msblk->waitq, msblk->unused_cache_blks);
++                              continue;
++                      }
++
++                      i = msblk->next_cache;
++                      for (n = 0; n < squashfs_cached_blks; n++) {
++                              if (msblk->block_cache[i].block != SQUASHFS_USED_BLK)
 +                                      break;
++                              i = (i + 1) % squashfs_cached_blks;
++                      }
 +
-+                      if (n == 0) {
-+                              wait_queue_t wait;
++                      msblk->next_cache = (i + 1) % squashfs_cached_blks;
 +
-+                              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");
++                      if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) {
++                              msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE);
++                              if (msblk->block_cache[i].data == NULL) {
++                                      ERROR("Failed to allocate cache block\n");
 +                                      mutex_unlock(&msblk->block_cache_mutex);
 +                                      goto out;
 +                              }
 +                      }
 +      
 +                      msblk->block_cache[i].block = SQUASHFS_USED_BLK;
++                      msblk->unused_cache_blks --;
 +                      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);
++                              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);
++                              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);
++                              msblk->unused_cache_blks ++;
++                              smp_mb();
++                              vfree(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;
++                      msblk->unused_cache_blks ++;
++                      smp_mb();
++                      wake_up(&msblk->waitq);
 +                      TRACE("Read cache block [%llx:%x]\n", block, offset);
 +              }
 +
 +                      goto out;
 +              } else if (bytes >= length) {
 +                      if (buffer)
-+                              memcpy(buffer, msblk->block_cache[i].data +
-+                                              offset, length);
++                              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;
 +                      goto finish;
 +              } else {
 +                      if (buffer) {
-+                              memcpy(buffer, msblk->block_cache[i].data +
-+                                              offset, bytes);
-+                              buffer += bytes;
++                              memcpy(buffer, msblk->block_cache[i].data + offset, bytes);
++                              buffer = (char *) buffer + bytes;
 +                      }
 +                      block = msblk->block_cache[i].next_index;
 +                      mutex_unlock(&msblk->block_cache_mutex);
 +      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))
++              if (!squashfs_get_cached_block(s, &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))
++              if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset,
++                                       sizeof(fragment_entry), &start_block, &offset))
 +                      goto out;
 +
 +      *fragment_start_block = fragment_entry.start_block;
 +}
 +
 +
-+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
-+                                      squashfs_fragment_cache *fragment)
++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);
++      if (fragment->locked == 0) {
++              msblk->unused_frag_blks ++;
++              smp_mb();
++              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)
++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 ) {
++      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);
++                      if (msblk->unused_frag_blks == 0) {
 +                              mutex_unlock(&msblk->fragment_mutex);
-+                              schedule();
-+                              set_current_state(TASK_RUNNING);
-+                              remove_wait_queue(&msblk->fragment_wait_queue,
-+                                                                      &wait);
++                              wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks);
 +                              continue;
 +                      }
++
++                      i = msblk->next_fragment;
++                      for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) {
++                              if (msblk->fragment[i].locked == 0)
++                                      break;
++                              i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS;
++                      }
++
 +                      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");
++                      if (msblk->fragment[i].data == NULL) {
++                              msblk->fragment[i].data = vmalloc(sblk->block_size);
++                              if (msblk->fragment[i].data == NULL) {
++                                      ERROR("Failed to allocate fragment cache block\n");
 +                                      mutex_unlock(&msblk->fragment_mutex);
 +                                      goto out;
 +                              }
++                      }
 +
++                      msblk->unused_frag_blks --;
 +                      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].length = squashfs_read_data(s,
++                              msblk->fragment[i].data, start_block, length, NULL,
++                              sblk->block_size);
++
++                      if (msblk->fragment[i].length == 0) {
++                              ERROR("Unable to read fragment cache block [%llx]\n", start_block);
 +                              msblk->fragment[i].locked = 0;
++                              msblk->unused_frag_blks ++;
 +                              smp_mb();
++                              wake_up(&msblk->fragment_wait_queue);
 +                              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);
++                              i, msblk->fragment[i].block, msblk->fragment[i].locked);
 +                      mutex_unlock(&msblk->fragment_mutex);
 +                      break;
 +              }
 +
++              if (msblk->fragment[i].locked == 0)
++                      msblk->unused_frag_blks --;
 +              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);
++                      msblk->fragment[i].block, msblk->fragment[i].locked);
 +              break;
 +      }
 +
 +
 +
 +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
-+              struct squashfs_base_inode_header *inodeb)
++                              struct squashfs_base_inode_header *inodeb)
 +{
 +      i->i_ino = inodeb->inode_number;
 +      i->i_mtime.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
 +      if (msblk->swap) {
 +              squashfs_inode_t sinode;
 +
-+              if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset,
++              if (!squashfs_get_cached_block(s, &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,
++      } else if (!squashfs_get_cached_block(s, &inode, start, offset,
 +                                      sizeof(inode), &start, &offset))
 +                      goto out;
 +
 +}
 +
 +      
-+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number)
++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);
 +      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;
++      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;
++      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))
++              if (!squashfs_get_cached_block(s, sinodeb, block, offset,
++                                      sizeof(*sinodeb), &next_block, &next_offset))
 +                      goto failed_read;
-+              SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
-+                                      sizeof(*sinodeb));
++              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))
++              if (!squashfs_get_cached_block(s, inodeb, block, offset,
++                                      sizeof(*inodeb), &next_block, &next_offset))
 +                      goto failed_read;
 +
 +      squashfs_new_inode(msblk, i, inodeb);
 +                      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))
++                              if (!squashfs_get_cached_block(s, 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))
++                              if (!squashfs_get_cached_block(s, 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;
++
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG)
++                                      if(!get_fragment_location(s, inodep->fragment, &frag_blk,
++                                                                                              &frag_size))
++                                              goto failed_read;
 +                              
 +                      i->i_nlink = 1;
 +                      i->i_size = inodep->file_size;
 +                      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;
++                      i->i_data.a_ops = &squashfs_aops;
 +
 +                      TRACE("File inode %x:%x, start_block %llx, "
 +                                      "block_list_start %llx, offset %x\n",
 +                      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))
++                              if (!squashfs_get_cached_block(s, 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))
++                              if (!squashfs_get_cached_block(s, 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;
++
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG)
++                              if (!get_fragment_location(s, inodep->fragment, &frag_blk,
++                                                                                               &frag_size))
++                                      goto failed_read;
 +                              
 +                      i->i_nlink = inodep->nlink;
 +                      i->i_size = inodep->file_size;
 +                      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;
++                      i->i_data.a_ops = &squashfs_aops;
 +
 +                      TRACE("File inode %x:%x, start_block %llx, "
 +                                      "block_list_start %llx, offset %x\n",
 +                      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))
++                              if (!squashfs_get_cached_block(s, 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))
++                              if (!squashfs_get_cached_block(s, inodep, block, offset,
++                                              sizeof(*inodep), &next_block, &next_offset))
 +                                      goto failed_read;
 +
 +                      i->i_nlink = inodep->nlink;
 +                      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))
++                              if (!squashfs_get_cached_block(s, sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block, &next_offset))
 +                                      goto failed_read;
-+                              SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
-+                                              sinodep);
++                              SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep);
 +                      } else
-+                              if (!squashfs_get_cached_block(s, (char *)
-+                                              inodep, block, offset,
-+                                              sizeof(*inodep), &next_block,
-+                                              &next_offset))
++                              if (!squashfs_get_cached_block(s, inodep, block, offset,
++                                              sizeof(*inodep), &next_block, &next_offset))
 +                                      goto failed_read;
 +
 +                      i->i_nlink = inodep->nlink;
 +                      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.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",
++                      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;
++                      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))
++                              if (!squashfs_get_cached_block(s, sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block, &next_offset))
 +                                      goto failed_read;
-+                              SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
-+                                                              sinodep);
++                              SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep);
 +                      } else
-+                              if (!squashfs_get_cached_block(s, (char *)
-+                                              inodep, block, offset,
-+                                              sizeof(*inodep), &next_block,
-+                                              &next_offset))
++                              if (!squashfs_get_cached_block(s, inodep, block, offset,
++                                              sizeof(*inodep), &next_block, &next_offset))
 +                                      goto failed_read;
 +
 +                      i->i_nlink = inodep->nlink;
 +                      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",
++                      TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n",
 +                                      SQUASHFS_INODE_BLK(inode), offset,
 +                                      next_block, next_offset);
 +                      break;
 +                      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))
++                              if (!squashfs_get_cached_block(s, 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))
++                              if (!squashfs_get_cached_block(s, 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));
++                      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);
++                                      SQUASHFS_INODE_BLK(inode), offset, inodep->rdev);
 +                      break;
 +               }
 +               case SQUASHFS_FIFO_TYPE:
 +                      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))
++                              if (!squashfs_get_cached_block(s, 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))
++                              if (!squashfs_get_cached_block(s, inodep, block, offset,
++                                              sizeof(*inodep), &next_block, &next_offset))
 +                                      goto failed_read;
 +
 +                      i->i_nlink = inodep->nlink;
 +      TRACE("In read_inode_lookup_table, length %d\n", length);
 +
 +      /* Allocate inode lookup table */
-+      if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) {
++      msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL);
++      if (msblk->inode_lookup_table == NULL) {
 +              ERROR("Failed to allocate inode lookup table\n");
 +              return 0;
 +      }
 +              long long block;
 +
 +              for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
++                      /* XXX */
 +                      SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
 +                                              &msblk->inode_lookup_table[i], 1);
 +                      msblk->inode_lookup_table[i] = block;
 +              return 1;
 +
 +      /* Allocate fragment index table */
-+      if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) {
++      msblk->fragment_index = kmalloc(length, GFP_KERNEL);
++      if (msblk->fragment_index == NULL) {
 +              ERROR("Failed to allocate fragment index table\n");
 +              return 0;
 +      }
 +              long long fragment;
 +
 +              for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
++                      /* XXX */
 +                      SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
 +                                              &msblk->fragment_index[i], 1);
 +                      msblk->fragment_index[i] = fragment;
 +}
 +
 +
++static int readahead_metadata(struct super_block *s)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      int i;
++
++      squashfs_cached_blks = SQUASHFS_CACHED_BLKS;
++
++      /* Init inode_table block pointer array */
++      msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
++                                      squashfs_cached_blks, GFP_KERNEL);
++      if (msblk->block_cache == NULL) {
++              ERROR("Failed to allocate block cache\n");
++              goto failed;
++      }
++
++      for (i = 0; i < squashfs_cached_blks; i++)
++              msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++
++      msblk->next_cache = 0;
++      msblk->unused_cache_blks = squashfs_cached_blks;
++
++      return 1;
++
++failed:
++      return 0;
++}
++
++
 +static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
 +{
 +      struct squashfs_super_block *sblk = &msblk->sblk;
 +              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");
++                      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");
++                      SERROR("Please recompile with Squashfs 2.0 support enabled\n");
 +                      return 0;
 +              }
 +      } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
 +      char b[BDEVNAME_SIZE];
 +      struct inode *root;
 +
-+      TRACE("Entered squashfs_read_superblock\n");
++      TRACE("Entered squashfs_fill_superblock\n");
 +
-+      if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
-+                                              GFP_KERNEL))) {
++      s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL);
++      if (s->s_fs_info == NULL) {
 +              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()))) {
++
++      msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize());
++      if (msblk->stream.workspace == NULL) {
 +              ERROR("Failed to allocate zlib workspace\n");
 +              goto failure;
 +      }
 +      init_waitqueue_head(&msblk->waitq);
 +      init_waitqueue_head(&msblk->fragment_wait_queue);
 +
++      /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not
++       * beyond filesystem end.  As we're using squashfs_read_data to read sblk here,
++       * first set sblk->bytes_used to a useful value */
 +      sblk->bytes_used = sizeof(struct squashfs_super_block);
 +      if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
 +                                      sizeof(struct squashfs_super_block) |
 +      }
 +
 +      /* 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));
++                      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));
 +              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)
++      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("Check data is %spresent 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);
 +      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->fragment_table_start %llx\n", sblk->fragment_table_start);
 +      TRACE("sblk->uid_start %llx\n", sblk->uid_start);
 +
++      s->s_maxbytes = MAX_LFS_FILESIZE;
 +      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");
++      if (readahead_metadata(s) == 0)
 +              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))) {
++      msblk->read_page = vmalloc(sblk->block_size);
++      if (msblk->read_page == NULL) {
 +              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))) {
++      msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
++                                      sizeof(unsigned int), GFP_KERNEL);
++      if (msblk->uid == NULL) {
 +              ERROR("Failed to allocate 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))) {
++      msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) *
++                              SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL);
++      if (msblk->fragment == NULL) {
 +              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;
++      msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS;
 +
 +      /* Allocate and read fragment index table */
 +      if (msblk->read_fragment_index_table(s) == 0)
 +              goto failed_mount;
 +      insert_inode_hash(root);
 +
-+      if ((s->s_root = d_alloc_root(root)) == NULL) {
++      s->s_root = d_alloc_root(root);
++      if (s->s_root == NULL) {
 +              ERROR("Root inode create failed\n");
 +              iput(root);
 +              goto failed_mount;
 +      }
 +
-+      TRACE("Leaving squashfs_read_super\n");
++      TRACE("Leaving squashfs_fill_super\n");
 +      return 0;
 +
 +failed_mount:
 +      kfree(msblk->fragment_index);
 +      kfree(msblk->fragment);
 +      kfree(msblk->uid);
-+      kfree(msblk->read_page);
++      vfree(msblk->read_page);
 +      kfree(msblk->block_cache);
 +      kfree(msblk->fragment_index_2);
 +      vfree(msblk->stream.workspace);
 +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;
++      int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes;
 +      long long block = SQUASHFS_I(inode)->start_block;
 +      int offset = SQUASHFS_I(inode)->offset;
 +      void *pageaddr = kmap(page);
 +                              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);
++              bytes = squashfs_get_cached_block(inode->i_sb, NULL, block,
++                              offset, PAGE_CACHE_SIZE, &block, &offset);
++              if (bytes == 0) {
++                      ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
 +                      goto skip_read;
 +              }
 +      }
 +              goto skip_read;
 +      }
 +
-+      bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
-+                                      i_size_read(inode) - length;
++      avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE);
 +
-+      if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
-+                                      offset, bytes, &block, &offset)))
++      bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset,
++              avail_bytes, &block, &offset);
++      if (bytes == 0)
 +              ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
 +
 +skip_read:
 +
 +      TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
 +
-+      if(msblk->meta_index == NULL)
++      if (msblk->meta_index == NULL)
 +              goto not_allocated;
 +
-+      for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
++      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 &&
 +                      meta = &msblk->meta_index[i];
 +                      offset = meta->offset;
 +              }
++      }
 +
 +      if (meta)
 +              meta->locked = 1;
 +
 +      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))) {
++      if (msblk->meta_index == NULL) {
++              msblk->meta_index = kmalloc(sizeof(struct meta_index) *
++                                      SQUASHFS_META_NUMBER, GFP_KERNEL);
++              if (msblk->meta_index == NULL) {
 +                      ERROR("Failed to allocate meta_index\n");
 +                      goto failed;
 +              }
-+              for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
++              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 &&
++      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) {
++      if (i == 0) {
 +              TRACE("empty_meta_index: failed!\n");
 +              goto failed;
 +      }
 +
 +
 +static int read_block_index(struct super_block *s, int blocks, char *block_list,
-+              long long *start_block, int *offset)
++                              long long *start_block, int *offset)
 +{
 +      struct squashfs_sb_info *msblk = s->s_fs_info;
 +      unsigned int *block_listp;
 +
 +              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);
++                      ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
 +                      goto failure;
 +              }
 +              SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
 +                              ((unsigned int *)sblock_list), blocks);
-+      } else
++      } 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);
++                      ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
 +                      goto failure;
 +              }
++      }
 +
 +      for (block_listp = (unsigned int *) block_list; blocks;
 +                              block_listp++, blocks --)
 + 
 +      index /= SQUASHFS_META_INDEXES * skip;
 +
-+      while ( offset < index ) {
++      while (offset < index) {
 +              meta = locate_meta_index(inode, index, offset + 1);
 +
 +              if (meta == NULL) {
-+                      if ((meta = empty_meta_index(inode, offset + 1,
-+                                                      skip)) == NULL)
++                      meta = empty_meta_index(inode, offset + 1, skip);
++                      if (meta == NULL)
 +                              goto all_done;
 +              } else {
 +                      if(meta->entries == 0)
 +                              goto failed;
++                      /* XXX */
 +                      offset = index < meta->offset + meta->entries ? index :
 +                              meta->offset + meta->entries - 1;
++                      /* XXX */
 +                      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);
++                              "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);
 +                      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);
++                              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;
 +              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);
++                     " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block);
 +
 +      if(res == -1)
 +              goto failure;
 +
 +      index -= res;
 +
-+      while ( index ) {
++      while (index) {
 +              int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
 +              int res = read_block_index(inode->i_sb, blocks, block_list,
 +                      &block_ptr, &offset);
 +              index -= blocks;
 +      }
 +
-+      if (read_block_index(inode->i_sb, 1, block_list,
-+                      &block_ptr, &offset) == -1)
++      if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1)
 +              goto failure;
 +      *bsize = *((unsigned int *) block_list);
 +
 +      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;
++      unsigned char *block_list = NULL;
 +      long long block;
-+      unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
++      unsigned int bsize, i;
++      int bytes;
 +      int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
 +      void *pageaddr;
 +      struct squashfs_fragment_cache *fragment = NULL;
 +      int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
 +      int start_index = page->index & ~mask;
 +      int end_index = start_index | mask;
++      int file_end = i_size_read(inode) >> sblk->block_log;
++      int sparse = 0;
 +
 +      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;
-+      }
++                                      page->index, SQUASHFS_I(inode)->start_block);
 +
 +      if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
 +                                      PAGE_CACHE_SHIFT))
-+              goto skip_read;
++              goto out;
 +
 +      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;
++                                      || index < file_end) {
++              block_list = kmalloc(SIZE, GFP_KERNEL);
++              if (block_list == NULL) {
++                      ERROR("Failed to allocate block_list\n");
++                      goto error_out;
++              }
++
++              block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize);
++              if (block == 0)
++                      goto error_out;
 +
-+              mutex_lock(&msblk->read_page_mutex);
++              if (bsize == 0) { /* hole */
++                      bytes = index == file_end ?
++                              (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size;
++                      sparse = 1;
++              } else {
++                      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;
++                      bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
++                              bsize, NULL, sblk->block_size);
++
++                      if (bytes == 0) {
++                              ERROR("Unable to read page, block %llx, size %x\n", block, bsize);
++                              mutex_unlock(&msblk->read_page_mutex);
++                              goto error_out;
++                      }
 +              }
 +      } 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) {
++              fragment = get_cached_fragment(inode->i_sb,
++                                      SQUASHFS_I(inode)-> u.s1.fragment_start_block,
++                                      SQUASHFS_I(inode)->u.s1.fragment_size);
++
++              if (fragment == 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;
++                                      SQUASHFS_I(inode)->u.s1.fragment_start_block,
++                                      (int) SQUASHFS_I(inode)->u.s1.fragment_size);
++                      goto error_out;
 +              }
-+              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;
++              bytes = i_size_read(inode) & (sblk->block_size - 1);
++              data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset;
 +      }
 +
-+      for (i = start_index; i <= end_index && byte_offset < bytes;
-+                                      i++, byte_offset += PAGE_CACHE_SIZE) {
++      for (i = start_index; i <= end_index && bytes > 0; i++,
++                                              bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) {
 +              struct page *push_page;
-+              int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
-+                                      PAGE_CACHE_SIZE : bytes - byte_offset;
++              int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE);
 +
-+              TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
-+                                      bytes, i, byte_offset, avail);
++              TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
 +
 +              push_page = (i == page->index) ? page :
 +                      grab_cache_page_nowait(page->mapping, i);
 +                      goto skip_page;
 +
 +              pageaddr = kmap_atomic(push_page, KM_USER0);
-+              memcpy(pageaddr, data_ptr + byte_offset, avail);
++              memcpy(pageaddr, data_ptr, avail);
 +              memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
 +              kunmap_atomic(pageaddr, KM_USER0);
 +              flush_dcache_page(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
++                                      || index < file_end) {
++              if (!sparse)
++                      mutex_unlock(&msblk->read_page_mutex);
++              kfree(block_list);
++      } 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:
++error_out:
++      SetPageError(page);
++out:
 +      pageaddr = kmap_atomic(page, KM_USER0);
-+      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      memset(pageaddr, 0, PAGE_CACHE_SIZE);
 +      kunmap_atomic(pageaddr, KM_USER0);
 +      flush_dcache_page(page);
-+      SetPageUptodate(page);
++      if (!PageError(page))
++              SetPageUptodate(page);
 +      unlock_page(page);
 +
 +      kfree(block_list);
 +}
 +
 +
-+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,
++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;
 +      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_get_cached_block(s, &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);
++                      squashfs_get_cached_block(s, &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);
++                                      index.size + 1, &index_start, &index_offset);
 +
 +              length = index.index;
 +              *next_block = index.start_block + sblk->directory_table_start;
 +}
 +
 +
-+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,
++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;
 +
 +      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))) {
++      str = kmalloc(sizeof(struct squashfs_dir_index) +
++              (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL);
++      if (str == NULL) {
 +              ERROR("Failed to allocate squashfs_dir_index\n");
 +              goto failure;
 +      }
 +      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_get_cached_block(s, &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, 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);
++              squashfs_get_cached_block(s, index->name, index_start, index_offset,
++                                      index->size + 1, &index_start, &index_offset);
 +
 +              index->name[index->size + 1] = '\0';
 +
 +
 +      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
 +      kfree(str);
++
 +failure:
 +      return length + 3;
 +}
 +      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;
++      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))) {
++      dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
++      if (dire == NULL) {
 +              ERROR("Failed to allocate squashfs_dir_entry\n");
 +              goto finish;
 +      }
 +              }
 +              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]);
++                              file->f_pos, i_ino, squashfs_filetype_table[1]);
 +
-+              if (filldir(dirent, name, size,
-+                              file->f_pos, i_ino,
++              if (filldir(dirent, name, size, file->f_pos, i_ino,
 +                              squashfs_filetype_table[1]) < 0) {
 +                              TRACE("Filldir returned less than 0\n");
-+                              goto finish;
++                      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);
++                              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))
++                      if (!squashfs_get_cached_block(i->i_sb, &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))
++                      if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
++                                      next_offset, sizeof(dirh), &next_block, &next_offset))
 +                              goto failed_read;
 +
 +                      length += sizeof(dirh);
 +              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))
++                              if (!squashfs_get_cached_block(i->i_sb, &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))
++                              if (!squashfs_get_cached_block(i->i_sb, 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))
++                      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;
 +                      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,
++                                      (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,
++                      if (filldir(dirent, dire->name, dire->size + 1, file->f_pos,
 +                                      dirh.inode_number + dire->inode_number,
-+                                      squashfs_filetype_table[dire->type])
-+                                      < 0) {
++                                      squashfs_filetype_table[dire->type]) < 0) {
 +                              TRACE("Filldir returned less than 0\n");
 +                              goto finish;
 +                      }
 +      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;
++      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))) {
++      dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
++      if (dire == NULL) {
 +              ERROR("Failed to allocate squashfs_dir_entry\n");
 +              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);
++                              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))
++                      if (!squashfs_get_cached_block(i->i_sb, &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))
++                      if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
++                                      next_offset, sizeof(dirh), &next_block, &next_offset))
 +                              goto failed_read;
 +
 +                      length += sizeof(dirh);
 +              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))
++                              if (!squashfs_get_cached_block(i->i_sb, &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))
++                              if (!squashfs_get_cached_block(i->i_sb, 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))
++                      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;
 +                              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,
++                              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);
 +      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);
++                      for (i = 0; i < squashfs_cached_blks; i++)
++                              if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK)
++                                      vfree(sbi->block_cache[i].data);
 +              if (sbi->fragment)
 +                      for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) 
-+                              SQUASHFS_FREE(sbi->fragment[i].data);
++                              vfree(sbi->fragment[i].data);
 +              kfree(sbi->fragment);
 +              kfree(sbi->block_cache);
-+              kfree(sbi->read_page);
++              vfree(sbi->read_page);
 +              kfree(sbi->uid);
 +              kfree(sbi->fragment_index);
 +              kfree(sbi->fragment_index_2);
 +
 +
 +static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
-+                              const char *dev_name, void *data,
-+                              struct vfsmount *mnt)
++                              const char *dev_name, void *data, struct vfsmount *mnt)
 +{
 +      return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
 +                              mnt);
 +      if (err)
 +              goto out;
 +
-+      printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) "
++      printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) "
 +              "Phillip Lougher\n");
 +
-+      if ((err = register_filesystem(&squashfs_fs_type)))
++      err = register_filesystem(&squashfs_fs_type);
++      if (err)
 +              destroy_inodecache();
 +
 +out:
 +{
 +      struct squashfs_inode_info *ei;
 +      ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
-+      if (!ei)
-+              return NULL;
-+      return &ei->vfs_inode;
++      return ei ? &ei->vfs_inode : NULL;
 +}
 +
 +
 +}
 +
 +
-+static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
++static void init_once(struct kmem_cache *cachep, void *foo)
 +{
 +      struct squashfs_inode_info *ei = foo;
 +
-+      if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-+                                                      SLAB_CTOR_CONSTRUCTOR)
-+              inode_init_once(&ei->vfs_inode);
++      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);
++          sizeof(struct squashfs_inode_info), 0,
++              SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
 +      if (squashfs_inode_cachep == NULL)
 +              return -ENOMEM;
 +      return 0;
 +
 +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_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem");
++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
 +MODULE_LICENSE("GPL");
---- /dev/null
-+++ linux-2.6.24-rc1/fs/squashfs/Makefile
+diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/Makefile linux-2.6.24-squashfs3.3/fs/squashfs/Makefile
+--- linux-2.6.24/fs/squashfs/Makefile  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/fs/squashfs/Makefile      2005-11-20 14:31:00.000000000 +0000
 @@ -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 @@
+diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/squashfs2_0.c linux-2.6.24-squashfs3.3/fs/squashfs/squashfs2_0.c
+--- linux-2.6.24/fs/squashfs/squashfs2_0.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/fs/squashfs/squashfs2_0.c 2007-10-25 00:43:59.000000000 +0100
+@@ -0,0 +1,740 @@
 +/*
 + * Squashfs - a compressed read only filesystem for Linux
 + *
 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
-+ * Phillip Lougher <phillip@lougher.org.uk>
++ * Phillip Lougher <phillip@lougher.demon.co.uk>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +      unsigned int block = SQUASHFS_INODE_BLK(inode) +
 +              sblk->inode_table_start;
 +      unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
-+      unsigned int ino = i->i_ino;
++      unsigned int ino = SQUASHFS_MK_VFS_INODE(block -
++              sblk->inode_table_start, offset);
 +      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");
++      TRACE("Entered squashfs_read_inode_2\n");
 +
 +      if (msblk->swap) {
 +              if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
 +                      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;
++                      i->i_data.a_ops = &squashfs_aops;
 +
 +                      TRACE("File inode %x:%x, start_block %x, "
 +                                      "block_list_start %llx, offset %x\n",
 +
 +      return 1;
 +}
---- /dev/null
-+++ linux-2.6.24-rc1/fs/squashfs/squashfs.h
-@@ -0,0 +1,87 @@
+diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/squashfs.h linux-2.6.24-squashfs3.3/fs/squashfs/squashfs.h
+--- linux-2.6.24/fs/squashfs/squashfs.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/fs/squashfs/squashfs.h    2007-08-19 04:23:16.000000000 +0100
+@@ -0,0 +1,86 @@
 +/*
 + * Squashfs - a compressed read only filesystem for Linux
 + *
 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
-+ * Phillip Lougher <phillip@lougher.org.uk>
++ * Phillip Lougher <phillip@lougher.demon.co.uk>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +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,
++extern int squashfs_get_cached_block(struct super_block *s, void *buffer,
 +                              long long block, unsigned int offset,
 +                              int length, long long *next_block,
 +                              unsigned int *next_offset);
 +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
 +      return 0;
 +}
 +#endif
---- /dev/null
-+++ linux-2.6.24-rc1/include/linux/squashfs_fs.h
-@@ -0,0 +1,934 @@
+diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs.h
+--- linux-2.6.24/include/linux/squashfs_fs.h   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs.h       2007-11-01 03:50:57.000000000 +0000
+@@ -0,0 +1,935 @@
 +#ifndef SQUASHFS_FS
 +#define SQUASHFS_FS
 +
 + * Squashfs
 + *
 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
-+ * Phillip Lougher <phillip@lougher.org.uk>
++ * Phillip Lougher <phillip@lougher.demon.co.uk>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +#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_MINOR                        1
 +#define SQUASHFS_MAGIC                        0x73717368
 +#define SQUASHFS_MAGIC_SWAP           0x68737173
 +#define SQUASHFS_START                        0
 +#define SQUASHFS_METADATA_LOG         13
 +
 +/* default size of data blocks */
-+#define SQUASHFS_FILE_SIZE            65536
-+#define SQUASHFS_FILE_LOG             16
++#define SQUASHFS_FILE_SIZE            131072
++#define SQUASHFS_FILE_LOG             17
 +
-+#define SQUASHFS_FILE_MAX_SIZE                65536
++#define SQUASHFS_FILE_MAX_SIZE                1048576
 +
 +/* Max number of uids and gids */
 +#define SQUASHFS_UIDS                 256
 +
 +#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_SIZE_BLOCK(B)     ((B) & \
++      ~SQUASHFS_COMPRESSED_BIT_BLOCK)
 +
 +#define SQUASHFS_COMPRESSED_BLOCK(B)  (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
 +
 +      unsigned int            start_block:24;
 +} __attribute__  ((packed));
 +
++union squashfs_inode_header_1 {
++      struct squashfs_base_inode_header_1     base;
++      struct squashfs_dev_inode_header_1      dev;
++      struct squashfs_symlink_inode_header_1  symlink;
++      struct squashfs_reg_inode_header_1      reg;
++      struct squashfs_dir_inode_header_1      dir;
++      struct squashfs_ipc_inode_header_1      ipc;
++};
++
 +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
 +      SQUASHFS_MEMSET(s, d, n);\
 +      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
 +
 +#endif
 +#endif
---- /dev/null
-+++ linux-2.6.24-rc1/include/linux/squashfs_fs_i.h
+diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs_i.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_i.h
+--- linux-2.6.24/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_i.h     2007-08-19 04:24:08.000000000 +0100
 @@ -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>
++ * Phillip Lougher <phillip@lougher.demon.co.uk>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +      struct inode    vfs_inode;
 +};
 +#endif
---- /dev/null
-+++ linux-2.6.24-rc1/include/linux/squashfs_fs_sb.h
-@@ -0,0 +1,74 @@
+diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs_sb.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_sb.h
+--- linux-2.6.24/include/linux/squashfs_fs_sb.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_sb.h    2007-08-19 04:24:26.000000000 +0100
+@@ -0,0 +1,76 @@
 +#ifndef SQUASHFS_FS_SB
 +#define SQUASHFS_FS_SB
 +/*
 + * Squashfs
 + *
 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
-+ * Phillip Lougher <phillip@lougher.org.uk>
++ * Phillip Lougher <phillip@lougher.demon.co.uk>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 +      struct meta_index       *meta_index;
 +      z_stream                stream;
 +      long long               *inode_lookup_table;
++      int                     unused_cache_blks;
++      int                     unused_frag_blks;
 +      int                     (*read_inode)(struct inode *i,  squashfs_inode_t \
 +                              inode);
 +      long long               (*read_blocklist)(struct inode *inode, int \
 +      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
+diff -x .gitignore -Nurp linux-2.6.24/init/do_mounts_rd.c linux-2.6.24-squashfs3.3/init/do_mounts_rd.c
+--- linux-2.6.24/init/do_mounts_rd.c   2007-10-25 17:41:49.000000000 +0100
++++ linux-2.6.24-squashfs3.3/init/do_mounts_rd.c       2007-11-01 05:06:25.000000000 +0000
 @@ -5,6 +5,7 @@
  #include <linux/ext2_fs.h>
  #include <linux/romfs_fs.h>
  #include <linux/initrd.h>
  #include <linux/string.h>
  
-@@ -39,6 +40,7 @@
+@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
   * numbers could not be found.
   *
   * We currently check for the following magic numbers:
   *    minix
   *    ext2
   *    romfs
-@@ -53,6 +55,7 @@
+@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
        struct ext2_super_block *ext2sb;
        struct romfs_super_block *romfsb;
        struct cramfs_super *cramfsb;
        int nblocks = -1;
        unsigned char *buf;
  
-@@ -64,6 +67,7 @@
+@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
        ext2sb = (struct ext2_super_block *) buf;
        romfsb = (struct romfs_super_block *) buf;
        cramfsb = (struct cramfs_super *) buf;
        memset(buf, 0xe5, size);
  
        /*
-@@ -101,6 +105,18 @@
+@@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
                goto done;
        }
  
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/uvesafb-0.1-rc3-2.6.22.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/uvesafb-0.1-rc3-2.6.22.patch
deleted file mode 100644 (file)
index 7113751..0000000
+++ /dev/null
@@ -1,2590 +0,0 @@
----
- Documentation/fb/uvesafb.txt |  188 +++
- drivers/video/Kconfig        |   18 
- drivers/video/Makefile       |    1 
- drivers/video/modedb.c       |   28 
- drivers/video/uvesafb.c      | 2058 +++++++++++++++++++++++++++++++++++++++++++
- include/linux/connector.h    |    7 
- include/video/Kbuild         |    2 
- include/video/uvesafb.h      |  193 ++++
- 8 files changed, 2479 insertions(+), 16 deletions(-)
-
-Index: linux-2.6.22/Documentation/fb/uvesafb.txt
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/Documentation/fb/uvesafb.txt  2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,188 @@
-+
-+uvesafb - A Generic Driver for VBE2+ compliant video cards
-+==========================================================
-+
-+1. Requirements
-+---------------
-+
-+uvesafb should work with any video card that has a Video BIOS compliant
-+with the VBE 2.0 standard.
-+
-+Unlike other drivers, uvesafb makes use of a userspace helper called
-+v86d.  v86d is used to run the x86 Video BIOS code in a simulated and
-+controlled environment.  This allows uvesafb to function on arches other
-+than x86.  Check the v86d documentation for a list of currently supported
-+arches.
-+
-+v86d source code can be downloaded from the following website:
-+  http://dev.gentoo.org/~spock/projects/uvesafb
-+
-+Please refer to the v86d documentation for detailed configuration and
-+installation instructions.
-+
-+Note that the v86d userspace helper has to be available at all times in
-+order for uvesafb to work properly.  If you want to use uvesafb during
-+early boot, you will have to include v86d into an initramfs image, and
-+either compile it into the kernel or use it as an initrd.
-+
-+2. Caveats and limitations
-+--------------------------
-+
-+uvesafb is a _generic_ driver which supports a wide variety of video
-+cards, but which is ultimately limited by the Video BIOS interface.
-+The most important limitations are:
-+
-+- Lack of any type of acceleration.
-+- A strict and limited set of supported video modes.  Often the native
-+  or most optimal resolution/refresh rate for your setup will not work
-+  with uvesafb, simply because the Video BIOS doesn't support the
-+  video mode you want to use.  This can be especially painful with
-+  widescreen panels, where native video modes don't have the 4:3 aspect
-+  ratio, which is what most BIOS-es are limited to.
-+- Adjusting the refresh rate is only possible with a VBE 3.0 compliant
-+  Video BIOS.  Note that many nVidia Video BIOS-es claim to be VBE 3.0
-+  compliant, while they simply ignore any refresh rate settings.
-+
-+3. Configuration
-+----------------
-+
-+uvesafb can be compiled either as a module, or directly into the kernel.
-+In both cases it supports the same set of configuration options, which
-+are either given on the kernel command line or as module parameters, e.g.:
-+
-+ video=uvesafb:1024x768-32,mtrr:3,ywrap (compiled into the kernel)
-+
-+ # modprobe uvesafb mode=1024x768-32 mtrr=3 scroll=ywrap  (module)
-+
-+Accepted options:
-+
-+ypan    Enable display panning using the VESA protected mode
-+        interface.  The visible screen is just a window of the
-+        video memory, console scrolling is done by changing the
-+        start of the window.  Available on x86 only.
-+
-+ywrap   Same as ypan, but assumes your gfx board can wrap-around
-+        the video memory (i.e. starts reading from top if it
-+        reaches the end of video memory).  Faster than ypan.
-+              Available on x86 only.
-+
-+redraw  Scroll by redrawing the affected part of the screen, this
-+        is the safe (and slow) default.
-+
-+(If you're using uvesafb as a module, the above three options are
-+ used a parameter of the scroll option, e.g. scroll=ypan.)
-+
-+vgapal  Use the standard VGA registers for palette changes.
-+
-+pmipal  Use the protected mode interface for palette changes.
-+        This is the default if the protected mode interface is
-+        available.  Available on x86 only.
-+
-+mtrr:n  Setup memory type range registers for the framebuffer
-+        where n:
-+              0 - disabled (equivalent to nomtrr) (default)
-+              1 - uncachable
-+              2 - write-back
-+              3 - write-combining
-+              4 - write-through
-+
-+        If you see the following in dmesg, choose the type that matches
-+        the old one.  In this example, use "mtrr:2".
-+...
-+mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining
-+...
-+
-+nomtrr  Do not use memory type range registers.
-+
-+vremap:n
-+        Remap 'n' MiB of video RAM.  If 0 or not specified, remap memory
-+        according to video mode.
-+
-+vtotal:n
-+        If the video BIOS of your card incorrectly determines the total
-+        amount of video RAM, use this option to override the BIOS (in MiB).
-+
-+<mode>  The mode you want to set, in the standard modedb format.  Refer to
-+        modedb.txt for a detailed description.  When uvesafb is compiled as
-+        a module, the mode string should be provided as a value of the
-+        'mode' option.
-+
-+vbemode:x
-+        Force the use of VBE mode x.  The mode will only be set if it's
-+        found in the VBE-provided list of supported modes.
-+        NOTE: The mode number 'x' should be specified in VESA mode number
-+        notation, not the Linux kernel one (eg. 257 instead of 769).
-+        HINT: If you use this option because normal <mode> parameter does
-+        not work for you and you use a X server, you'll probably want to
-+        set the 'nocrtc' option to ensure that the video mode is properly
-+        restored after console <-> X switches.
-+
-+nocrtc  Do not use CRTC timings while setting the video mode.  This option
-+        has any effect only if the Video BIOS is VBE 3.0 compliant.  Use it
-+        if you have problems with modes set the standard way.  Note that
-+        using this option implies that any refresh rate adjustments will
-+        be ignored and the refresh rate will stay at your BIOS default (60 Hz).
-+
-+noedid  Do not try to fetch and use EDID-provided modes.
-+
-+noblank Disable hardware blanking.
-+
-+v86d:path
-+        Set path to the v86d executable. This option is only available as
-+        a module parameter, and not as a part of the video= string.  If you
-+        need to use it and have uvesafb built into the kernel, use
-+        uvesafb.v86d="path".
-+
-+Additionally, the following parameters may be provided.  They all override the
-+EDID-provided values and BIOS defaults.  Refer to your monitor's specs to get
-+the correct values for maxhf, maxvf and maxclk for your hardware.
-+
-+maxhf:n     Maximum horizontal frequency (in kHz).
-+maxvf:n     Maximum vertical frequency (in Hz).
-+maxclk:n    Maximum pixel clock (in MHz).
-+
-+4. The sysfs interface
-+----------------------
-+
-+uvesafb provides several sysfs nodes for configurable parameters and
-+additional information.
-+
-+Driver attributes:
-+
-+/sys/bus/platform/drivers/uvesafb
-+  - v86d (default: /sbin/v86d)
-+    Path to the v86d executable. v86d is started by uvesafb
-+    if an instance of the daemon isn't already running.
-+
-+Device attributes:
-+
-+/sys/bus/platform/drivers/uvesafb/uvesafb.0
-+  - nocrtc
-+    Use the default refresh rate (60 Hz) if set to 1.
-+
-+  - oem_product_name
-+  - oem_product_rev
-+  - oem_string
-+  - oem_vendor
-+    Information about the card and its maker.
-+
-+  - vbe_modes
-+    A list of video modes supported by the Video BIOS along with their
-+    VBE mode numbers in hex.
-+
-+  - vbe_version
-+    A BCD value indicating the implemented VBE standard.
-+
-+5. Miscellaneous
-+----------------
-+
-+Uvesafb will set a video mode with the default refresh rate and timings
-+from the Video BIOS if you set pixclock to 0 in fb_var_screeninfo.
-+
-+
-+--
-+ Michal Januszewski <spock@gentoo.org>
-+ Last updated: 2007-06-16
-+
-+ Documentation of the uvesafb options is loosely based on vesafb.txt.
-+
-Index: linux-2.6.22/drivers/video/Kconfig
-===================================================================
---- linux-2.6.22.orig/drivers/video/Kconfig    2007-08-28 21:56:33.000000000 +0100
-+++ linux-2.6.22/drivers/video/Kconfig 2007-08-28 21:56:34.000000000 +0100
-@@ -592,6 +592,24 @@ config FB_TGA
-         Say Y if you have one of those.
-+config FB_UVESA
-+      tristate "Userspace VESA VGA graphics support"
-+      depends on FB && CONNECTOR
-+      select FB_CFB_FILLRECT
-+      select FB_CFB_COPYAREA
-+      select FB_CFB_IMAGEBLIT
-+      select FB_MODE_HELPERS
-+      help
-+        This is the frame buffer driver for generic VBE 2.0 compliant
-+        graphic cards. It can also take advantage of VBE 3.0 features,
-+        such as refresh rate adjustment.
-+
-+        This driver generally provides more features than vesafb but
-+        requires a userspace helper application called 'v86d'. See
-+        <file:Documentation/fb/uvesafb.txt> for more information.
-+
-+        If unsure, say N.
-+
- config FB_VESA
-       bool "VESA VGA graphics support"
-       depends on (FB = y) && X86
-Index: linux-2.6.22/drivers/video/Makefile
-===================================================================
---- linux-2.6.22.orig/drivers/video/Makefile   2007-08-28 21:56:33.000000000 +0100
-+++ linux-2.6.22/drivers/video/Makefile        2007-08-28 21:56:34.000000000 +0100
-@@ -116,6 +116,7 @@ obj-$(CONFIG_FB_XILINX)           += xil
- obj-$(CONFIG_FB_OMAP)             += omap/
- # Platform or fallback drivers go here
-+obj-$(CONFIG_FB_UVESA)            += uvesafb.o
- obj-$(CONFIG_FB_VESA)             += vesafb.o
- obj-$(CONFIG_FB_IMAC)             += imacfb.o
- obj-$(CONFIG_FB_VGA16)            += vga16fb.o
-Index: linux-2.6.22/drivers/video/modedb.c
-===================================================================
---- linux-2.6.22.orig/drivers/video/modedb.c   2007-08-28 21:54:13.000000000 +0100
-+++ linux-2.6.22/drivers/video/modedb.c        2007-08-28 21:56:34.000000000 +0100
-@@ -606,26 +606,29 @@ done:
-       DPRINTK("Trying specified video mode%s %ix%i\n",
-           refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
--      diff = refresh;
-+      if (!refresh_specified)
-+              diff = 0;
-+      else
-+              diff = refresh;
-+
-       best = -1;
-       for (i = 0; i < dbsize; i++) {
--              if (name_matches(db[i], name, namelen) ||
--                  (res_specified && res_matches(db[i], xres, yres))) {
--                      if(!fb_try_mode(var, info, &db[i], bpp)) {
--                              if(!refresh_specified || db[i].refresh == refresh)
--                                      return 1;
--                              else {
--                                      if(diff > abs(db[i].refresh - refresh)) {
--                                              diff = abs(db[i].refresh - refresh);
--                                              best = i;
--                                      }
-+              if ((name_matches(db[i], name, namelen) ||
-+                  (res_specified && res_matches(db[i], xres, yres))) &&
-+                  !fb_try_mode(var, info, &db[i], bpp)) {
-+                      if (refresh_specified && db[i].refresh == refresh) {
-+                              return 1;
-+                      } else {
-+                              if (diff < db[i].refresh) {
-+                                      diff = db[i].refresh;
-+                                      best = i;
-                               }
-                       }
-               }
-       }
-       if (best != -1) {
-               fb_try_mode(var, info, &db[best], bpp);
--              return 2;
-+              return (refresh_specified) ? 2 : 1;
-       }
-       diff = xres + yres;
-@@ -938,6 +941,7 @@ void fb_destroy_modelist(struct list_hea
-               kfree(pos);
-       }
- }
-+EXPORT_SYMBOL_GPL(fb_destroy_modelist);
- /**
-  * fb_videomode_to_modelist: convert mode array to mode list
-Index: linux-2.6.22/drivers/video/uvesafb.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/video/uvesafb.c       2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,2058 @@
-+/*
-+ * A framebuffer driver for VBE 2.0+ compliant video cards
-+ *
-+ * (c) 2007 Michal Januszewski <spock@gentoo.org>
-+ *     Loosely based upon the vesafb driver.
-+ *
-+ */
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/skbuff.h>
-+#include <linux/timer.h>
-+#include <linux/completion.h>
-+#include <linux/connector.h>
-+#include <linux/random.h>
-+#include <linux/platform_device.h>
-+#include <linux/limits.h>
-+#include <linux/fb.h>
-+#include <linux/io.h>
-+#include <linux/mutex.h>
-+#include <video/edid.h>
-+#include <video/vga.h>
-+#include <video/uvesafb.h>
-+#ifdef CONFIG_MTRR
-+#include <asm/mtrr.h>
-+#endif
-+#include "edid.h"
-+
-+static struct cb_id uvesafb_cn_id = {
-+      .idx = CN_IDX_V86D,
-+      .val = CN_VAL_V86D_UVESAFB
-+};
-+static char v86d_path[PATH_MAX] = "/sbin/v86d";
-+static char v86d_started;     /* has v86d been started by uvesafb? */
-+
-+static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
-+      .id     = "VESA VGA",
-+      .type   = FB_TYPE_PACKED_PIXELS,
-+      .accel  = FB_ACCEL_NONE,
-+      .visual = FB_VISUAL_TRUECOLOR,
-+};
-+
-+static int mtrr               __devinitdata = 3; /* enable mtrr by default */
-+static int blank      __devinitdata = 1; /* enable blanking by default */
-+static int ypan               __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */
-+static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */
-+static int nocrtc     __devinitdata; /* ignore CRTC settings */
-+static int noedid     __devinitdata; /* don't try DDC transfers */
-+static int vram_remap __devinitdata; /* set amt. of memory to be used */
-+static int vram_total __devinitdata; /* set total amount of memory */
-+static u16 maxclk     __devinitdata; /* maximum pixel clock */
-+static u16 maxvf      __devinitdata; /* maximum vertical frequency */
-+static u16 maxhf      __devinitdata; /* maximum horizontal frequency */
-+static u16 vbemode    __devinitdata; /* force use of a specific VBE mode */
-+static char *mode_option __devinitdata;
-+
-+static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX];
-+static DEFINE_MUTEX(uvfb_lock);
-+
-+/*
-+ * A handler for replies from userspace.
-+ *
-+ * Make sure each message passes consistency checks and if it does,
-+ * find the kernel part of the task struct, copy the registers and
-+ * the buffer contents and then complete the task.
-+ */
-+static void uvesafb_cn_callback(void *data)
-+{
-+      struct cn_msg *msg = data;
-+      struct uvesafb_task *utask;
-+      struct uvesafb_ktask *task;
-+
-+      if (msg->seq >= UVESAFB_TASKS_MAX)
-+              return;
-+
-+      mutex_lock(&uvfb_lock);
-+      task = uvfb_tasks[msg->seq];
-+
-+      if (!task || msg->ack != task->ack) {
-+              mutex_unlock(&uvfb_lock);
-+              return;
-+      }
-+
-+      utask = (struct uvesafb_task *)msg->data;
-+
-+      /* Sanity checks for the buffer length. */
-+      if (task->t.buf_len < utask->buf_len ||
-+          utask->buf_len > msg->len - sizeof(*utask)) {
-+              mutex_unlock(&uvfb_lock);
-+              return;
-+      }
-+
-+      uvfb_tasks[msg->seq] = NULL;
-+      mutex_unlock(&uvfb_lock);
-+
-+      memcpy(&task->t, utask, sizeof(*utask));
-+
-+      if (task->t.buf_len && task->buf)
-+              memcpy(task->buf, utask + 1, task->t.buf_len);
-+
-+      complete(task->done);
-+      return;
-+}
-+
-+static int uvesafb_helper_start(void)
-+{
-+      char *envp[] = {
-+              "HOME=/",
-+              "PATH=/sbin:/bin",
-+              NULL,
-+      };
-+
-+      char *argv[] = {
-+              v86d_path,
-+              NULL,
-+      };
-+
-+      return call_usermodehelper(v86d_path, argv, envp, 1);
-+}
-+
-+/*
-+ * Execute a uvesafb task.
-+ *
-+ * Returns 0 if the task is executed successfully.
-+ *
-+ * A message sent to the userspace consists of the uvesafb_task
-+ * struct and (optionally) a buffer. The uvesafb_task struct is
-+ * a simplified version of uvesafb_ktask (its kernel counterpart)
-+ * containing only the register values, flags and the length of
-+ * the buffer.
-+ *
-+ * Each message is assigned a sequence number (increased linearly)
-+ * and a random ack number. The sequence number is used as a key
-+ * for the uvfb_tasks array which holds pointers to uvesafb_ktask
-+ * structs for all requests.
-+ */
-+static int uvesafb_exec(struct uvesafb_ktask *task)
-+{
-+      static int seq;
-+      struct cn_msg *m;
-+      int err;
-+      int len = sizeof(task->t) + task->t.buf_len;
-+
-+      /*
-+       * Check whether the message isn't longer than the maximum
-+       * allowed by connector.
-+       */
-+      if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) {
-+              printk(KERN_WARNING "uvesafb: message too long (%d), "
-+                      "can't execute task\n", (int)(sizeof(*m) + len));
-+              return -E2BIG;
-+      }
-+
-+      m = kzalloc(sizeof(*m) + len, GFP_KERNEL);
-+      if (!m)
-+              return -ENOMEM;
-+
-+      init_completion(task->done);
-+
-+      memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id));
-+      m->seq = seq;
-+      m->len = len;
-+      m->ack = random32();
-+
-+      /* uvesafb_task structure */
-+      memcpy(m + 1, &task->t, sizeof(task->t));
-+
-+      /* Buffer */
-+      memcpy((u8 *)(m + 1) + sizeof(task->t), task->buf, task->t.buf_len);
-+
-+      /*
-+       * Save the message ack number so that we can find the kernel
-+       * part of this task when a reply is received from userspace.
-+       */
-+      task->ack = m->ack;
-+
-+      mutex_lock(&uvfb_lock);
-+
-+      /* If all slots are taken -- bail out. */
-+      if (uvfb_tasks[seq]) {
-+              mutex_unlock(&uvfb_lock);
-+              return -EBUSY;
-+      }
-+
-+      /* Save a pointer to the kernel part of the task struct. */
-+      uvfb_tasks[seq] = task;
-+      mutex_unlock(&uvfb_lock);
-+
-+      err = cn_netlink_send(m, 0, gfp_any());
-+      if (err == -ESRCH) {
-+              /*
-+               * Try to start the userspace helper if sending
-+               * the request failed the first time.
-+               */
-+              err = uvesafb_helper_start();
-+              if (err) {
-+                      printk(KERN_ERR "uvesafb: failed to execute %s\n",
-+                                      v86d_path);
-+                      printk(KERN_ERR "uvesafb: make sure that the v86d "
-+                                      "helper is installed and executable\n");
-+              } else {
-+                      v86d_started = 1;
-+                      err = cn_netlink_send(m, 0, gfp_any());
-+              }
-+      }
-+      kfree(m);
-+
-+      if (!err && !(task->t.flags & TF_EXIT))
-+              err = !wait_for_completion_timeout(task->done,
-+                              msecs_to_jiffies(UVESAFB_TIMEOUT));
-+
-+      mutex_lock(&uvfb_lock);
-+      uvfb_tasks[seq] = NULL;
-+      mutex_unlock(&uvfb_lock);
-+
-+      seq++;
-+      if (seq >= UVESAFB_TASKS_MAX)
-+              seq = 0;
-+
-+      return err;
-+}
-+
-+/*
-+ * Free a uvesafb_ktask struct.
-+ */
-+static void uvesafb_free(struct uvesafb_ktask *task)
-+{
-+      if (task) {
-+              if (task->done)
-+                      kfree(task->done);
-+              kfree(task);
-+      }
-+}
-+
-+/*
-+ * Prepare a uvesafb_ktask struct to be used again.
-+ */
-+static void uvesafb_reset(struct uvesafb_ktask *task)
-+{
-+      struct completion *cpl = task->done;
-+
-+      memset(task, 0, sizeof(*task));
-+      task->done = cpl;
-+}
-+
-+/*
-+ * Allocate and prepare a uvesafb_ktask struct.
-+ */
-+static struct uvesafb_ktask *uvesafb_prep(void)
-+{
-+      struct uvesafb_ktask *task;
-+
-+      task = kzalloc(sizeof(*task), GFP_KERNEL);
-+      if (task) {
-+              task->done = kzalloc(sizeof(*task->done), GFP_KERNEL);
-+              if (!task->done) {
-+                      kfree(task);
-+                      task = NULL;
-+              }
-+      }
-+      return task;
-+}
-+
-+static void uvesafb_setup_var(struct fb_var_screeninfo *var,
-+              struct fb_info *info, struct vbe_mode_ib *mode)
-+{
-+      struct uvesafb_par *par = info->par;
-+
-+      var->vmode = FB_VMODE_NONINTERLACED;
-+      var->sync = FB_SYNC_VERT_HIGH_ACT;
-+
-+      var->xres = mode->x_res;
-+      var->yres = mode->y_res;
-+      var->xres_virtual = mode->x_res;
-+      var->yres_virtual = (par->ypan) ?
-+                      info->fix.smem_len / mode->bytes_per_scan_line :
-+                      mode->y_res;
-+      var->xoffset = 0;
-+      var->yoffset = 0;
-+      var->bits_per_pixel = mode->bits_per_pixel;
-+
-+      if (var->bits_per_pixel == 15)
-+              var->bits_per_pixel = 16;
-+
-+      if (var->bits_per_pixel > 8) {
-+              var->red.offset    = mode->red_off;
-+              var->red.length    = mode->red_len;
-+              var->green.offset  = mode->green_off;
-+              var->green.length  = mode->green_len;
-+              var->blue.offset   = mode->blue_off;
-+              var->blue.length   = mode->blue_len;
-+              var->transp.offset = mode->rsvd_off;
-+              var->transp.length = mode->rsvd_len;
-+      } else {
-+              var->red.offset    = 0;
-+              var->green.offset  = 0;
-+              var->blue.offset   = 0;
-+              var->transp.offset = 0;
-+
-+              /*
-+               * We're assuming that we can switch the DAC to 8 bits. If
-+               * this proves to be incorrect, we'll update the fields
-+               * later in set_par().
-+               */
-+              if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) {
-+                      var->red.length    = 8;
-+                      var->green.length  = 8;
-+                      var->blue.length   = 8;
-+                      var->transp.length = 0;
-+              } else {
-+                      var->red.length    = 6;
-+                      var->green.length  = 6;
-+                      var->blue.length   = 6;
-+                      var->transp.length = 0;
-+              }
-+      }
-+}
-+
-+static int uvesafb_vbe_find_mode(struct uvesafb_par *par,
-+              int xres, int yres, int depth, unsigned char flags)
-+{
-+      int i, match = -1, h = 0, d = 0x7fffffff;
-+
-+      for (i = 0; i < par->vbe_modes_cnt; i++) {
-+              h = abs(par->vbe_modes[i].x_res - xres) +
-+                  abs(par->vbe_modes[i].y_res - yres) +
-+                  abs(depth - par->vbe_modes[i].depth);
-+
-+              /*
-+               * We have an exact match in terms of resolution
-+               * and depth.
-+               */
-+              if (h == 0)
-+                      return i;
-+
-+              if (h < d || (h == d && par->vbe_modes[i].depth > depth)) {
-+                      d = h;
-+                      match = i;
-+              }
-+      }
-+      i = 1;
-+
-+      if (flags & UVESAFB_EXACT_DEPTH &&
-+                      par->vbe_modes[match].depth != depth)
-+              i = 0;
-+
-+      if (flags & UVESAFB_EXACT_RES && d > 24)
-+              i = 0;
-+
-+      if (i != 0)
-+              return match;
-+      else
-+              return -1;
-+}
-+
-+static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par)
-+{
-+      struct uvesafb_ktask *task;
-+      u8 *state;
-+      int err;
-+
-+      if (!par->vbe_state_size)
-+              return NULL;
-+
-+      state = kmalloc(par->vbe_state_size, GFP_KERNEL);
-+      if (!state)
-+              return NULL;
-+
-+      task = uvesafb_prep();
-+      if (!task) {
-+              kfree(state);
-+              return NULL;
-+      }
-+
-+      task->t.regs.eax = 0x4f04;
-+      task->t.regs.ecx = 0x000f;
-+      task->t.regs.edx = 0x0001;
-+      task->t.flags = TF_BUF_RET | TF_BUF_ESBX;
-+      task->t.buf_len = par->vbe_state_size;
-+      task->buf = state;
-+      err = uvesafb_exec(task);
-+
-+      if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-+              printk(KERN_WARNING "uvesafb: VBE get state call "
-+                              "failed (eax=0x%x, err=%d)\n",
-+                              task->t.regs.eax, err);
-+              kfree(state);
-+              state = NULL;
-+      }
-+
-+      uvesafb_free(task);
-+      return state;
-+}
-+
-+static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf)
-+{
-+      struct uvesafb_ktask *task;
-+      int err;
-+
-+      if (!state_buf)
-+              return;
-+
-+      task = uvesafb_prep();
-+      if (!task)
-+              return;
-+
-+      task->t.regs.eax = 0x4f04;
-+      task->t.regs.ecx = 0x000f;
-+      task->t.regs.edx = 0x0002;
-+      task->t.buf_len = par->vbe_state_size;
-+      task->t.flags = TF_BUF_ESBX;
-+      task->buf = state_buf;
-+
-+      err = uvesafb_exec(task);
-+      if (err || (task->t.regs.eax & 0xffff) != 0x004f)
-+              printk(KERN_WARNING "uvesafb: VBE state restore call "
-+                              "failed (eax=0x%x, err=%d)\n",
-+                              task->t.regs.eax, err);
-+
-+      uvesafb_free(task);
-+}
-+
-+static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
-+              struct uvesafb_par *par)
-+{
-+      int err;
-+
-+      task->t.regs.eax = 0x4f00;
-+      task->t.flags = TF_VBEIB;
-+      task->t.buf_len = sizeof(struct vbe_ib);
-+      task->buf = &par->vbe_ib;
-+      strncpy(par->vbe_ib.vbe_signature, "VBE2", 4);
-+
-+      err = uvesafb_exec(task);
-+      if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-+              printk(KERN_ERR "uvesafb: Getting VBE info block failed "
-+                              "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax,
-+                              err);
-+              return -EINVAL;
-+      }
-+
-+      if (par->vbe_ib.vbe_version < 0x0200) {
-+              printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are "
-+                              "not supported.\n");
-+              return -EINVAL;
-+      }
-+
-+      if (!par->vbe_ib.mode_list_ptr) {
-+              printk(KERN_ERR "uvesafb: Missing mode list!\n");
-+              return -EINVAL;
-+      }
-+
-+      printk(KERN_INFO "uvesafb: ");
-+
-+      /*
-+       * Convert string pointers and the mode list pointer into
-+       * usable addresses. Print informational messages about the
-+       * video adapter and its vendor.
-+       */
-+      if (par->vbe_ib.oem_vendor_name_ptr)
-+              printk("%s, ",
-+                      ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr);
-+
-+      if (par->vbe_ib.oem_product_name_ptr)
-+              printk("%s, ",
-+                      ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr);
-+
-+      if (par->vbe_ib.oem_product_rev_ptr)
-+              printk("%s, ",
-+                      ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr);
-+
-+      if (par->vbe_ib.oem_string_ptr)
-+              printk("OEM: %s, ",
-+                      ((char *)task->buf) + par->vbe_ib.oem_string_ptr);
-+
-+      printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8),
-+                      par->vbe_ib.vbe_version & 0xff);
-+
-+      return 0;
-+}
-+
-+static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
-+              struct uvesafb_par *par)
-+{
-+      int off = 0, err;
-+      u16 *mode;
-+
-+      par->vbe_modes_cnt = 0;
-+
-+      /* Count available modes. */
-+      mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr);
-+      while (*mode != 0xffff) {
-+              par->vbe_modes_cnt++;
-+              mode++;
-+      }
-+
-+      par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) *
-+                              par->vbe_modes_cnt, GFP_KERNEL);
-+      if (!par->vbe_modes)
-+              return -ENOMEM;
-+
-+      /* Get info about all available modes. */
-+      mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr);
-+      while (*mode != 0xffff) {
-+              struct vbe_mode_ib *mib;
-+
-+              uvesafb_reset(task);
-+              task->t.regs.eax = 0x4f01;
-+              task->t.regs.ecx = (u32) *mode;
-+              task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
-+              task->t.buf_len = sizeof(struct vbe_mode_ib);
-+              task->buf = par->vbe_modes + off;
-+
-+              err = uvesafb_exec(task);
-+              if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-+                      printk(KERN_ERR "uvesafb: Getting mode info block "
-+                              "for mode 0x%x failed (eax=0x%x, err=%d)\n",
-+                              *mode, (u32)task->t.regs.eax, err);
-+                      return -EINVAL;
-+              }
-+
-+              mib = task->buf;
-+              mib->mode_id = *mode;
-+
-+              /*
-+               * We only want modes that are supported with the current
-+               * hardware configuration, color, graphics and that have
-+               * support for the LFB.
-+               */
-+              if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK &&
-+                               mib->bits_per_pixel >= 8)
-+                      off++;
-+              else
-+                      par->vbe_modes_cnt--;
-+
-+              mode++;
-+              mib->depth = mib->red_len + mib->green_len + mib->blue_len;
-+
-+              /*
-+               * Handle 8bpp modes and modes with broken color component
-+               * lengths.
-+               */
-+              if (mib->depth == 0 || (mib->depth == 24 &&
-+                                      mib->bits_per_pixel == 32))
-+                      mib->depth = mib->bits_per_pixel;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * The Protected Mode Interface is 32-bit x86 code, so we only run it on
-+ * x86 and not x86_64.
-+ */
-+#ifdef CONFIG_X86_32
-+static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
-+              struct uvesafb_par *par)
-+{
-+      int i, err;
-+
-+      uvesafb_reset(task);
-+      task->t.regs.eax = 0x4f0a;
-+      task->t.regs.ebx = 0x0;
-+      err = uvesafb_exec(task);
-+
-+      if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) {
-+              par->pmi_setpal = par->ypan = 0;
-+      } else {
-+              par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4)
-+                                              + task->t.regs.edi);
-+              par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1];
-+              par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2];
-+              printk(KERN_INFO "uvesafb: protected mode interface info at "
-+                               "%04x:%04x\n",
-+                               (u16)task->t.regs.es, (u16)task->t.regs.edi);
-+              printk(KERN_INFO "uvesafb: pmi: set display start = %p, "
-+                               "set palette = %p\n", par->pmi_start,
-+                               par->pmi_pal);
-+
-+              if (par->pmi_base[3]) {
-+                      printk(KERN_INFO "uvesafb: pmi: ports = ");
-+                      for (i = par->pmi_base[3]/2;
-+                                      par->pmi_base[i] != 0xffff; i++)
-+                              printk("%x ", par->pmi_base[i]);
-+                      printk("\n");
-+
-+                      if (par->pmi_base[i] != 0xffff) {
-+                              printk(KERN_INFO "uvesafb: can't handle memory"
-+                                               " requests, pmi disabled\n");
-+                              par->ypan = par->pmi_setpal = 0;
-+                      }
-+              }
-+      }
-+      return 0;
-+}
-+#endif /* CONFIG_X86_32 */
-+
-+/*
-+ * Check whether a video mode is supported by the Video BIOS and is
-+ * compatible with the monitor limits.
-+ */
-+static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode,
-+              struct fb_info *info)
-+{
-+      if (info->monspecs.gtf) {
-+              fb_videomode_to_var(&info->var, mode);
-+              if (fb_validate_mode(&info->var, info))
-+                      return 0;
-+      }
-+
-+      if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8,
-+                              UVESAFB_EXACT_RES) == -1)
-+              return 0;
-+
-+      return 1;
-+}
-+
-+static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
-+              struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+      int err = 0;
-+
-+      if (noedid || par->vbe_ib.vbe_version < 0x0300)
-+              return -EINVAL;
-+
-+      task->t.regs.eax = 0x4f15;
-+      task->t.regs.ebx = 0;
-+      task->t.regs.ecx = 0;
-+      task->t.buf_len = 0;
-+      task->t.flags = 0;
-+
-+      err = uvesafb_exec(task);
-+
-+      if ((task->t.regs.eax & 0xffff) != 0x004f || err)
-+              return -EINVAL;
-+
-+      if ((task->t.regs.ebx & 0x3) == 3) {
-+              printk(KERN_INFO "uvesafb: VBIOS/hardware supports both "
-+                               "DDC1 and DDC2 transfers\n");
-+      } else if ((task->t.regs.ebx & 0x3) == 2) {
-+              printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 "
-+                               "transfers\n");
-+      } else if ((task->t.regs.ebx & 0x3) == 1) {
-+              printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 "
-+                               "transfers\n");
-+      } else {
-+              printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support "
-+                               "DDC transfers\n");
-+              return -EINVAL;
-+      }
-+
-+      task->t.regs.eax = 0x4f15;
-+      task->t.regs.ebx = 1;
-+      task->t.regs.ecx = task->t.regs.edx = 0;
-+      task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
-+      task->t.buf_len = EDID_LENGTH;
-+      task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL);
-+
-+      err = uvesafb_exec(task);
-+
-+      if ((task->t.regs.eax & 0xffff) == 0x004f && !err) {
-+              fb_edid_to_monspecs(task->buf, &info->monspecs);
-+
-+              if (info->monspecs.vfmax && info->monspecs.hfmax) {
-+                      /*
-+                       * If the maximum pixel clock wasn't specified in
-+                       * the EDID block, set it to 300 MHz.
-+                       */
-+                      if (info->monspecs.dclkmax == 0)
-+                              info->monspecs.dclkmax = 300 * 1000000;
-+                      info->monspecs.gtf = 1;
-+              }
-+      } else {
-+              err = -EINVAL;
-+      }
-+
-+      kfree(task->buf);
-+      return err;
-+}
-+
-+static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
-+              struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+      int i;
-+
-+      memset(&info->monspecs, 0, sizeof(info->monspecs));
-+
-+      /*
-+       * If we don't get all necessary data from the EDID block,
-+       * mark it as incompatible with the GTF and set nocrtc so
-+       * that we always use the default BIOS refresh rate.
-+       */
-+      if (uvesafb_vbe_getedid(task, info)) {
-+              info->monspecs.gtf = 0;
-+              par->nocrtc = 1;
-+      }
-+
-+      /* Kernel command line overrides. */
-+      if (maxclk)
-+              info->monspecs.dclkmax = maxclk * 1000000;
-+      if (maxvf)
-+              info->monspecs.vfmax = maxvf;
-+      if (maxhf)
-+              info->monspecs.hfmax = maxhf * 1000;
-+
-+      /*
-+       * In case DDC transfers are not supported, the user can provide
-+       * monitor limits manually. Lower limits are set to "safe" values.
-+       */
-+      if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) {
-+              info->monspecs.dclkmin = 0;
-+              info->monspecs.vfmin = 60;
-+              info->monspecs.hfmin = 29000;
-+              info->monspecs.gtf = 1;
-+              par->nocrtc = 0;
-+      }
-+
-+      if (info->monspecs.gtf)
-+              printk(KERN_INFO
-+                      "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, "
-+                      "clk = %d MHz\n", info->monspecs.vfmax,
-+                      (int)(info->monspecs.hfmax / 1000),
-+                      (int)(info->monspecs.dclkmax / 1000000));
-+      else
-+              printk(KERN_INFO "uvesafb: no monitor limits have been set, "
-+                               "default refresh rate will be used\n");
-+
-+      /* Add VBE modes to the modelist. */
-+      for (i = 0; i < par->vbe_modes_cnt; i++) {
-+              struct fb_var_screeninfo var;
-+              struct vbe_mode_ib *mode;
-+              struct fb_videomode vmode;
-+
-+              mode = &par->vbe_modes[i];
-+              memset(&var, 0, sizeof(var));
-+
-+              var.xres = mode->x_res;
-+              var.yres = mode->y_res;
-+
-+              fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info);
-+              fb_var_to_videomode(&vmode, &var);
-+              fb_add_videomode(&vmode, &info->modelist);
-+      }
-+
-+      /* Add valid VESA modes to our modelist. */
-+      for (i = 0; i < VESA_MODEDB_SIZE; i++) {
-+              if (uvesafb_is_valid_mode((struct fb_videomode *)
-+                                              &vesa_modes[i], info))
-+                      fb_add_videomode(&vesa_modes[i], &info->modelist);
-+      }
-+
-+      for (i = 0; i < info->monspecs.modedb_len; i++) {
-+              if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info))
-+                      fb_add_videomode(&info->monspecs.modedb[i],
-+                                      &info->modelist);
-+      }
-+
-+      return;
-+}
-+
-+static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
-+              struct uvesafb_par *par)
-+{
-+      int err;
-+
-+      uvesafb_reset(task);
-+
-+      /*
-+       * Get the VBE state buffer size. We want all available
-+       * hardware state data (CL = 0x0f).
-+       */
-+      task->t.regs.eax = 0x4f04;
-+      task->t.regs.ecx = 0x000f;
-+      task->t.regs.edx = 0x0000;
-+      task->t.flags = 0;
-+
-+      err = uvesafb_exec(task);
-+
-+      if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-+              printk(KERN_WARNING "uvesafb: VBE state buffer size "
-+                      "cannot be determined (eax=0x%x, err=%d)\n",
-+                      task->t.regs.eax, err);
-+              par->vbe_state_size = 0;
-+              return;
-+      }
-+
-+      par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff);
-+}
-+
-+static int __devinit uvesafb_vbe_init(struct fb_info *info)
-+{
-+      struct uvesafb_ktask *task = NULL;
-+      struct uvesafb_par *par = info->par;
-+      int err;
-+
-+      task = uvesafb_prep();
-+      if (!task)
-+              return -ENOMEM;
-+
-+      err = uvesafb_vbe_getinfo(task, par);
-+      if (err)
-+              goto out;
-+
-+      err = uvesafb_vbe_getmodes(task, par);
-+      if (err)
-+              goto out;
-+
-+      par->nocrtc = nocrtc;
-+#ifdef CONFIG_X86_32
-+      par->pmi_setpal = pmi_setpal;
-+      par->ypan = ypan;
-+
-+      if (par->pmi_setpal || par->ypan)
-+              uvesafb_vbe_getpmi(task, par);
-+#else
-+      /* The protected mode interface is not available on non-x86. */
-+      par->pmi_setpal = par->ypan = 0;
-+#endif
-+
-+      INIT_LIST_HEAD(&info->modelist);
-+      uvesafb_vbe_getmonspecs(task, info);
-+      uvesafb_vbe_getstatesize(task, par);
-+
-+out:  uvesafb_free(task);
-+      return err;
-+}
-+
-+static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
-+{
-+      struct list_head *pos;
-+      struct fb_modelist *modelist;
-+      struct fb_videomode *mode;
-+      struct uvesafb_par *par = info->par;
-+      int i, modeid;
-+
-+      /* Has the user requested a specific VESA mode? */
-+      if (vbemode) {
-+              for (i = 0; i < par->vbe_modes_cnt; i++) {
-+                      if (par->vbe_modes[i].mode_id == vbemode) {
-+                              fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-+                                                      &info->var, info);
-+                              /*
-+                               * With pixclock set to 0, the default BIOS
-+                               * timings will be used in set_par().
-+                               */
-+                              info->var.pixclock = 0;
-+                              modeid = i;
-+                              goto gotmode;
-+                      }
-+              }
-+              printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is "
-+                               "unavailable\n", vbemode);
-+              vbemode = 0;
-+      }
-+
-+      /* Count the modes in the modelist */
-+      i = 0;
-+      list_for_each(pos, &info->modelist)
-+              i++;
-+
-+      /*
-+       * Convert the modelist into a modedb so that we can use it with
-+       * fb_find_mode().
-+       */
-+      mode = kzalloc(i * sizeof(*mode), GFP_KERNEL);
-+      if (mode) {
-+              i = 0;
-+              list_for_each(pos, &info->modelist) {
-+                      modelist = list_entry(pos, struct fb_modelist, list);
-+                      mode[i] = modelist->mode;
-+                      i++;
-+              }
-+
-+              if (!mode_option)
-+                      mode_option = UVESAFB_DEFAULT_MODE;
-+
-+              i = fb_find_mode(&info->var, info, mode_option, mode, i,
-+                      NULL, 8);
-+
-+              kfree(mode);
-+      }
-+
-+      /* fb_find_mode() failed */
-+      if (i == 0 || i >= 3) {
-+              info->var.xres = 640;
-+              info->var.yres = 480;
-+              mode = (struct fb_videomode *)
-+                              fb_find_best_mode(&info->var, &info->modelist);
-+
-+              if (mode) {
-+                      fb_videomode_to_var(&info->var, mode);
-+              } else {
-+                      modeid = par->vbe_modes[0].mode_id;
-+                      fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-+                                  &info->var, info);
-+                      goto gotmode;
-+              }
-+      }
-+
-+      /* Look for a matching VBE mode. */
-+      modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres,
-+                      info->var.bits_per_pixel, UVESAFB_EXACT_RES);
-+
-+      if (modeid == -1)
-+              return -EINVAL;
-+
-+gotmode:
-+      uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]);
-+
-+      /*
-+       * If we are not VBE3.0+ compliant, we're done -- the BIOS will
-+       * ignore our timings anyway.
-+       */
-+      if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc)
-+              fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-+                                      &info->var, info);
-+
-+      return modeid;
-+}
-+
-+static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count,
-+              int start, struct fb_info *info)
-+{
-+      struct uvesafb_ktask *task;
-+      struct uvesafb_par *par = info->par;
-+      int i = par->mode_idx;
-+      int err = 0;
-+
-+      /*
-+       * We support palette modifications for 8 bpp modes only, so
-+       * there can never be more than 256 entries.
-+       */
-+      if (start + count > 256)
-+              return -EINVAL;
-+
-+      /* Use VGA registers if mode is VGA-compatible. */
-+      if (i >= 0 && i < par->vbe_modes_cnt &&
-+          par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) {
-+              for (i = 0; i < count; i++) {
-+                      outb_p(start + i,        dac_reg);
-+                      outb_p(entries[i].red,   dac_val);
-+                      outb_p(entries[i].green, dac_val);
-+                      outb_p(entries[i].blue,  dac_val);
-+              }
-+      }
-+#ifdef CONFIG_X86_32
-+      else if (par->pmi_setpal) {
-+              __asm__ __volatile__(
-+              "call *(%%esi)"
-+              : /* no return value */
-+              : "a" (0x4f09),         /* EAX */
-+                "b" (0),              /* EBX */
-+                "c" (count),          /* ECX */
-+                "d" (start),          /* EDX */
-+                "D" (entries),        /* EDI */
-+                "S" (&par->pmi_pal)); /* ESI */
-+      }
-+#endif
-+      else {
-+              task = uvesafb_prep();
-+              if (!task)
-+                      return -ENOMEM;
-+
-+              task->t.regs.eax = 0x4f09;
-+              task->t.regs.ebx = 0x0;
-+              task->t.regs.ecx = count;
-+              task->t.regs.edx = start;
-+              task->t.flags = TF_BUF_ESDI;
-+              task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count;
-+              task->buf = entries;
-+
-+              err = uvesafb_exec(task);
-+              if ((task->t.regs.eax & 0xffff) != 0x004f)
-+                      err = 1;
-+
-+              uvesafb_free(task);
-+      }
-+      return err;
-+}
-+
-+static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
-+              unsigned blue, unsigned transp,
-+              struct fb_info *info)
-+{
-+      struct uvesafb_pal_entry entry;
-+      int shift = 16 - info->var.green.length;
-+      int err = 0;
-+
-+      if (regno >= info->cmap.len)
-+              return -EINVAL;
-+
-+      if (info->var.bits_per_pixel == 8) {
-+              entry.red   = red   >> shift;
-+              entry.green = green >> shift;
-+              entry.blue  = blue  >> shift;
-+              entry.pad   = 0;
-+
-+              err = uvesafb_setpalette(&entry, 1, regno, info);
-+      } else if (regno < 16) {
-+              switch (info->var.bits_per_pixel) {
-+              case 16:
-+                      if (info->var.red.offset == 10) {
-+                              /* 1:5:5:5 */
-+                              ((u32 *) (info->pseudo_palette))[regno] =
-+                                              ((red   & 0xf800) >>  1) |
-+                                              ((green & 0xf800) >>  6) |
-+                                              ((blue  & 0xf800) >> 11);
-+                      } else {
-+                              /* 0:5:6:5 */
-+                              ((u32 *) (info->pseudo_palette))[regno] =
-+                                              ((red   & 0xf800)      ) |
-+                                              ((green & 0xfc00) >>  5) |
-+                                              ((blue  & 0xf800) >> 11);
-+                      }
-+                      break;
-+
-+              case 24:
-+              case 32:
-+                      red   >>= 8;
-+                      green >>= 8;
-+                      blue  >>= 8;
-+                      ((u32 *)(info->pseudo_palette))[regno] =
-+                              (red   << info->var.red.offset)   |
-+                              (green << info->var.green.offset) |
-+                              (blue  << info->var.blue.offset);
-+                      break;
-+              }
-+      }
-+      return err;
-+}
-+
-+static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
-+{
-+      struct uvesafb_pal_entry *entries;
-+      int shift = 16 - info->var.green.length;
-+      int i, err = 0;
-+
-+      if (info->var.bits_per_pixel == 8) {
-+              if (cmap->start + cmap->len > info->cmap.start +
-+                  info->cmap.len || cmap->start < info->cmap.start)
-+                      return -EINVAL;
-+
-+              entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL);
-+              if (!entries)
-+                      return -ENOMEM;
-+
-+              for (i = 0; i < cmap->len; i++) {
-+                      entries[i].red   = cmap->red[i]   >> shift;
-+                      entries[i].green = cmap->green[i] >> shift;
-+                      entries[i].blue  = cmap->blue[i]  >> shift;
-+                      entries[i].pad   = 0;
-+              }
-+              err = uvesafb_setpalette(entries, cmap->len, cmap->start, info);
-+              kfree(entries);
-+      } else {
-+              /*
-+               * For modes with bpp > 8, we only set the pseudo palette in
-+               * the fb_info struct. We rely on uvesafb_setcolreg to do all
-+               * sanity checking.
-+               */
-+              for (i = 0; i < cmap->len; i++) {
-+                      err |= uvesafb_setcolreg(cmap->start + i, cmap->red[i],
-+                                              cmap->green[i], cmap->blue[i],
-+                                              0, info);
-+              }
-+      }
-+      return err;
-+}
-+
-+static int uvesafb_pan_display(struct fb_var_screeninfo *var,
-+              struct fb_info *info)
-+{
-+#ifdef CONFIG_X86_32
-+      int offset;
-+      struct uvesafb_par *par = info->par;
-+
-+      offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
-+
-+      /*
-+       * It turns out it's not the best idea to do panning via vm86,
-+       * so we only allow it if we have a PMI.
-+       */
-+      if (par->pmi_start) {
-+              __asm__ __volatile__(
-+                      "call *(%%edi)"
-+                      : /* no return value */
-+                      : "a" (0x4f07),         /* EAX */
-+                        "b" (0),              /* EBX */
-+                        "c" (offset),         /* ECX */
-+                        "d" (offset >> 16),   /* EDX */
-+                        "D" (&par->pmi_start));    /* EDI */
-+      }
-+#endif
-+      return 0;
-+}
-+
-+static int uvesafb_blank(int blank, struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+      struct uvesafb_ktask *task;
-+      int err = 1;
-+
-+      if (par->vbe_ib.capabilities & VBE_CAP_VGACOMPAT) {
-+              int loop = 10000;
-+              u8 seq = 0, crtc17 = 0;
-+
-+              if (blank == FB_BLANK_POWERDOWN) {
-+                      seq = 0x20;
-+                      crtc17 = 0x00;
-+                      err = 0;
-+              } else {
-+                      seq = 0x00;
-+                      crtc17 = 0x80;
-+                      err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL;
-+              }
-+
-+              vga_wseq(NULL, 0x00, 0x01);
-+              seq |= vga_rseq(NULL, 0x01) & ~0x20;
-+              vga_wseq(NULL, 0x00, seq);
-+
-+              crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80;
-+              while (loop--);
-+              vga_wcrt(NULL, 0x17, crtc17);
-+              vga_wseq(NULL, 0x00, 0x03);
-+      } else {
-+              task = uvesafb_prep();
-+              if (!task)
-+                      return -ENOMEM;
-+
-+              task->t.regs.eax = 0x4f10;
-+              switch (blank) {
-+              case FB_BLANK_UNBLANK:
-+                      task->t.regs.ebx = 0x0001;
-+                      break;
-+              case FB_BLANK_NORMAL:
-+                      task->t.regs.ebx = 0x0101;      /* standby */
-+                      break;
-+              case FB_BLANK_POWERDOWN:
-+                      task->t.regs.ebx = 0x0401;      /* powerdown */
-+                      break;
-+              default:
-+                      goto out;
-+              }
-+
-+              err = uvesafb_exec(task);
-+              if (err || (task->t.regs.eax & 0xffff) != 0x004f)
-+                      err = 1;
-+out:          uvesafb_free(task);
-+      }
-+      return err;
-+}
-+
-+static int uvesafb_open(struct fb_info *info, int user)
-+{
-+      struct uvesafb_par *par = info->par;
-+      int cnt = atomic_read(&par->ref_count);
-+
-+      if (!cnt && par->vbe_state_size)
-+              par->vbe_state_orig = uvesafb_vbe_state_save(par);
-+
-+      atomic_inc(&par->ref_count);
-+      return 0;
-+}
-+
-+static int uvesafb_release(struct fb_info *info, int user)
-+{
-+      struct uvesafb_ktask *task = NULL;
-+      struct uvesafb_par *par = info->par;
-+      int cnt = atomic_read(&par->ref_count);
-+
-+      if (!cnt)
-+              return -EINVAL;
-+
-+      if (cnt != 1)
-+              goto out;
-+
-+      task = uvesafb_prep();
-+      if (!task)
-+              goto out;
-+
-+      /* First, try to set the standard 80x25 text mode. */
-+      task->t.regs.eax = 0x0003;
-+      uvesafb_exec(task);
-+
-+      /*
-+       * Now try to restore whatever hardware state we might have
-+       * saved when the fb device was first opened.
-+       */
-+      uvesafb_vbe_state_restore(par, par->vbe_state_orig);
-+out:
-+      atomic_dec(&par->ref_count);
-+      if (task)
-+              uvesafb_free(task);
-+      return 0;
-+}
-+
-+static int uvesafb_set_par(struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+      struct uvesafb_ktask *task = NULL;
-+      struct vbe_crtc_ib *crtc = NULL;
-+      struct vbe_mode_ib *mode = NULL;
-+      int i, err = 0, depth = info->var.bits_per_pixel;
-+
-+      if (depth > 8 && depth != 32)
-+              depth = info->var.red.length + info->var.green.length +
-+                      info->var.blue.length;
-+
-+      i = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, depth,
-+                               UVESAFB_EXACT_RES | UVESAFB_EXACT_DEPTH);
-+      if (i >= 0)
-+              mode = &par->vbe_modes[i];
-+      else
-+              return -EINVAL;
-+
-+      task = uvesafb_prep();
-+      if (!task)
-+              return -ENOMEM;
-+setmode:
-+      task->t.regs.eax = 0x4f02;
-+      task->t.regs.ebx = mode->mode_id | 0x4000;      /* use LFB */
-+
-+      if (par->vbe_ib.vbe_version >= 0x0300 && !par->nocrtc &&
-+          info->var.pixclock != 0) {
-+              task->t.regs.ebx |= 0x0800;             /* use CRTC data */
-+              task->t.flags = TF_BUF_ESDI;
-+              crtc = kzalloc(sizeof(struct vbe_crtc_ib), GFP_KERNEL);
-+              if (!crtc) {
-+                      err = -ENOMEM;
-+                      goto out;
-+              }
-+              crtc->horiz_start = info->var.xres + info->var.right_margin;
-+              crtc->horiz_end   = crtc->horiz_start + info->var.hsync_len;
-+              crtc->horiz_total = crtc->horiz_end + info->var.left_margin;
-+
-+              crtc->vert_start  = info->var.yres + info->var.lower_margin;
-+              crtc->vert_end    = crtc->vert_start + info->var.vsync_len;
-+              crtc->vert_total  = crtc->vert_end + info->var.upper_margin;
-+
-+              crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000;
-+              crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock /
-+                              (crtc->vert_total * crtc->horiz_total)));
-+
-+              if (info->var.vmode & FB_VMODE_DOUBLE)
-+                      crtc->flags |= 0x1;
-+              if (info->var.vmode & FB_VMODE_INTERLACED)
-+                      crtc->flags |= 0x2;
-+              if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+                      crtc->flags |= 0x4;
-+              if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+                      crtc->flags |= 0x8;
-+              memcpy(&par->crtc, crtc, sizeof(*crtc));
-+      } else {
-+              memset(&par->crtc, 0, sizeof(*crtc));
-+      }
-+
-+      task->t.buf_len = sizeof(struct vbe_crtc_ib);
-+      task->buf = &par->crtc;
-+
-+      err = uvesafb_exec(task);
-+      if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
-+              /*
-+               * The mode switch might have failed because we tried to
-+               * use our own timings.  Try again with the default timings.
-+               */
-+              if (crtc != NULL) {
-+                      printk(KERN_WARNING "uvesafb: mode switch failed "
-+                              "(eax=0x%x, err=%d). Trying again with "
-+                              "default timings.\n", task->t.regs.eax, err);
-+                      uvesafb_reset(task);
-+                      kfree(crtc);
-+                      crtc = NULL;
-+                      info->var.pixclock = 0;
-+                      goto setmode;
-+              } else {
-+                      printk(KERN_ERR "uvesafb: mode switch failed (eax="
-+                              "0x%x, err=%d)\n", task->t.regs.eax, err);
-+                      err = -EINVAL;
-+                      goto out;
-+              }
-+      }
-+      par->mode_idx = i;
-+
-+      /* For 8bpp modes, always try to set the DAC to 8 bits. */
-+      if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC &&
-+          mode->bits_per_pixel <= 8) {
-+              uvesafb_reset(task);
-+              task->t.regs.eax = 0x4f08;
-+              task->t.regs.ebx = 0x0800;
-+
-+              err = uvesafb_exec(task);
-+              if (err || (task->t.regs.eax & 0xffff) != 0x004f ||
-+                  ((task->t.regs.ebx & 0xff00) >> 8) != 8) {
-+                      /*
-+                       * We've failed to set the DAC palette format -
-+                       * time to correct var.
-+                       */
-+                      info->var.red.length    = 6;
-+                      info->var.green.length  = 6;
-+                      info->var.blue.length   = 6;
-+              }
-+      }
-+
-+      info->fix.visual = (info->var.bits_per_pixel == 8) ?
-+                              FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-+      info->fix.line_length = mode->bytes_per_scan_line;
-+
-+out:  if (crtc != NULL)
-+              kfree(crtc);
-+      uvesafb_free(task);
-+
-+      return err;
-+}
-+
-+static void uvesafb_check_limits(struct fb_var_screeninfo *var,
-+              struct fb_info *info)
-+{
-+      const struct fb_videomode *mode;
-+      struct uvesafb_par *par = info->par;
-+
-+      /*
-+       * If pixclock is set to 0, then we're using default BIOS timings
-+       * and thus don't have to perform any checks here.
-+       */
-+      if (!var->pixclock)
-+              return;
-+
-+      if (par->vbe_ib.vbe_version < 0x0300) {
-+              fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info);
-+              return;
-+      }
-+
-+      if (!fb_validate_mode(var, info))
-+              return;
-+
-+      mode = fb_find_best_mode(var, &info->modelist);
-+      if (mode) {
-+              if (mode->xres == var->xres && mode->yres == var->yres &&
-+                  !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) {
-+                      fb_videomode_to_var(var, mode);
-+                      return;
-+              }
-+      }
-+
-+      if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
-+              return;
-+      /* Use default refresh rate */
-+      var->pixclock = 0;
-+}
-+
-+static int uvesafb_check_var(struct fb_var_screeninfo *var,
-+              struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+      struct vbe_mode_ib *mode = NULL;
-+      int match = -1;
-+      int depth = var->red.length + var->green.length + var->blue.length;
-+
-+      /*
-+       * Various apps will use bits_per_pixel to set the color depth,
-+       * which is theoretically incorrect, but which we'll try to handle
-+       * here.
-+       */
-+      if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8)
-+              depth = var->bits_per_pixel;
-+
-+      match = uvesafb_vbe_find_mode(par, var->xres, var->yres, depth,
-+                                              UVESAFB_EXACT_RES);
-+      if (match == -1)
-+              return -EINVAL;
-+
-+      mode = &par->vbe_modes[match];
-+      uvesafb_setup_var(var, info, mode);
-+
-+      /*
-+       * Check whether we have remapped enough memory for this mode.
-+       * We might be called at an early stage, when we haven't remapped
-+       * any memory yet, in which case we simply skip the check.
-+       */
-+      if (var->yres * mode->bytes_per_scan_line > info->fix.smem_len
-+                                              && info->fix.smem_len)
-+              return -EINVAL;
-+
-+      if ((var->vmode & FB_VMODE_DOUBLE) &&
-+                              !(par->vbe_modes[match].mode_attr & 0x100))
-+              var->vmode &= ~FB_VMODE_DOUBLE;
-+
-+      if ((var->vmode & FB_VMODE_INTERLACED) &&
-+                              !(par->vbe_modes[match].mode_attr & 0x200))
-+              var->vmode &= ~FB_VMODE_INTERLACED;
-+
-+      uvesafb_check_limits(var, info);
-+
-+      var->xres_virtual = var->xres;
-+      var->yres_virtual = (par->ypan) ?
-+                              info->fix.smem_len / mode->bytes_per_scan_line :
-+                              var->yres;
-+      return 0;
-+}
-+
-+static void uvesafb_save_state(struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+
-+      if (par->vbe_state_saved)
-+              kfree(par->vbe_state_saved);
-+
-+      par->vbe_state_saved = uvesafb_vbe_state_save(par);
-+}
-+
-+static void uvesafb_restore_state(struct fb_info *info)
-+{
-+      struct uvesafb_par *par = info->par;
-+
-+      uvesafb_vbe_state_restore(par, par->vbe_state_saved);
-+}
-+
-+static struct fb_ops uvesafb_ops = {
-+      .owner          = THIS_MODULE,
-+      .fb_open        = uvesafb_open,
-+      .fb_release     = uvesafb_release,
-+      .fb_setcolreg   = uvesafb_setcolreg,
-+      .fb_setcmap     = uvesafb_setcmap,
-+      .fb_pan_display = uvesafb_pan_display,
-+      .fb_blank       = uvesafb_blank,
-+      .fb_fillrect    = cfb_fillrect,
-+      .fb_copyarea    = cfb_copyarea,
-+      .fb_imageblit   = cfb_imageblit,
-+      .fb_check_var   = uvesafb_check_var,
-+      .fb_set_par     = uvesafb_set_par,
-+      .fb_save_state  = uvesafb_save_state,
-+      .fb_restore_state = uvesafb_restore_state,
-+};
-+
-+static void __devinit uvesafb_init_info(struct fb_info *info,
-+              struct vbe_mode_ib *mode)
-+{
-+      unsigned int size_vmode;
-+      unsigned int size_remap;
-+      unsigned int size_total;
-+      struct uvesafb_par *par = info->par;
-+      int i, h;
-+
-+      info->pseudo_palette = ((u8 *)info->par + sizeof(struct uvesafb_par));
-+      info->fix = uvesafb_fix;
-+      info->fix.ypanstep = par->ypan ? 1 : 0;
-+      info->fix.ywrapstep = (par->ypan > 1) ? 1 : 0;
-+
-+      /*
-+       * If we were unable to get the state buffer size, disable
-+       * functions for saving and restoring the hardware state.
-+       */
-+      if (par->vbe_state_size == 0) {
-+              info->fbops->fb_save_state = NULL;
-+              info->fbops->fb_restore_state = NULL;
-+      }
-+
-+      /* Disable blanking if the user requested so. */
-+      if (!blank)
-+              info->fbops->fb_blank = NULL;
-+
-+      /*
-+       * Find out how much IO memory is required for the mode with
-+       * the highest resolution.
-+       */
-+      size_remap = 0;
-+      for (i = 0; i < par->vbe_modes_cnt; i++) {
-+              h = par->vbe_modes[i].bytes_per_scan_line *
-+                                      par->vbe_modes[i].y_res;
-+              if (h > size_remap)
-+                      size_remap = h;
-+      }
-+      size_remap *= 2;
-+
-+      /*
-+       *   size_vmode -- that is the amount of memory needed for the
-+       *                 used video mode, i.e. the minimum amount of
-+       *                 memory we need.
-+       */
-+      if (mode != NULL) {
-+              size_vmode = info->var.yres * mode->bytes_per_scan_line;
-+      } else {
-+              size_vmode = info->var.yres * info->var.xres *
-+                           ((info->var.bits_per_pixel + 7) >> 3);
-+      }
-+
-+      /*
-+       *   size_total -- all video memory we have. Used for mtrr
-+       *                 entries, resource allocation and bounds
-+       *                 checking.
-+       */
-+      size_total = par->vbe_ib.total_memory * 65536;
-+      if (vram_total)
-+              size_total = vram_total * 1024 * 1024;
-+      if (size_total < size_vmode)
-+              size_total = size_vmode;
-+
-+      /*
-+       *   size_remap -- the amount of video memory we are going to
-+       *                 use for vesafb.  With modern cards it is no
-+       *                 option to simply use size_total as th
-+       *                 wastes plenty of kernel address space.
-+       */
-+      if (vram_remap)
-+              size_remap = vram_remap * 1024 * 1024;
-+      if (size_remap < size_vmode)
-+              size_remap = size_vmode;
-+      if (size_remap > size_total)
-+              size_remap = size_total;
-+
-+      info->fix.smem_len = size_remap;
-+      info->fix.smem_start = mode->phys_base_ptr;
-+
-+      /*
-+       * We have to set yres_virtual here because when setup_var() was
-+       * called, smem_len wasn't defined yet.
-+       */
-+      info->var.yres_virtual = info->fix.smem_len /
-+                               mode->bytes_per_scan_line;
-+
-+      if (par->ypan && info->var.yres_virtual > info->var.yres) {
-+              printk(KERN_INFO "uvesafb: scrolling: %s "
-+                      "using protected mode interface, "
-+                      "yres_virtual=%d\n",
-+                      (par->ypan > 1) ? "ywrap" : "ypan",
-+                      info->var.yres_virtual);
-+      } else {
-+              printk(KERN_INFO "uvesafb: scrolling: redraw\n");
-+              info->var.yres_virtual = info->var.yres;
-+              par->ypan = 0;
-+      }
-+
-+      info->flags = FBINFO_FLAG_DEFAULT |
-+                      (par->ypan) ? FBINFO_HWACCEL_YPAN : 0;
-+
-+      if (!par->ypan)
-+              info->fbops->fb_pan_display = NULL;
-+}
-+
-+static void uvesafb_init_mtrr(struct fb_info *info)
-+{
-+#ifdef CONFIG_MTRR
-+      if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) {
-+              int temp_size = info->fix.smem_len;
-+              unsigned int type = 0;
-+
-+              switch (mtrr) {
-+              case 1:
-+                      type = MTRR_TYPE_UNCACHABLE;
-+                      break;
-+              case 2:
-+                      type = MTRR_TYPE_WRBACK;
-+                      break;
-+              case 3:
-+                      type = MTRR_TYPE_WRCOMB;
-+                      break;
-+              case 4:
-+                      type = MTRR_TYPE_WRTHROUGH;
-+                      break;
-+              default:
-+                      type = 0;
-+                      break;
-+              }
-+
-+              if (type) {
-+                      int rc;
-+
-+                      /* Find the largest power-of-two */
-+                      while (temp_size & (temp_size - 1))
-+                              temp_size &= (temp_size - 1);
-+
-+                      /* Try and find a power of two to add */
-+                      do {
-+                              rc = mtrr_add(info->fix.smem_start,
-+                                            temp_size, type, 1);
-+                              temp_size >>= 1;
-+                      } while (temp_size >= PAGE_SIZE && rc == -EINVAL);
-+              }
-+      }
-+#endif /* CONFIG_MTRR */
-+}
-+
-+
-+static ssize_t uvesafb_show_vbe_ver(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version);
-+}
-+
-+static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL);
-+
-+static ssize_t uvesafb_show_vbe_modes(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+      int ret = 0, i;
-+
-+      for (i = 0; i < par->vbe_modes_cnt && ret < PAGE_SIZE; i++) {
-+              ret += snprintf(buf + ret, PAGE_SIZE - ret,
-+                      "%dx%d-%d, 0x%.4x\n",
-+                      par->vbe_modes[i].x_res, par->vbe_modes[i].y_res,
-+                      par->vbe_modes[i].depth, par->vbe_modes[i].mode_id);
-+      }
-+
-+      return ret;
-+}
-+
-+static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL);
-+
-+static ssize_t uvesafb_show_vendor(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      if (par->vbe_ib.oem_vendor_name_ptr)
-+              return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
-+                      (&par->vbe_ib) + par->vbe_ib.oem_vendor_name_ptr);
-+      else
-+              return 0;
-+}
-+
-+static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL);
-+
-+static ssize_t uvesafb_show_product_name(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      if (par->vbe_ib.oem_product_name_ptr)
-+              return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
-+                      (&par->vbe_ib) + par->vbe_ib.oem_product_name_ptr);
-+      else
-+              return 0;
-+}
-+
-+static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL);
-+
-+static ssize_t uvesafb_show_product_rev(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      if (par->vbe_ib.oem_product_rev_ptr)
-+              return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
-+                      (&par->vbe_ib) + par->vbe_ib.oem_product_rev_ptr);
-+      else
-+              return 0;
-+}
-+
-+static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL);
-+
-+static ssize_t uvesafb_show_oem_string(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      if (par->vbe_ib.oem_string_ptr)
-+              return snprintf(buf, PAGE_SIZE, "%s\n",
-+                      (char *)(&par->vbe_ib) + par->vbe_ib.oem_string_ptr);
-+      else
-+              return 0;
-+}
-+
-+static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL);
-+
-+static ssize_t uvesafb_show_nocrtc(struct device *dev,
-+              struct device_attribute *attr, char *buf)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc);
-+}
-+
-+static ssize_t uvesafb_store_nocrtc(struct device *dev,
-+              struct device_attribute *attr, const char *buf, size_t count)
-+{
-+      struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
-+      struct uvesafb_par *par = info->par;
-+
-+      if (count > 0) {
-+              if (buf[0] == '0')
-+                      par->nocrtc = 0;
-+              else
-+                      par->nocrtc = 1;
-+      }
-+      return count;
-+}
-+
-+static DEVICE_ATTR(nocrtc, S_IRUGO | S_IWUSR, uvesafb_show_nocrtc,
-+                      uvesafb_store_nocrtc);
-+
-+static struct attribute *uvesafb_dev_attrs[] = {
-+      &dev_attr_vbe_version.attr,
-+      &dev_attr_vbe_modes.attr,
-+      &dev_attr_oem_vendor.attr,
-+      &dev_attr_oem_product_name.attr,
-+      &dev_attr_oem_product_rev.attr,
-+      &dev_attr_oem_string.attr,
-+      &dev_attr_nocrtc.attr,
-+      NULL,
-+};
-+
-+static struct attribute_group uvesafb_dev_attgrp = {
-+      .name = NULL,
-+      .attrs = uvesafb_dev_attrs,
-+};
-+
-+static int __devinit uvesafb_probe(struct platform_device *dev)
-+{
-+      struct fb_info *info;
-+      struct vbe_mode_ib *mode = NULL;
-+      struct uvesafb_par *par;
-+      int err = 0, i;
-+
-+      info = framebuffer_alloc(sizeof(*par) + sizeof(u32) * 256, &dev->dev);
-+      if (!info)
-+              return -ENOMEM;
-+
-+      par = info->par;
-+
-+      err = uvesafb_vbe_init(info);
-+      if (err) {
-+              printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err);
-+              goto out;
-+      }
-+
-+      info->fbops = &uvesafb_ops;
-+
-+      i = uvesafb_vbe_init_mode(info);
-+      if (i < 0) {
-+              err = -EINVAL;
-+              goto out;
-+      } else {
-+              mode = &par->vbe_modes[i];
-+      }
-+
-+      if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
-+              err = -ENXIO;
-+              goto out;
-+      }
-+
-+      uvesafb_init_info(info, mode);
-+
-+      if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
-+                              "uvesafb")) {
-+              printk(KERN_ERR "uvesafb: cannot reserve video memory at "
-+                              "0x%lx\n", info->fix.smem_start);
-+              err = -EIO;
-+              goto out_mode;
-+      }
-+
-+      info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
-+
-+      if (!info->screen_base) {
-+              printk(KERN_ERR
-+                      "uvesafb: abort, cannot ioremap 0x%x bytes of video "
-+                      "memory at 0x%lx\n",
-+                      info->fix.smem_len, info->fix.smem_start);
-+              err = -EIO;
-+              goto out_mem;
-+      }
-+
-+      if (!request_region(0x3c0, 32, "uvesafb")) {
-+              printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
-+              err = -EIO;
-+              goto out_unmap;
-+      }
-+
-+      uvesafb_init_mtrr(info);
-+      platform_set_drvdata(dev, info);
-+
-+      if (register_framebuffer(info) < 0) {
-+              printk(KERN_ERR
-+                      "uvesafb: failed to register framebuffer device\n");
-+              err = -EINVAL;
-+              goto out_reg;
-+      }
-+
-+      printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
-+                      "using %dk, total %dk\n", info->fix.smem_start,
-+                      info->screen_base, info->fix.smem_len/1024,
-+                      par->vbe_ib.total_memory * 64);
-+      printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
-+                      info->fix.id);
-+
-+      err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
-+      if (err != 0)
-+              printk(KERN_WARNING "fb%d: failed to register attributes\n",
-+                      info->node);
-+
-+      return 0;
-+
-+out_reg:
-+      release_region(0x3c0, 32);
-+out_unmap:
-+      iounmap(info->screen_base);
-+out_mem:
-+      release_mem_region(info->fix.smem_start, info->fix.smem_len);
-+out_mode:
-+      if (!list_empty(&info->modelist))
-+              fb_destroy_modelist(&info->modelist);
-+      fb_destroy_modedb(info->monspecs.modedb);
-+      fb_dealloc_cmap(&info->cmap);
-+out:
-+      if (par->vbe_modes)
-+              kfree(par->vbe_modes);
-+
-+      framebuffer_release(info);
-+      return err;
-+}
-+
-+static int uvesafb_remove(struct platform_device *dev)
-+{
-+      struct fb_info *info = platform_get_drvdata(dev);
-+
-+      if (info) {
-+              struct uvesafb_par *par = info->par;
-+
-+              sysfs_remove_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
-+              unregister_framebuffer(info);
-+              release_region(0x3c0, 32);
-+              iounmap(info->screen_base);
-+              release_mem_region(info->fix.smem_start, info->fix.smem_len);
-+              fb_destroy_modedb(info->monspecs.modedb);
-+              fb_dealloc_cmap(&info->cmap);
-+
-+              if (par) {
-+                      if (par->vbe_modes)
-+                              kfree(par->vbe_modes);
-+                      if (par->vbe_state_orig)
-+                              kfree(par->vbe_state_orig);
-+                      if (par->vbe_state_saved)
-+                              kfree(par->vbe_state_saved);
-+              }
-+
-+              framebuffer_release(info);
-+      }
-+      return 0;
-+}
-+
-+static struct platform_driver uvesafb_driver = {
-+      .probe  = uvesafb_probe,
-+      .remove = uvesafb_remove,
-+      .driver = {
-+              .name = "uvesafb",
-+      },
-+};
-+
-+static struct platform_device *uvesafb_device;
-+
-+#ifndef MODULE
-+static int __devinit uvesafb_setup(char *options)
-+{
-+      char *this_opt;
-+
-+      if (!options || !*options)
-+              return 0;
-+
-+      while ((this_opt = strsep(&options, ",")) != NULL) {
-+              if (!*this_opt) continue;
-+
-+              if (!strcmp(this_opt, "redraw"))
-+                      ypan = 0;
-+              else if (!strcmp(this_opt, "ypan"))
-+                      ypan = 1;
-+              else if (!strcmp(this_opt, "ywrap"))
-+                      ypan = 2;
-+              else if (!strcmp(this_opt, "vgapal"))
-+                      pmi_setpal = 0;
-+              else if (!strcmp(this_opt, "pmipal"))
-+                      pmi_setpal = 1;
-+              else if (!strncmp(this_opt, "mtrr:", 5))
-+                      mtrr = simple_strtoul(this_opt+5, NULL, 0);
-+              else if (!strcmp(this_opt, "nomtrr"))
-+                      mtrr = 0;
-+              else if (!strcmp(this_opt, "nocrtc"))
-+                      nocrtc = 1;
-+              else if (!strcmp(this_opt, "noedid"))
-+                      noedid = 1;
-+              else if (!strcmp(this_opt, "noblank"))
-+                      blank = 0;
-+              else if (!strncmp(this_opt, "vtotal:", 7))
-+                      vram_total = simple_strtoul(this_opt + 7, NULL, 0);
-+              else if (!strncmp(this_opt, "vremap:", 7))
-+                      vram_remap = simple_strtoul(this_opt + 7, NULL, 0);
-+              else if (!strncmp(this_opt, "maxhf:", 6))
-+                      maxhf = simple_strtoul(this_opt + 6, NULL, 0);
-+              else if (!strncmp(this_opt, "maxvf:", 6))
-+                      maxvf = simple_strtoul(this_opt + 6, NULL, 0);
-+              else if (!strncmp(this_opt, "maxclk:", 7))
-+                      maxclk = simple_strtoul(this_opt + 7, NULL, 0);
-+              else if (!strncmp(this_opt, "vbemode:", 8))
-+                      vbemode = simple_strtoul(this_opt + 8, NULL, 0);
-+              else if (this_opt[0] >= '0' && this_opt[0] <= '9') {
-+                      mode_option = this_opt;
-+              } else {
-+                      printk(KERN_WARNING
-+                              "uvesafb: unrecognized option %s\n", this_opt);
-+              }
-+      }
-+
-+      return 0;
-+}
-+#endif /* !MODULE */
-+
-+static ssize_t show_v86d(struct device_driver *dev, char *buf)
-+{
-+      return snprintf(buf, PAGE_SIZE, "%s\n", v86d_path);
-+}
-+
-+static ssize_t store_v86d(struct device_driver *dev, const char *buf,
-+              size_t count)
-+{
-+      strncpy(v86d_path, buf, PATH_MAX);
-+      return count;
-+}
-+
-+static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d);
-+
-+static int __devinit uvesafb_init(void)
-+{
-+      int err;
-+
-+#ifndef MODULE
-+      char *option = NULL;
-+
-+      if (fb_get_options("uvesafb", &option))
-+              return -ENODEV;
-+      uvesafb_setup(option);
-+#endif
-+      err = cn_add_callback(&uvesafb_cn_id, "uvesafb", uvesafb_cn_callback);
-+      if (err)
-+              return err;
-+
-+      err = platform_driver_register(&uvesafb_driver);
-+
-+      if (!err) {
-+              uvesafb_device = platform_device_alloc("uvesafb", 0);
-+              if (uvesafb_device)
-+                      err = platform_device_add(uvesafb_device);
-+              else
-+                      err = -ENOMEM;
-+
-+              if (err) {
-+                      platform_device_put(uvesafb_device);
-+                      platform_driver_unregister(&uvesafb_driver);
-+                      cn_del_callback(&uvesafb_cn_id);
-+                      return err;
-+              }
-+
-+              err = driver_create_file(&uvesafb_driver.driver,
-+                              &driver_attr_v86d);
-+              if (err) {
-+                      printk(KERN_WARNING "uvesafb: failed to register "
-+                                      "attributes\n");
-+                      err = 0;
-+              }
-+      }
-+      return err;
-+}
-+
-+module_init(uvesafb_init);
-+
-+static void __devexit uvesafb_exit(void)
-+{
-+      struct uvesafb_ktask *task;
-+
-+      if (v86d_started) {
-+              task = uvesafb_prep();
-+              if (task) {
-+                      task->t.flags = TF_EXIT;
-+                      uvesafb_exec(task);
-+                      uvesafb_free(task);
-+              }
-+      }
-+
-+      cn_del_callback(&uvesafb_cn_id);
-+      driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d);
-+      platform_device_unregister(uvesafb_device);
-+      platform_driver_unregister(&uvesafb_driver);
-+}
-+
-+module_exit(uvesafb_exit);
-+
-+static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
-+{
-+      return 0;
-+}
-+
-+static inline int param_set_scroll(const char *val, struct kernel_param *kp)
-+{
-+      ypan = 0;
-+
-+      if (!strcmp(val, "redraw"))
-+              ypan = 0;
-+      else if (!strcmp(val, "ypan"))
-+              ypan = 1;
-+      else if (!strcmp(val, "ywrap"))
-+              ypan = 2;
-+
-+      return 0;
-+}
-+
-+#define param_check_scroll(name, p) __param_check(name, p, void);
-+
-+module_param_named(scroll, ypan, scroll, 0);
-+MODULE_PARM_DESC(scroll,
-+      "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
-+module_param_named(vgapal, pmi_setpal, invbool, 0);
-+MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
-+module_param_named(pmipal, pmi_setpal, bool, 0);
-+MODULE_PARM_DESC(pmipal, "Set palette using PMI calls");
-+module_param(mtrr, uint, 0);
-+MODULE_PARM_DESC(mtrr,
-+      "Memory Type Range Registers setting. Use 0 to disable.");
-+module_param(blank, bool, 0);
-+MODULE_PARM_DESC(blank, "Enable hardware blanking");
-+module_param(nocrtc, bool, 0);
-+MODULE_PARM_DESC(nocrtc, "Ignore CRTC timings when setting modes");
-+module_param(noedid, bool, 0);
-+MODULE_PARM_DESC(noedid,
-+      "Ignore EDID-provided monitor limits when setting modes");
-+module_param(vram_remap, uint, 0);
-+MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]");
-+module_param(vram_total, uint, 0);
-+MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]");
-+module_param(maxclk, ushort, 0);
-+MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data");
-+module_param(maxhf, ushort, 0);
-+MODULE_PARM_DESC(maxhf,
-+      "Maximum horizontal frequency [kHz], overrides EDID data");
-+module_param(maxvf, ushort, 0);
-+MODULE_PARM_DESC(maxvf,
-+      "Maximum vertical frequency [Hz], overrides EDID data");
-+module_param_named(mode, mode_option, charp, 0);
-+MODULE_PARM_DESC(mode,
-+      "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
-+module_param(vbemode, ushort, 0);
-+MODULE_PARM_DESC(vbemode,
-+      "VBE mode number to set, overrides the 'mode' option");
-+module_param_string(v86d, v86d_path, PATH_MAX, 0660);
-+MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper.");
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>");
-+MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards");
-+
-Index: linux-2.6.22/include/linux/connector.h
-===================================================================
---- linux-2.6.22.orig/include/linux/connector.h        2007-08-28 21:54:13.000000000 +0100
-+++ linux-2.6.22/include/linux/connector.h     2007-08-28 21:56:34.000000000 +0100
-@@ -36,14 +36,15 @@
- #define CN_VAL_CIFS                     0x1
- #define CN_W1_IDX                     0x3     /* w1 communication */
- #define CN_W1_VAL                     0x1
-+#define CN_IDX_V86D                   0x4
-+#define CN_VAL_V86D_UVESAFB           0x1
--
--#define CN_NETLINK_USERS              4
-+#define CN_NETLINK_USERS              5
- /*
-  * Maximum connector's message size.
-  */
--#define CONNECTOR_MAX_MSG_SIZE        1024
-+#define CONNECTOR_MAX_MSG_SIZE        16384
- /*
-  * idx and val are unique identifiers which 
-Index: linux-2.6.22/include/video/Kbuild
-===================================================================
---- linux-2.6.22.orig/include/video/Kbuild     2007-08-28 21:54:13.000000000 +0100
-+++ linux-2.6.22/include/video/Kbuild  2007-08-28 21:56:34.000000000 +0100
-@@ -1 +1 @@
--unifdef-y += sisfb.h
-+unifdef-y += sisfb.h uvesafb.h
-Index: linux-2.6.22/include/video/uvesafb.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/include/video/uvesafb.h       2007-08-28 21:56:34.000000000 +0100
-@@ -0,0 +1,193 @@
-+#ifndef _UVESAFB_H
-+#define _UVESAFB_H
-+
-+struct v86_regs {
-+      __u32 ebx;
-+      __u32 ecx;
-+      __u32 edx;
-+      __u32 esi;
-+      __u32 edi;
-+      __u32 ebp;
-+      __u32 eax;
-+      __u32 eip;
-+      __u32 eflags;
-+      __u32 esp;
-+      __u16 cs;
-+      __u16 ss;
-+      __u16 es;
-+      __u16 ds;
-+      __u16 fs;
-+      __u16 gs;
-+};
-+
-+/* Task flags */
-+#define TF_VBEIB      0x01
-+#define TF_BUF_ESDI   0x02
-+#define TF_BUF_ESBX   0x04
-+#define TF_BUF_RET    0x08
-+#define TF_EXIT               0x10
-+
-+struct uvesafb_task {
-+      __u8 flags;
-+      int buf_len;
-+      struct v86_regs regs;
-+};
-+
-+/* Constants for the capabilities field
-+ * in vbe_ib */
-+#define VBE_CAP_CAN_SWITCH_DAC        0x01
-+#define VBE_CAP_VGACOMPAT     0x02
-+
-+/* The VBE Info Block */
-+struct vbe_ib {
-+      char  vbe_signature[4];
-+      __u16 vbe_version;
-+      __u32 oem_string_ptr;
-+      __u32 capabilities;
-+      __u32 mode_list_ptr;
-+      __u16 total_memory;
-+      __u16 oem_software_rev;
-+      __u32 oem_vendor_name_ptr;
-+      __u32 oem_product_name_ptr;
-+      __u32 oem_product_rev_ptr;
-+      __u8  reserved[222];
-+      char  oem_data[256];
-+      char  misc_data[512];
-+} __attribute__ ((packed));
-+
-+#ifdef __KERNEL__
-+
-+/* VBE CRTC Info Block */
-+struct vbe_crtc_ib {
-+      u16 horiz_total;
-+      u16 horiz_start;
-+      u16 horiz_end;
-+      u16 vert_total;
-+      u16 vert_start;
-+      u16 vert_end;
-+      u8  flags;
-+      u32 pixel_clock;
-+      u16 refresh_rate;
-+      u8  reserved[40];
-+} __attribute__ ((packed));
-+
-+#define VBE_MODE_VGACOMPAT    0x20
-+#define VBE_MODE_COLOR                0x08
-+#define VBE_MODE_SUPPORTEDHW  0x01
-+#define VBE_MODE_GRAPHICS     0x10
-+#define VBE_MODE_LFB          0x80
-+
-+#define VBE_MODE_MASK         (VBE_MODE_COLOR | VBE_MODE_SUPPORTEDHW | \
-+                              VBE_MODE_GRAPHICS | VBE_MODE_LFB)
-+
-+/* VBE Mode Info Block */
-+struct vbe_mode_ib {
-+      /* for all VBE revisions */
-+      u16 mode_attr;
-+      u8  winA_attr;
-+      u8  winB_attr;
-+      u16 win_granularity;
-+      u16 win_size;
-+      u16 winA_seg;
-+      u16 winB_seg;
-+      u32 win_func_ptr;
-+      u16 bytes_per_scan_line;
-+
-+      /* for VBE 1.2+ */
-+      u16 x_res;
-+      u16 y_res;
-+      u8  x_char_size;
-+      u8  y_char_size;
-+      u8  planes;
-+      u8  bits_per_pixel;
-+      u8  banks;
-+      u8  memory_model;
-+      u8  bank_size;
-+      u8  image_pages;
-+      u8  reserved1;
-+
-+      /* Direct color fields for direct/6 and YUV/7 memory models. */
-+      /* Offsets are bit positions of lsb in the mask. */
-+      u8  red_len;
-+      u8  red_off;
-+      u8  green_len;
-+      u8  green_off;
-+      u8  blue_len;
-+      u8  blue_off;
-+      u8  rsvd_len;
-+      u8  rsvd_off;
-+      u8  direct_color_info;  /* direct color mode attributes */
-+
-+      /* for VBE 2.0+ */
-+      u32 phys_base_ptr;
-+      u8  reserved2[6];
-+
-+      /* for VBE 3.0+ */
-+      u16 lin_bytes_per_scan_line;
-+      u8  bnk_image_pages;
-+      u8  lin_image_pages;
-+      u8  lin_red_len;
-+      u8  lin_red_off;
-+      u8  lin_green_len;
-+      u8  lin_green_off;
-+      u8  lin_blue_len;
-+      u8  lin_blue_off;
-+      u8  lin_rsvd_len;
-+      u8  lin_rsvd_off;
-+      u32 max_pixel_clock;
-+      u16 mode_id;
-+      u8  depth;
-+} __attribute__ ((packed));
-+
-+#define UVESAFB_DEFAULT_MODE "640x480-16"
-+
-+/* How long to wait for a reply from userspace [ms] */
-+#define UVESAFB_TIMEOUT 5000
-+
-+/* Max number of concurrent tasks */
-+#define UVESAFB_TASKS_MAX 16
-+
-+#define dac_reg       (0x3c8)
-+#define dac_val       (0x3c9)
-+
-+struct uvesafb_pal_entry {
-+      u_char blue, green, red, pad;
-+} __attribute__ ((packed));
-+
-+struct uvesafb_ktask {
-+      struct uvesafb_task t;
-+      void *buf;
-+      struct completion *done;
-+      u32 ack;
-+};
-+
-+static int uvesafb_exec(struct uvesafb_ktask *tsk);
-+
-+#define UVESAFB_EXACT_RES     1
-+#define UVESAFB_EXACT_DEPTH   2
-+
-+struct uvesafb_par {
-+      struct vbe_ib vbe_ib;           /* VBE Info Block */
-+      struct vbe_mode_ib *vbe_modes;  /* list of supported VBE modes */
-+      int vbe_modes_cnt;
-+
-+      u8 nocrtc;
-+      u8 ypan;                        /* 0 - nothing, 1 - ypan, 2 - ywrap */
-+      u8 pmi_setpal;                  /* PMI for palette changes */
-+      u16 *pmi_base;                  /* protected mode interface location */
-+      void *pmi_start;
-+      void *pmi_pal;
-+      u8 *vbe_state_orig;             /*
-+                                       * original hardware state, before the
-+                                       * driver was loaded
-+                                       */
-+      u8 *vbe_state_saved;            /* state saved by fb_save_state */
-+      int vbe_state_size;
-+      atomic_t ref_count;
-+
-+      int mode_idx;
-+      struct vbe_crtc_ib crtc;
-+};
-+
-+#endif /* __KERNEL__ */
-+#endif /* _UVESAFB_H */
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/vt_ioctl_race.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/vt_ioctl_race.patch
deleted file mode 100644 (file)
index 5a51d1c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
----
- drivers/char/vt_ioctl.c |    8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-Index: linux-2.6.22/drivers/char/vt_ioctl.c
-===================================================================
---- linux-2.6.22.orig/drivers/char/vt_ioctl.c  2007-07-09 01:32:17.000000000 +0200
-+++ linux-2.6.22/drivers/char/vt_ioctl.c       2007-09-27 11:58:42.000000000 +0200
-@@ -770,6 +770,7 @@
-               /*
-                * Switching-from response
-                */
-+              acquire_console_sem();
-               if (vc->vt_newvt >= 0) {
-                       if (arg == 0)
-                               /*
-@@ -784,7 +785,6 @@
-                                * complete the switch.
-                                */
-                               int newvt;
--                              acquire_console_sem();
-                               newvt = vc->vt_newvt;
-                               vc->vt_newvt = -1;
-                               i = vc_allocate(newvt);
-@@ -798,7 +798,6 @@
-                                * other console switches..
-                                */
-                               complete_change_console(vc_cons[newvt].d);
--                              release_console_sem();
-                       }
-               }
-@@ -810,9 +809,12 @@
-                       /*
-                        * If it's just an ACK, ignore it
-                        */
--                      if (arg != VT_ACKACQ)
-+                      if (arg != VT_ACKACQ) {
-+                              release_console_sem();
-                               return -EINVAL;
-+                      }
-               }
-+              release_console_sem();
-               return 0;
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/w100fb-unused-var.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/w100fb-unused-var.patch
deleted file mode 100644 (file)
index 8cbbb6b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-From: Marcin Juszkiewicz <openembedded@haerwu.biz>
-
-drivers/video/w100fb.c: In function â€˜w100fb_imageblit’:
-drivers/video/w100fb.c:507: warning: unused variable â€˜par’
-
-Signed-off-by: Marcin Juszkiewicz <openembedded@haerwu.biz>
-
---- linux-2.6.23/drivers/video/w100fb.c        2007-10-11 16:52:30.000000000 +0200
-+++ linux-2.6.23/drivers/video/w100fb.c        2007-10-15 12:56:01.000000000 +0200
-@@ -504,7 +504,6 @@ static void w100_hostdata(u32 width, u32
- static void w100fb_imageblit(struct fb_info *info,
-                              const struct fb_image *image)
- {
--      struct w100fb_par *par = info->par;
-       union dp_gui_master_cntl_u gmc;
-       u32 fgcolor, bgcolor;
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/wm97xx-lcdnoise-r0.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/wm97xx-lcdnoise-r0.patch
deleted file mode 100644 (file)
index 191de3a..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-Index: linux-tosa/drivers/input/touchscreen/wm9712.c
-===================================================================
---- linux-tosa.orig/drivers/input/touchscreen/wm9712.c 2006-08-29 16:52:36.008543280 +0100
-+++ linux-tosa/drivers/input/touchscreen/wm9712.c      2006-08-29 16:52:50.923275896 +0100
-@@ -1,7 +1,7 @@
- /*
-  * wm9712.c  --  Codec driver for Wolfson WM9712 AC97 Codecs.
-  *
-- * Copyright 2003, 2004, 2005 Wolfson Microelectronics PLC.
-+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
-  * Author: Liam Girdwood
-  *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
-  * Parts Copyright : Ian Molton <spyro@f2s.com>
-@@ -13,6 +13,12 @@
-  *  Free Software Foundation;  either version 2 of the  License, or (at your
-  *  option) any later version.
-  *
-+ *  Revision history
-+ *     4th Jul 2005  Initial version.
-+ *    29th Aug 2006  Mike Arthur <mike@mikearthur.co.uk>
-+ *                   Added fixes for Sharp SL-6000 (Tosa) LCD noise causing
-+ *                   touchscreen interference.
-+ *
-  */
- #include <linux/module.h>
-@@ -28,6 +34,10 @@
- #define WM9705_VERSION                "0.60"
- #define DEFAULT_PRESSURE      0xb0c0
-+#define CCNT(a)     asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a))
-+#define CCNT_ON()   asm("mcr p14, 0, %0, C0, C0, 0" : : "r"(1))
-+#define CCNT_OFF()  asm("mcr p14, 0, %0, C0, C0, 0" : : "r"(1))
-+
- /*
-  * Debug
-  */
-@@ -243,6 +253,36 @@
-       return wm->dig[2] & WM9712_PDEN;
- }
-+
-+#ifdef CONFIG_MACH_TOSA
-+/* On the Sharp SL-6000 (Tosa), due to a noisy LCD, we need to perform a wait
-+ * before sampling the Y axis of the touchscreen */
-+static inline void wm9712_lcd_sync_on(struct wm97xx* wm, int adcsel) {
-+    unsigned long timer1 = 0, timer2 = 0, wait_time = 0;
-+    if (adcsel == WM97XX_ADCSEL_Y) {
-+        wait_time = wm97xx_calc_lcd_waittime(wm);
-+
-+        CCNT_ON();
-+
-+        if (wait_time) {
-+            /* wait for LCD rising edge */
-+            wm_machinfo->wait_hsync();
-+            /* get clock */
-+            CCNT(timer1);
-+            CCNT(timer2);
-+
-+            while ((timer2 - timer1) < wait_time) {
-+                CCNT(timer2);
-+            }
-+        }
-+    }
-+}
-+
-+static inline void wm9712_lcd_sync_off(void) {
-+    CCNT_OFF();
-+}
-+#endif
-+
- /*
-  * Read a sample from the WM9712 adc in polling mode.
-  */
-@@ -260,6 +300,9 @@
-       /* set up digitiser */
-       if (adcsel & 0x8000)
-               adcsel = ((adcsel & 0x7fff) + 3) << 12;
-+    #ifdef CONFIG_MACH_TOSA
-+    wm9712_lcd_sync_on(wm, adcsel);
-+    #endif
-       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
-       
-       /* wait 3 AC97 time slots + delay for conversion */
-@@ -282,6 +325,10 @@
-       
-       *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
-       
-+    #ifdef CONFIG_MACH_TOSA
-+    wm9712_lcd_sync_off();
-+    #endif
-+
-       /* check we have correct sample */
-       if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
-               dbg ("adc wrong sample, read %x got %x", adcsel,
-@@ -303,11 +350,12 @@
- static int wm9712_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
- {
-       int rc;
--      
-       if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID)
-               return rc;
-+
-       if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID)
-               return rc;
-+
-       if (pil && !five_wire) {
-               if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID)
-                       return rc;
-Index: linux-tosa/drivers/input/touchscreen/wm97xx-core.c
-===================================================================
---- linux-tosa.orig/drivers/input/touchscreen/wm97xx-core.c    2006-08-29 16:52:36.008543280 +0100
-+++ linux-tosa/drivers/input/touchscreen/wm97xx-core.c 2006-08-29 16:52:50.924275744 +0100
-@@ -2,7 +2,7 @@
-  * wm97xx-core.c  --  Touch screen driver core for Wolfson WM9705, WM9712
-  *                           and WM9713 AC97 Codecs.
-  *
-- * Copyright 2003, 2004, 2005 Wolfson Microelectronics PLC.
-+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
-  * Author: Liam Girdwood
-  *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
-  * Parts Copyright : Ian Molton <spyro@f2s.com>
-@@ -67,6 +67,9 @@
-  *                   GPIOs) and 2.6 power management. 
-  *    29th Nov 2004  Added WM9713 support.
-  *     4th Jul 2005  Moved codec specific code out to seperate files.
-+ *    29th Aug 2006  Mike Arthur <mike@mikearthur.co.uk>
-+ *                   Added fixes for Sharp SL-6000 (Tosa) LCD noise causing
-+ *                   touchscreen interference.
-  */  
-     
- #include <linux/module.h>
-@@ -94,6 +97,7 @@
- static DECLARE_MUTEX(gpio_sem);
- static LIST_HEAD(wm97xx_misc_list);
- static struct wm97xx* wm_codec = NULL;
-+struct wm97xx_machinfo *wm_machinfo;
- /*
-  * WM97xx - enable/disable AUX ADC sysfs 
-@@ -832,6 +836,23 @@
-               mdev->remove(wm_codec);
- }
-+#ifdef CONFIG_MACH_TOSA
-+/* On the Sharp SL-6000 (Tosa), due to a noisy LCD, we need to perform a wait
-+ * before sampling the Y axis of the touchscreen */
-+unsigned long wm97xx_calc_lcd_waittime(struct wm97xx *wm) {
-+    unsigned long hsync_time = wm_machinfo->get_hsync_time();
-+    return hsync_time;
-+}
-+
-+void wm97xx_set_machinfo(struct wm97xx_machinfo *machinfo) {
-+    wm_machinfo = machinfo;
-+}
-+
-+void wm97xx_unset_machinfo() {
-+    wm_machinfo = NULL;
-+}
-+#endif
-+
- static struct device_driver wm97xx_driver = {
-       .name =         "ac97", 
-       .bus =          &ac97_bus_type, 
-@@ -861,6 +882,9 @@
- EXPORT_SYMBOL_GPL(wm97xx_reg_write);
- EXPORT_SYMBOL_GPL(wm97xx_register_misc_dev);
- EXPORT_SYMBOL_GPL(wm97xx_unregister_misc_dev);
-+EXPORT_SYMBOL_GPL(wm97xx_calc_lcd_waittime);
-+EXPORT_SYMBOL_GPL(wm97xx_set_machinfo);
-+EXPORT_SYMBOL_GPL(wm97xx_unset_machinfo);
- module_init(wm97xx_init); 
- module_exit(wm97xx_exit);
-Index: linux-tosa/include/linux/wm97xx.h
-===================================================================
---- linux-tosa.orig/include/linux/wm97xx.h     2006-08-29 16:52:36.008543280 +0100
-+++ linux-tosa/include/linux/wm97xx.h  2006-08-29 16:52:50.924275744 +0100
-@@ -207,6 +207,7 @@
- struct wm97xx;
- extern struct wm97xx_codec_drv wm97xx_codec;
-+extern struct wm97xx_machinfo *wm_machinfo;
- /*
-  * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
-@@ -253,6 +254,11 @@
-       struct list_head list;
- };
-+struct wm97xx_machinfo {
-+    unsigned long (*get_hsync_time)(void);
-+    void (*wait_hsync)(void);
-+};
-+
- int wm97xx_register_misc_dev(struct wm97xx_misc_dev* mdev);
- void wm97xx_unregister_misc_dev(struct wm97xx_misc_dev* mdev);
-@@ -281,4 +287,9 @@
- int wm97xx_acc_startup(struct wm97xx* wm);
- void wm97xx_acc_shutdown(struct wm97xx* wm);
-+
-+unsigned long wm97xx_calc_lcd_waittime(struct wm97xx *wm);
-+void wm97xx_set_machinfo(struct wm97xx_machinfo *machinfo);
-+void wm97xx_unset_machinfo(void);
-+
- #endif
diff --git a/meta/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch b/meta/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch
deleted file mode 100644 (file)
index ac2245f..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
----
- drivers/mmc/core/sd.c |   11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
-Index: linux-2.6.23/drivers/mmc/core/sd.c
-===================================================================
---- linux-2.6.23.orig/drivers/mmc/core/sd.c    2007-10-17 11:33:26.000000000 +0200
-+++ linux-2.6.23/drivers/mmc/core/sd.c 2007-10-17 11:33:49.000000000 +0200
-@@ -173,14 +173,15 @@
-       scr_struct = UNSTUFF_BITS(resp, 60, 4);
-       if (scr_struct != 0) {
--              printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
-+              printk(KERN_WARNING "%s: unrecognised SCR structure version %d\n",
-                       mmc_hostname(card->host), scr_struct);
--              return -EINVAL;
-+              scr->sda_vsn = 0;
-+              scr->bus_widths = 0;
-+      } else {
-+              scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
-+              scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
-       }
--      scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
--      scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
--
-       return 0;
- }
diff --git a/meta/packages/linux/linux-rp-2.6.23/pda-power.patch b/meta/packages/linux/linux-rp-2.6.23/pda-power.patch
deleted file mode 100644 (file)
index face2f4..0000000
+++ /dev/null
@@ -1,3373 +0,0 @@
----
- arch/arm/Kconfig                   |    2 
- drivers/Kconfig                    |    2 
- drivers/Makefile                   |    1 
- drivers/power/Kconfig              |   70 +++++
- drivers/power/Makefile             |   28 ++
- drivers/power/adc_battery.c        |  278 +++++++++++++++++++++
- drivers/power/apm_power.c          |  247 +++++++++++++++++++
- drivers/power/ds2760_battery.c     |  475 +++++++++++++++++++++++++++++++++++++
- drivers/power/micro_battery.c      |  257 ++++++++++++++++++++
- drivers/power/olpc_battery.c       |  302 +++++++++++++++++++++++
- drivers/power/pda_power.c          |  263 ++++++++++++++++++++
- drivers/power/pmu_battery.c        |  215 ++++++++++++++++
- drivers/power/power_supply.h       |   42 +++
- drivers/power/power_supply_core.c  |  168 +++++++++++++
- drivers/power/power_supply_leds.c  |  188 ++++++++++++++
- drivers/power/power_supply_sysfs.c |  289 ++++++++++++++++++++++
- drivers/power/simpad-battery.c     |  242 ++++++++++++++++++
- include/linux/power_supply.h       |  175 +++++++++++++
- 18 files changed, 3244 insertions(+)
-
-Index: linux-2.6.22/drivers/power/adc_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/adc_battery.c   2007-08-23 12:26:28.000000000 +0200
-@@ -0,0 +1,278 @@
-+/*
-+ * Copyright (c) 2007 Paul Sokolovsky
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ */
-+
-+//#define DEBUG
-+
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/pm.h>
-+#include <linux/delay.h>
-+#include <linux/workqueue.h>
-+#include <linux/platform_device.h>
-+#include <linux/power_supply.h>
-+#include <linux/adc.h>
-+#include <linux/adc_battery.h>
-+
-+#include <asm/irq.h>
-+
-+#define PIN_NO_VOLT 0
-+#define PIN_NO_CURR 1
-+#define PIN_NO_TEMP 2
-+
-+struct battery_adc_priv {
-+      struct power_supply batt_cdev;
-+
-+      struct battery_adc_platform_data *pdata;
-+
-+      struct adc_request req;
-+      struct adc_sense pins[3];
-+      struct adc_sense last_good_pins[3];
-+
-+      struct workqueue_struct *wq;
-+      struct delayed_work work;
-+};
-+
-+/*
-+ *  Battery properties
-+ */
-+
-+static int adc_battery_get_property(struct power_supply *psy,
-+                                    enum power_supply_property psp,
-+                                    union power_supply_propval *val)
-+{
-+      struct battery_adc_priv* drvdata = (struct battery_adc_priv*)psy;
-+      int voltage;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              val->intval = drvdata->pdata->charge_status;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.voltage_max_design;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.voltage_min_design;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.charge_full_design;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
-+              val->intval = drvdata->pdata->battery_info.charge_empty_design;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+              val->intval = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_NOW:
-+              val->intval = drvdata->last_good_pins[PIN_NO_CURR].value * drvdata->pdata->current_mult;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_NOW:
-+              /* We do calculations in mX, not uX, because todo it in uX we should use "long long"s,
-+               * which is a mess (need to use do_div) when you need divide operation). */
-+              voltage = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
-+              val->intval = ((voltage/1000 - drvdata->pdata->battery_info.voltage_min_design/1000) *
-+                   (drvdata->pdata->battery_info.charge_full_design/1000 -
-+                    drvdata->pdata->battery_info.charge_empty_design/1000)) /
-+                   (drvdata->pdata->battery_info.voltage_max_design/1000 -
-+                    drvdata->pdata->battery_info.voltage_min_design/1000);
-+              val->intval *= 1000; /* convert final result to uX */
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = drvdata->last_good_pins[PIN_NO_TEMP].value * drvdata->pdata->temperature_mult / 1000;
-+              break;
-+      default:
-+              return -EINVAL;
-+      };
-+      return 0;
-+}
-+
-+/*
-+ *  Driver body
-+ */
-+
-+static void adc_battery_query(struct battery_adc_priv *drvdata)
-+{
-+      struct battery_adc_platform_data *pdata = drvdata->pdata;
-+      int powered, charging;
-+
-+      adc_request_sample(&drvdata->req);
-+
-+      powered = power_supply_am_i_supplied(&drvdata->batt_cdev);
-+      charging = pdata->is_charging ? pdata->is_charging() : -1;
-+
-+      if (powered && charging)
-+              pdata->charge_status = POWER_SUPPLY_STATUS_CHARGING;
-+      else if (powered && !charging && charging != -1)
-+              pdata->charge_status = POWER_SUPPLY_STATUS_FULL;
-+      else
-+              pdata->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
-+
-+      /* Throw away invalid samples, this may happen soon after resume for example. */
-+      if (drvdata->pins[PIN_NO_VOLT].value > 0) {
-+              memcpy(drvdata->last_good_pins, drvdata->pins, sizeof(drvdata->pins));
-+#ifdef DEBUG
-+              printk("%d %d %d\n", drvdata->pins[PIN_NO_VOLT].value,
-+                                   drvdata->pins[PIN_NO_CURR].value,
-+                                   drvdata->pins[PIN_NO_TEMP].value);
-+#endif
-+      }
-+}
-+
-+static void adc_battery_charge_power_changed(struct power_supply *bat)
-+{
-+      struct battery_adc_priv *drvdata = (struct battery_adc_priv*)bat;
-+      cancel_delayed_work(&drvdata->work);
-+      queue_delayed_work(drvdata->wq, &drvdata->work, 0);
-+}
-+
-+static void adc_battery_work_func(struct work_struct *work)
-+{
-+      struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);
-+      struct battery_adc_priv *drvdata = container_of(delayed_work, struct battery_adc_priv, work);
-+
-+      adc_battery_query(drvdata);
-+      power_supply_changed(&drvdata->batt_cdev);
-+
-+      queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
-+}
-+
-+static int adc_battery_probe(struct platform_device *pdev)
-+{
-+        int retval;
-+      struct battery_adc_platform_data *pdata = pdev->dev.platform_data;
-+      struct battery_adc_priv *drvdata;
-+      int i, j;
-+      enum power_supply_property props[] = {
-+              POWER_SUPPLY_PROP_STATUS,
-+              POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+              POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-+              POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+              POWER_SUPPLY_PROP_CURRENT_NOW,
-+              POWER_SUPPLY_PROP_CHARGE_NOW,
-+              POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+              POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
-+              POWER_SUPPLY_PROP_TEMP,
-+      };
-+
-+      // Initialize ts data structure.
-+      drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-+      if (!drvdata)
-+              return -ENOMEM;
-+
-+      drvdata->batt_cdev.name           = pdata->battery_info.name;
-+      drvdata->batt_cdev.use_for_apm    = pdata->battery_info.use_for_apm;
-+      drvdata->batt_cdev.num_properties = ARRAY_SIZE(props);
-+      drvdata->batt_cdev.get_property   = adc_battery_get_property;
-+      drvdata->batt_cdev.external_power_changed =
-+                                adc_battery_charge_power_changed;
-+
-+      if (!pdata->voltage_pin) {
-+              drvdata->batt_cdev.num_properties--;
-+              props[3] = -1;
-+      }
-+      if (!pdata->current_pin) {
-+              drvdata->batt_cdev.num_properties--;
-+              props[4] = -1;
-+      }
-+      if (!pdata->temperature_pin) {
-+              drvdata->batt_cdev.num_properties--;
-+              props[8] = -1;
-+      }
-+
-+      drvdata->batt_cdev.properties = kmalloc(
-+                      sizeof(*drvdata->batt_cdev.properties) *
-+                      drvdata->batt_cdev.num_properties, GFP_KERNEL);
-+      if (!drvdata->batt_cdev.properties)
-+              return -ENOMEM;
-+
-+      j = 0;
-+      for (i = 0; i < ARRAY_SIZE(props); i++) {
-+              if (props[i] == -1)
-+                      continue;
-+              drvdata->batt_cdev.properties[j++] = props[i];
-+      }
-+
-+      retval = power_supply_register(&pdev->dev, &drvdata->batt_cdev);
-+      if (retval) {
-+              printk("adc-battery: Error registering battery classdev");
-+              return retval;
-+      }
-+
-+      drvdata->req.senses = drvdata->pins;
-+      drvdata->req.num_senses = ARRAY_SIZE(drvdata->pins);
-+      drvdata->pins[PIN_NO_VOLT].name = pdata->voltage_pin;
-+      drvdata->pins[PIN_NO_CURR].name = pdata->current_pin;
-+      drvdata->pins[PIN_NO_TEMP].name = pdata->temperature_pin;
-+
-+      adc_request_register(&drvdata->req);
-+
-+      /* Here we assume raw values in mV */
-+      if (!pdata->voltage_mult)
-+              pdata->voltage_mult = 1000;
-+      /* Here we assume raw values in mA */
-+      if (!pdata->current_mult)
-+              pdata->current_mult = 1000;
-+      /* Here we assume raw values in 1/10 C */
-+      if (!pdata->temperature_mult)
-+              pdata->temperature_mult = 1000;
-+
-+      drvdata->pdata = pdata;
-+      pdata->drvdata = drvdata; /* Seems ugly, we need better solution */
-+
-+      platform_set_drvdata(pdev, drvdata);
-+
-+        // Load initial values ASAP
-+      adc_battery_query(drvdata);
-+
-+      // Still schedule next sampling soon
-+      INIT_DELAYED_WORK(&drvdata->work, adc_battery_work_func);
-+      drvdata->wq = create_workqueue(pdev->dev.bus_id);
-+      if (!drvdata->wq)
-+              return -ESRCH;
-+
-+      queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
-+
-+      return retval;
-+}
-+
-+static int adc_battery_remove(struct platform_device *pdev)
-+{
-+      struct battery_adc_priv *drvdata = platform_get_drvdata(pdev);
-+      cancel_delayed_work(&drvdata->work);
-+      destroy_workqueue(drvdata->wq);
-+      power_supply_unregister(&drvdata->batt_cdev);
-+      adc_request_unregister(&drvdata->req);
-+      kfree(drvdata->batt_cdev.properties);
-+      return 0;
-+}
-+
-+static struct platform_driver adc_battery_driver = {
-+      .driver         = {
-+              .name   = "adc-battery",
-+      },
-+      .probe          = adc_battery_probe,
-+      .remove         = adc_battery_remove,
-+};
-+
-+static int __init adc_battery_init(void)
-+{
-+      return platform_driver_register(&adc_battery_driver);
-+}
-+
-+static void __exit adc_battery_exit(void)
-+{
-+      platform_driver_unregister(&adc_battery_driver);
-+}
-+
-+module_init(adc_battery_init)
-+module_exit(adc_battery_exit)
-+
-+MODULE_AUTHOR("Paul Sokolovsky");
-+MODULE_DESCRIPTION("Battery driver for ADC device");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/drivers/power/apm_power.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/apm_power.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,247 @@
-+/*
-+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
-+ * Copyright (c) 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
-+ *
-+ * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
-+ *
-+ * Use consistent with the GNU GPL is permitted,
-+ * provided that this copyright notice is
-+ * preserved in its entirety in all copies and derived works.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/power_supply.h>
-+#include <linux/apm-emulation.h>
-+
-+#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
-+                         POWER_SUPPLY_PROP_##prop, val)
-+
-+#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
-+                                                         prop, val)
-+
-+#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
-+
-+static struct power_supply *main_battery;
-+
-+static void find_main_battery(void)
-+{
-+      struct device *dev;
-+      struct power_supply *bat, *batm;
-+      union power_supply_propval full;
-+      int max_charge = 0;
-+
-+      main_battery = NULL;
-+      batm = NULL;
-+      list_for_each_entry(dev, &power_supply_class->devices, node) {
-+              bat = dev_get_drvdata(dev);
-+              /* If none of battery devices cantains 'use_for_apm' flag,
-+                 choice one with maximum design charge */
-+              if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
-+                      if (full.intval > max_charge) {
-+                              batm = bat;
-+                              max_charge = full.intval;
-+                      }
-+              }
-+
-+              if (bat->use_for_apm)
-+                      main_battery = bat;
-+      }
-+      if (!main_battery)
-+              main_battery = batm;
-+
-+      return;
-+}
-+
-+static int calculate_time(int status)
-+{
-+      union power_supply_propval charge_full, charge_empty;
-+      union power_supply_propval charge, I;
-+
-+      if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
-+              /* if battery can't report this property, use design value */
-+              if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
-+                      return -1;
-+      }
-+
-+      if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
-+              /* if battery can't report this property, use design value */
-+              if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
-+                      charge_empty.intval = 0;
-+      }
-+
-+      if (MPSY_PROP(CHARGE_AVG, &charge)) {
-+              /* if battery can't report average value, use momentary */
-+              if (MPSY_PROP(CHARGE_NOW, &charge))
-+                      return -1;
-+      }
-+
-+      if (MPSY_PROP(CURRENT_AVG, &I)) {
-+              /* if battery can't report average value, use momentary */
-+              if (MPSY_PROP(CURRENT_NOW, &I))
-+                      return -1;
-+      }
-+
-+      if (I.intval == 0)
-+              return 0;
-+      else if (status == POWER_SUPPLY_STATUS_CHARGING)
-+              return ((charge.intval - charge_full.intval) * 60L) /
-+                     I.intval;
-+      else
-+              return -((charge.intval - charge_empty.intval) * 60L) /
-+                      I.intval;
-+}
-+
-+static int calculate_capacity(int using_charge)
-+{
-+      enum power_supply_property full_prop, empty_prop;
-+      enum power_supply_property full_design_prop, empty_design_prop;
-+      enum power_supply_property now_prop, avg_prop;
-+      union power_supply_propval empty, full, cur;
-+      int ret;
-+
-+      if (using_charge) {
-+              full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
-+              empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
-+              full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
-+              empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
-+              now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
-+              avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
-+      }
-+      else {
-+              full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
-+              empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
-+              full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
-+              empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
-+              now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
-+              avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
-+      }
-+
-+      if (_MPSY_PROP(full_prop, &full)) {
-+              /* if battery can't report this property, use design value */
-+              if (_MPSY_PROP(full_design_prop, &full))
-+                      return -1;
-+      }
-+
-+      if (_MPSY_PROP(avg_prop, &cur)) {
-+              /* if battery can't report average value, use momentary */
-+              if (_MPSY_PROP(now_prop, &cur))
-+                      return -1;
-+      }
-+
-+      if (_MPSY_PROP(empty_prop, &empty)) {
-+              /* if battery can't report this property, use design value */
-+              if (_MPSY_PROP(empty_design_prop, &empty))
-+                      empty.intval = 0;
-+      }
-+
-+      if (full.intval - empty.intval)
-+              ret =  ((cur.intval - empty.intval) * 100L) /
-+                     (full.intval - empty.intval);
-+      else
-+              return -1;
-+
-+      if (ret > 100)
-+              return 100;
-+      else if (ret < 0)
-+              return 0;
-+
-+      return ret;
-+}
-+
-+static void apm_battery_apm_get_power_status(struct apm_power_info *info)
-+{
-+      union power_supply_propval status;
-+      union power_supply_propval capacity, time_to_full, time_to_empty;
-+
-+      down(&power_supply_class->sem);
-+      find_main_battery();
-+      if (!main_battery) {
-+              up(&power_supply_class->sem);
-+              return;
-+      }
-+
-+      /* status */
-+
-+      if (MPSY_PROP(STATUS, &status))
-+              status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+      /* ac line status */
-+
-+      if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
-+          (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
-+          (status.intval == POWER_SUPPLY_STATUS_FULL))
-+              info->ac_line_status = APM_AC_ONLINE;
-+      else
-+              info->ac_line_status = APM_AC_OFFLINE;
-+
-+      /* battery life (i.e. capacity, in percents) */
-+
-+      if (MPSY_PROP(CAPACITY, &capacity) == 0)
-+              info->battery_life = capacity.intval;
-+      else {
-+              /* try calculate using energy */
-+              info->battery_life = calculate_capacity(0);
-+              /* if failed try calculate using charge instead */
-+              if (info->battery_life == -1)
-+                      info->battery_life = calculate_capacity(1);
-+      }
-+
-+      /* charging status */
-+
-+      if (status.intval == POWER_SUPPLY_STATUS_CHARGING)
-+              info->battery_status = APM_BATTERY_STATUS_CHARGING;
-+      else {
-+              if (info->battery_life > 50)
-+                      info->battery_status = APM_BATTERY_STATUS_HIGH;
-+              else if (info->battery_life > 5)
-+                      info->battery_status = APM_BATTERY_STATUS_LOW;
-+              else
-+                      info->battery_status = APM_BATTERY_STATUS_CRITICAL;
-+      }
-+      info->battery_flag = info->battery_status;
-+
-+      /* time */
-+
-+      info->units = APM_UNITS_MINS;
-+
-+      if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
-+              if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
-+                      if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
-+                              info->time = calculate_time(status.intval);
-+                      else
-+                              info->time = time_to_full.intval / 60;
-+              }
-+      }
-+      else {
-+              if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
-+                      if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
-+                              info->time = calculate_time(status.intval);
-+                      else
-+                              info->time = time_to_empty.intval / 60;
-+              }
-+      }
-+
-+      up(&power_supply_class->sem);
-+      return;
-+}
-+
-+static int __init apm_battery_init(void)
-+{
-+      printk(KERN_INFO "APM Battery Driver\n");
-+
-+      apm_get_power_status = apm_battery_apm_get_power_status;
-+      return 0;
-+}
-+
-+static void __exit apm_battery_exit(void)
-+{
-+      apm_get_power_status = NULL;
-+      return;
-+}
-+
-+module_init(apm_battery_init);
-+module_exit(apm_battery_exit);
-+
-+MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
-+MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/drivers/power/ds2760_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/ds2760_battery.c        2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,475 @@
-+/*
-+ * Driver for batteries with DS2760 chips inside.
-+ *
-+ * Copyright (c) 2007 Anton Vorontsov
-+ *               2004-2007 Matt Reimer
-+ *               2004 Szabolcs Gyurko
-+ *
-+ * Use consistent with the GNU GPL is permitted,
-+ * provided that this copyright notice is
-+ * preserved in its entirety in all copies and derived works.
-+ *
-+ * Author:  Anton Vorontsov <cbou@mail.ru>
-+ *          February 2007
-+ *
-+ *          Matt Reimer <mreimer@vpop.net>
-+ *          April 2004, 2005, 2007
-+ *
-+ *          Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
-+ *          September 2004
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/param.h>
-+#include <linux/jiffies.h>
-+#include <linux/workqueue.h>
-+#include <linux/pm.h>
-+#include <linux/platform_device.h>
-+#include <linux/power_supply.h>
-+
-+#include "../w1/w1.h"
-+#include "../w1/slaves/w1_ds2760.h"
-+
-+struct ds2760_device_info {
-+      struct device *dev;
-+
-+      /* DS2760 data, valid after calling ds2760_battery_read_status() */
-+      unsigned long update_time;      /* jiffies when data read */
-+      char raw[DS2760_DATA_SIZE];     /* raw DS2760 data */
-+      int voltage_raw;                /* units of 4.88 mV */
-+      int voltage_uV;                 /* units of uV */
-+      int current_raw;                /* units of 0.625 mA */
-+      int current_uA;                 /* units of uA */
-+      int accum_current_raw;          /* units of 0.25 mAh */
-+      int accum_current_uAh;          /* units of uAh */
-+      int temp_raw;                   /* units of 0.125 C */
-+      int temp_C;                     /* units of 0.1 C */
-+      int rated_capacity;             /* units of uAh */
-+      int rem_capacity;               /* percentage */
-+      int full_active_uAh;            /* units of uAh */
-+      int empty_uAh;                  /* units of uAh */
-+      int life_sec;                   /* units of seconds */
-+      int charge_status;              /* POWER_SUPPLY_STATUS_* */
-+
-+      int full_counter;
-+      struct power_supply bat;
-+      struct device *w1_dev;
-+      struct workqueue_struct *monitor_wqueue;
-+      struct delayed_work monitor_work;
-+};
-+
-+static unsigned int cache_time = 1000;
-+module_param(cache_time, uint, 0644);
-+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
-+
-+/* Some batteries have their rated capacity stored a N * 10 mAh, while
-+ * others use an index into this table. */
-+static int rated_capacities[] = {
-+      0,
-+      920,        /* Samsung */
-+      920,        /* BYD */
-+      920,        /* Lishen */
-+      920,        /* NEC */
-+      1440,       /* Samsung */
-+      1440,       /* BYD */
-+      1440,       /* Lishen */
-+      1440,       /* NEC */
-+      2880,       /* Samsung */
-+      2880,       /* BYD */
-+      2880,       /* Lishen */
-+      2880        /* NEC */
-+};
-+
-+/* array is level at temps 0C, 10C, 20C, 30C, 40C
-+ * temp is in Celsius */
-+static int battery_interpolate(int array[], int temp)
-+{
-+      int index, dt;
-+
-+      if (temp <= 0)
-+              return array[0];
-+      if (temp >= 40)
-+              return array[4];
-+
-+      index = temp / 10;
-+      dt    = temp % 10;
-+
-+      return array[index] + (((array[index + 1] - array[index]) * dt) / 10);
-+}
-+
-+static int ds2760_battery_read_status(struct ds2760_device_info *di)
-+{
-+      int ret, i, start, count, scale[5];
-+
-+      if (di->update_time && time_before(jiffies, di->update_time +
-+                                         msecs_to_jiffies(cache_time)))
-+              return 0;
-+
-+      /* The first time we read the entire contents of SRAM/EEPROM,
-+       * but after that we just read the interesting bits that change. */
-+      if (di->update_time == 0) {
-+              start = 0;
-+              count = DS2760_DATA_SIZE;
-+      }
-+      else {
-+              start = DS2760_VOLTAGE_MSB;
-+              count = DS2760_TEMP_LSB - start + 1;
-+      }
-+
-+      ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count);
-+      if (ret != count) {
-+              dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n",
-+                       di->w1_dev);
-+              return 1;
-+      }
-+
-+      di->update_time = jiffies;
-+
-+      /* DS2760 reports voltage in units of 4.88mV, but the battery class
-+       * reports in units of uV, so convert by multiplying by 4880. */
-+      di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) |
-+                        (di->raw[DS2760_VOLTAGE_LSB] >> 5);
-+      di->voltage_uV = di->voltage_raw * 4880;
-+
-+      /* DS2760 reports current in signed units of 0.625mA, but the battery
-+       * class reports in units of uA, so convert by multiplying by 625. */
-+      di->current_raw =
-+          (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) |
-+                        (di->raw[DS2760_CURRENT_LSB] >> 3);
-+      di->current_uA = di->current_raw * 625;
-+
-+      /* DS2760 reports accumulated current in signed units of 0.25mAh. */
-+      di->accum_current_raw =
-+          (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) |
-+                         di->raw[DS2760_CURRENT_ACCUM_LSB];
-+      di->accum_current_uAh = di->accum_current_raw * 250;
-+
-+      /* DS2760 reports temperature in signed units of 0.125C, but the
-+       * battery class reports in units of 1/10 C, so we convert by
-+       * multiplying by .125 * 10 = 1.25. */
-+      di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) |
-+                                   (di->raw[DS2760_TEMP_LSB] >> 5);
-+      di->temp_C = di->temp_raw + (di->temp_raw / 4);
-+
-+      /* At least some battery monitors (e.g. HP iPAQ) store the battery's
-+       * maximum rated capacity. */
-+      if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities))
-+              di->rated_capacity = rated_capacities[
-+                      (unsigned int)di->raw[DS2760_RATED_CAPACITY]];
-+      else
-+              di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10;
-+
-+      di->rated_capacity *= 1000; /* convert to uAh */
-+
-+      /* Calculate the full level at the present temperature. */
-+      di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
-+                            di->raw[DS2760_ACTIVE_FULL + 1];
-+
-+      scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 |
-+                 di->raw[DS2760_ACTIVE_FULL + 1];
-+      for (i = 1; i < 5; i++)
-+              scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
-+
-+      di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
-+      di->full_active_uAh *= 1000; /* convert to uAh */
-+
-+      /* Calculate the empty level at the present temperature. */
-+      scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4];
-+      for (i = 3; i >= 0; i--)
-+              scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i];
-+
-+      di->empty_uAh = battery_interpolate(scale, di->temp_C / 10);
-+      di->empty_uAh *= 1000; /* convert to uAh */
-+
-+      /* From Maxim Application Note 131: remaining capacity =
-+       * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */
-+      di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) /
-+                          (di->full_active_uAh - di->empty_uAh);
-+
-+      if (di->rem_capacity < 0)
-+              di->rem_capacity = 0;
-+      if (di->rem_capacity > 100)
-+              di->rem_capacity = 100;
-+
-+      if (di->current_uA)
-+              di->life_sec = -((di->accum_current_uAh - di->empty_uAh) *
-+                               3600L) / di->current_uA;
-+      else
-+              di->life_sec = 0;
-+
-+      return 0;
-+}
-+
-+static void ds2760_battery_update_status(struct ds2760_device_info *di)
-+{
-+      int old_charge_status = di->charge_status;
-+
-+      ds2760_battery_read_status(di);
-+
-+      if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN)
-+              di->full_counter = 0;
-+
-+      if (power_supply_am_i_supplied(&di->bat)) {
-+              if (di->current_uA > 10000) {
-+                      di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
-+                      di->full_counter = 0;
-+              }
-+              else if (di->current_uA < -5000) {
-+                      if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING)
-+                              dev_notice(di->dev, "not enough power to "
-+                                         "charge\n");
-+                      di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-+                      di->full_counter = 0;
-+              }
-+              else if (di->current_uA < 10000 &&
-+                          di->charge_status != POWER_SUPPLY_STATUS_FULL) {
-+
-+                      /* Don't consider the battery to be full unless
-+                       * we've seen the current < 10 mA at least two
-+                       * consecutive times. */
-+
-+                      di->full_counter++;
-+
-+                      if (di->full_counter < 2)
-+                              di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
-+                      else {
-+                              unsigned char acr[2];
-+                              int acr_val;
-+
-+                              /* acr is in units of 0.25 mAh */
-+                              acr_val = di->full_active_uAh * 4L / 1000;
-+
-+                              acr[0] = acr_val >> 8;
-+                              acr[1] = acr_val & 0xff;
-+
-+                              if (w1_ds2760_write(di->w1_dev, acr,
-+                                  DS2760_CURRENT_ACCUM_MSB, 2) < 2)
-+                                      dev_warn(di->dev,
-+                                               "ACR reset failed\n");
-+
-+                              di->charge_status = POWER_SUPPLY_STATUS_FULL;
-+                      }
-+              }
-+      }
-+      else {
-+              di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
-+              di->full_counter = 0;
-+      }
-+
-+      if (di->charge_status != old_charge_status)
-+              power_supply_changed(&di->bat);
-+
-+      return;
-+}
-+
-+static void ds2760_battery_work(struct work_struct *work)
-+{
-+      struct ds2760_device_info *di = container_of(work,
-+              struct ds2760_device_info, monitor_work.work);
-+      const int interval = HZ * 60;
-+
-+      dev_dbg(di->dev, "%s\n", __FUNCTION__);
-+
-+      ds2760_battery_update_status(di);
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
-+
-+      return;
-+}
-+
-+#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \
-+                                              bat);
-+
-+static void ds2760_battery_external_power_changed(struct power_supply *psy)
-+{
-+      struct ds2760_device_info *di = to_ds2760_device_info(psy);
-+
-+      dev_dbg(di->dev, "%s\n", __FUNCTION__);
-+
-+      cancel_delayed_work(&di->monitor_work);
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
-+
-+      return;
-+}
-+
-+static int ds2760_battery_get_property(struct power_supply *psy,
-+                                       enum power_supply_property psp,
-+                                       union power_supply_propval *val)
-+{
-+      struct ds2760_device_info *di = to_ds2760_device_info(psy);
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              val->intval = di->charge_status;
-+              return 0;
-+      default:
-+              break;
-+      }
-+
-+      ds2760_battery_read_status(di);
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+              val->intval = di->voltage_uV;
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_NOW:
-+              val->intval = di->current_uA;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-+              val->intval = di->rated_capacity;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_FULL:
-+              val->intval = di->full_active_uAh;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_EMPTY:
-+              val->intval = di->empty_uAh;
-+              break;
-+      case POWER_SUPPLY_PROP_CHARGE_NOW:
-+              val->intval = di->accum_current_uAh;
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = di->temp_C;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property ds2760_battery_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+      POWER_SUPPLY_PROP_CURRENT_NOW,
-+      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+      POWER_SUPPLY_PROP_CHARGE_FULL,
-+      POWER_SUPPLY_PROP_CHARGE_EMPTY,
-+      POWER_SUPPLY_PROP_CHARGE_NOW,
-+      POWER_SUPPLY_PROP_TEMP,
-+};
-+
-+static int ds2760_battery_probe(struct platform_device *pdev)
-+{
-+      int retval = 0;
-+      struct ds2760_device_info *di;
-+      struct ds2760_platform_data *pdata;
-+
-+      di = kzalloc(sizeof(*di), GFP_KERNEL);
-+      if (!di) {
-+              retval = -ENOMEM;
-+              goto di_alloc_failed;
-+      }
-+
-+      platform_set_drvdata(pdev, di);
-+
-+      pdata = pdev->dev.platform_data;
-+      di->dev                = &pdev->dev;
-+      di->w1_dev             = pdev->dev.parent;
-+      di->bat.name           = pdev->dev.bus_id;
-+      di->bat.type           = POWER_SUPPLY_TYPE_BATTERY;
-+      di->bat.properties     = ds2760_battery_props;
-+      di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
-+      di->bat.get_property   = ds2760_battery_get_property;
-+      di->bat.external_power_changed =
-+                                ds2760_battery_external_power_changed;
-+      di->bat.use_for_apm = 1;
-+
-+      di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+      retval = power_supply_register(&pdev->dev, &di->bat);
-+      if (retval) {
-+              dev_err(di->dev, "failed to register battery");
-+              goto batt_failed;
-+      }
-+
-+      INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
-+      di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id);
-+      if (!di->monitor_wqueue) {
-+              retval = -ESRCH;
-+              goto workqueue_failed;
-+      }
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1);
-+
-+      goto success;
-+
-+workqueue_failed:
-+      power_supply_unregister(&di->bat);
-+batt_failed:
-+      kfree(di);
-+di_alloc_failed:
-+success:
-+      return retval;
-+}
-+
-+static int ds2760_battery_remove(struct platform_device *pdev)
-+{
-+      struct ds2760_device_info *di = platform_get_drvdata(pdev);
-+
-+      cancel_rearming_delayed_workqueue(di->monitor_wqueue,
-+                                        &di->monitor_work);
-+      destroy_workqueue(di->monitor_wqueue);
-+      power_supply_unregister(&di->bat);
-+
-+      return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+
-+static int ds2760_battery_suspend(struct platform_device *pdev,
-+                                  pm_message_t state)
-+{
-+      struct ds2760_device_info *di = platform_get_drvdata(pdev);
-+
-+      di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+      return 0;
-+}
-+
-+static int ds2760_battery_resume(struct platform_device *pdev)
-+{
-+      struct ds2760_device_info *di = platform_get_drvdata(pdev);
-+
-+      di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-+      power_supply_changed(&di->bat);
-+
-+      cancel_delayed_work(&di->monitor_work);
-+      queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
-+
-+      return 0;
-+}
-+
-+#else
-+
-+#define ds2760_battery_suspend NULL
-+#define ds2760_battery_resume NULL
-+
-+#endif /* CONFIG_PM */
-+
-+static struct platform_driver ds2760_battery_driver = {
-+      .driver = {
-+              .name = "ds2760-battery",
-+      },
-+      .probe    = ds2760_battery_probe,
-+      .remove   = ds2760_battery_remove,
-+      .suspend  = ds2760_battery_suspend,
-+      .resume   = ds2760_battery_resume,
-+};
-+
-+static int __init ds2760_battery_init(void)
-+{
-+      return platform_driver_register(&ds2760_battery_driver);
-+}
-+
-+static void __exit ds2760_battery_exit(void)
-+{
-+      platform_driver_unregister(&ds2760_battery_driver);
-+      return;
-+}
-+
-+module_init(ds2760_battery_init);
-+module_exit(ds2760_battery_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
-+              "Matt Reimer <mreimer@vpop.net>, "
-+              "Anton Vorontsov <cbou@mail.ru>");
-+MODULE_DESCRIPTION("ds2760 battery driver");
-Index: linux-2.6.22/drivers/power/Kconfig
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/Kconfig 2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,70 @@
-+menuconfig POWER_SUPPLY
-+      tristate "Power supply class support"
-+      help
-+        Say Y here to enable power supply class support. This allows
-+        power supply (batteries, AC, USB) monitoring by userspace
-+        via sysfs and uevent (if available) and/or APM kernel interface
-+        (if selected below).
-+
-+if POWER_SUPPLY
-+
-+config POWER_SUPPLY_DEBUG
-+      bool "Power supply debug"
-+      help
-+        Say Y here to enable debugging messages for power supply class
-+        and drivers.
-+
-+config PDA_POWER
-+      tristate "Generic PDA/phone power driver"
-+      help
-+        Say Y here to enable generic power driver for PDAs and phones with
-+        one or two external power supplies (AC/USB) connected to main and
-+        backup batteries, and optional builtin charger.
-+
-+config APM_POWER
-+      tristate "APM emulation for class batteries"
-+      depends on APM_EMULATION
-+      help
-+        Say Y here to enable support APM status emulation using
-+        battery class devices.
-+
-+config BATTERY_DS2760
-+      tristate "DS2760 battery driver (HP iPAQ & others)"
-+      select W1
-+      select W1_SLAVE_DS2760
-+      help
-+        Say Y here to enable support for batteries with ds2760 chip.
-+
-+config BATTERY_PMU
-+      tristate "Apple PMU battery"
-+      depends on ADB_PMU
-+      help
-+        Say Y here to expose battery information on Apple machines
-+        through the generic battery class.
-+
-+config BATTERY_OLPC
-+      tristate "One Laptop Per Child battery"
-+      depends on X86_32
-+      help
-+        Say Y to enable support for the battery on the OLPC laptop.
-+
-+# drivers below are not in battery2-2.6 tree
-+
-+config ADC_BATTERY
-+      tristate "Generic ADC battery driver"
-+      depends on ADC && POWER_SUPPLY
-+      help
-+        Say Y here to enable support for battery monitoring using generic ADC device.
-+
-+config IPAQ_MICRO_BATTERY
-+      tristate "HP iPAQ Micro ASIC battery driver"
-+      depends on IPAQ_MICRO && POWER_SUPPLY
-+      help
-+        Choose this option if you want to monitor battery status on
-+        Compaq/HP iPAQ h3100 h3600
-+
-+config MCP_UCB1x00_SIMPAD_BATTERY
-+      tristate "SIMpad Battery Reading Support"
-+      depends on MCP_UCB1x00 && POWER_SUPPLY
-+
-+endif # POWER_SUPPLY
-Index: linux-2.6.22/drivers/power/Makefile
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/Makefile        2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,28 @@
-+power_supply-objs := power_supply_core.o
-+
-+ifeq ($(CONFIG_SYSFS),y)
-+power_supply-objs += power_supply_sysfs.o
-+endif
-+
-+ifeq ($(CONFIG_LEDS_TRIGGERS),y)
-+power_supply-objs += power_supply_leds.o
-+endif
-+
-+ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y)
-+EXTRA_CFLAGS += -DDEBUG
-+endif
-+
-+obj-$(CONFIG_POWER_SUPPLY)         += power_supply.o
-+
-+obj-$(CONFIG_PDA_POWER)            += pda_power.o
-+obj-$(CONFIG_APM_POWER)            += apm_power.o
-+
-+obj-$(CONFIG_BATTERY_DS2760)       += ds2760_battery.o
-+obj-$(CONFIG_BATTERY_PMU)          += pmu_battery.o
-+obj-$(CONFIG_BATTERY_OLPC)         += olpc_battery.o
-+
-+# drivers below are not in battery2-2.6 tree
-+
-+obj-$(CONFIG_ADC_BATTERY)          += adc_battery.o
-+obj-$(CONFIG_IPAQ_MICRO_BATTERY)   += micro_battery.o
-+obj-$(CONFIG_MCP_UCB1x00_SIMPAD_BATTERY) += simpad-battery.o
-Index: linux-2.6.22/drivers/power/micro_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/micro_battery.c 2007-08-23 12:25:20.000000000 +0200
-@@ -0,0 +1,257 @@
-+/*
-+ * 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.
-+ *
-+ * h3600 atmel micro companion support, battery subdevice
-+ * based on previous kernel 2.4 version
-+ * Author : Alessandro Gardich <gremlin@gremlin.it>
-+ *
-+ */
-+
-+
-+#include <linux/module.h>
-+#include <linux/version.h>
-+
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/pm.h>
-+#include <linux/sysctl.h>
-+#include <linux/proc_fs.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/power_supply.h>
-+#include <linux/platform_device.h>
-+#include <linux/timer.h>
-+
-+#include <asm/arch/hardware.h>
-+
-+#include <asm/arch/h3600.h>
-+#include <asm/arch/SA-1100.h>
-+
-+#include <asm/hardware/micro.h>
-+
-+#define BATT_PERIOD 10*HZ
-+
-+#define H3600_BATT_STATUS_HIGH         0x01
-+#define H3600_BATT_STATUS_LOW          0x02
-+#define H3600_BATT_STATUS_CRITICAL     0x04
-+#define H3600_BATT_STATUS_CHARGING     0x08
-+#define H3600_BATT_STATUS_CHARGEMAIN   0x10
-+#define H3600_BATT_STATUS_DEAD         0x20 /* Battery will not charge */
-+#define H3600_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */
-+#define H3600_BATT_STATUS_FULL         0x40 /* Battery fully charged (and connected to AC) */
-+#define H3600_BATT_STATUS_NOBATTERY    0x80
-+#define H3600_BATT_STATUS_UNKNOWN      0xff
-+
-+
-+//static struct power_supply_dev *micro_battery;
-+
-+static micro_private_t *p_micro;
-+
-+struct timer_list batt_timer;
-+
-+struct {
-+      int ac;
-+      int update_time;
-+      int chemistry;
-+      int voltage;
-+      int temperature;
-+      int flag;
-+} micro_battery;
-+
-+static void micro_battery_receive (int len, unsigned char *data) {
-+      if (0) {
-+              printk(KERN_ERR "h3600_battery - AC = %02x\n", data[0]);
-+              printk(KERN_ERR "h3600_battery - BAT1 chemistry = %02x\n", data[1]);
-+              printk(KERN_ERR "h3600_battery - BAT1 voltage = %d %02x%02x\n", (data[3]<<8)+data[2], data[2], data[3]);
-+              printk(KERN_ERR "h3600_battery - BAT1 status = %02x\n", data[4]);
-+      }
-+
-+      micro_battery.ac = data[0];
-+      micro_battery.chemistry = data[1];
-+      micro_battery.voltage = ((((unsigned short)data[3]<<8)+data[2]) * 5000L ) * 1000 / 1024;
-+      micro_battery.flag = data[4];
-+
-+      if (len == 9) {
-+              if (0) {
-+                      printk(KERN_ERR "h3600_battery - BAT2 chemistry = %02x\n", data[5]);
-+                      printk(KERN_ERR "h3600_battery - BAT2 voltage = %d %02x%02x\n", (data[7]<<8)+data[6], data[6], data[7]);
-+                      printk(KERN_ERR "h3600_battery - BAT2 status = %02x\n", data[8]);
-+              }
-+      }
-+}
-+
-+static void micro_temperature_receive (int len, unsigned char *data) {
-+      micro_battery.temperature = ((unsigned short)data[1]<<8)+data[0];
-+}
-+
-+void h3600_battery_read_status(unsigned long data) {
-+
-+      if (++data % 2)
-+              h3600_micro_tx_msg(0x09,0,NULL);
-+      else
-+              h3600_micro_tx_msg(0x06,0,NULL);
-+
-+      batt_timer.expires += BATT_PERIOD;
-+      batt_timer.data = data;
-+
-+      add_timer(&batt_timer);
-+}
-+
-+int get_capacity(struct power_supply *b) {
-+    switch (micro_battery.flag) {
-+    case H3600_BATT_STATUS_HIGH :     return 100; break;
-+    case H3600_BATT_STATUS_LOW :      return 50; break;
-+    case H3600_BATT_STATUS_CRITICAL : return 5; break;
-+    default: break;
-+    }
-+    return 0;
-+}
-+
-+int get_status(struct power_supply *b) {
-+
-+   if (micro_battery.flag == H3600_BATT_STATUS_UNKNOWN)
-+      return POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+   if (micro_battery.flag & H3600_BATT_STATUS_FULL)
-+      return POWER_SUPPLY_STATUS_FULL;
-+
-+   if ((micro_battery.flag & H3600_BATT_STATUS_CHARGING) ||
-+       (micro_battery.flag & H3600_BATT_STATUS_CHARGEMAIN))
-+      return POWER_SUPPLY_STATUS_CHARGING;
-+
-+   return POWER_SUPPLY_STATUS_DISCHARGING;
-+}
-+
-+static int micro_batt_get_property(struct power_supply *b,
-+                                   enum power_supply_property psp,
-+                                   union power_supply_propval *val)
-+{
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              val->intval = get_status(b);
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-+              val->intval = 4700000;
-+              break;
-+      case POWER_SUPPLY_PROP_CAPACITY:
-+              val->intval = get_capacity(b);
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = micro_battery.temperature;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+              val->intval = micro_battery.voltage;
-+              break;
-+      default:
-+              return -EINVAL;
-+      };
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property micro_batt_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+      POWER_SUPPLY_PROP_CAPACITY,
-+      POWER_SUPPLY_PROP_TEMP,
-+      POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+};
-+
-+static struct power_supply h3600_battery = {
-+      .name               = "main-battery",
-+      .properties         = micro_batt_props,
-+      .num_properties     = ARRAY_SIZE(micro_batt_props),
-+      .get_property       = micro_batt_get_property,
-+      .use_for_apm        = 1,
-+};
-+
-+static int micro_batt_probe (struct platform_device *pdev)
-+{
-+      if (1) printk(KERN_ERR "micro battery probe : begin\n");
-+
-+      power_supply_register(&pdev->dev, &h3600_battery);
-+
-+      { /*--- callback ---*/
-+              p_micro = platform_get_drvdata(pdev);
-+              spin_lock(p_micro->lock);
-+              p_micro->h_batt = micro_battery_receive;
-+              p_micro->h_temp = micro_temperature_receive;
-+              spin_unlock(p_micro->lock);
-+      }
-+
-+      { /*--- timer ---*/
-+              init_timer(&batt_timer);
-+              batt_timer.expires = jiffies + BATT_PERIOD;
-+              batt_timer.data = 0;
-+              batt_timer.function = h3600_battery_read_status;
-+
-+              add_timer(&batt_timer);
-+      }
-+
-+      if (1) printk(KERN_ERR "micro battery probe : end\n");
-+      return 0;
-+}
-+
-+static int micro_batt_remove (struct platform_device *pdev)
-+{
-+      power_supply_unregister(&h3600_battery);
-+      { /*--- callback ---*/
-+              init_timer(&batt_timer);
-+              p_micro->h_batt = NULL;
-+              p_micro->h_temp = NULL;
-+              spin_unlock(p_micro->lock);
-+      }
-+      { /*--- timer ---*/
-+              del_timer_sync(&batt_timer);
-+      }
-+        return 0;
-+}
-+
-+static int micro_batt_suspend ( struct platform_device *pdev, pm_message_t state)
-+{
-+      { /*--- timer ---*/
-+              del_timer(&batt_timer);
-+      }
-+      return 0;
-+}
-+
-+static int micro_batt_resume ( struct platform_device *pdev)
-+{
-+      { /*--- timer ---*/
-+              add_timer(&batt_timer);
-+      }
-+      return 0;
-+}
-+
-+struct platform_driver micro_batt_device_driver = {
-+      .driver  = {
-+              .name    = "h3600-micro-battery",
-+      },
-+      .probe   = micro_batt_probe,
-+      .remove  = micro_batt_remove,
-+      .suspend = micro_batt_suspend,
-+      .resume  = micro_batt_resume,
-+};
-+
-+static int micro_batt_init (void)
-+{
-+      return platform_driver_register(&micro_batt_device_driver);
-+}
-+
-+static void micro_batt_cleanup (void)
-+{
-+      platform_driver_unregister (&micro_batt_device_driver);
-+}
-+
-+module_init (micro_batt_init);
-+module_exit (micro_batt_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("gremlin.it");
-+MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery");
-+
-+
-Index: linux-2.6.22/drivers/power/olpc_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/olpc_battery.c  2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,302 @@
-+/*
-+ * Battery driver for One Laptop Per Child board.
-+ *
-+ *    Copyright Â© 2006  David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * 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/module.h>
-+#include <linux/err.h>
-+#include <linux/platform_device.h>
-+#include <linux/power_supply.h>
-+#include <linux/jiffies.h>
-+#include <linux/sched.h>
-+#include <asm/io.h>
-+
-+#define wBAT_VOLTAGE     0xf900  /* *9.76/32,    mV   */
-+#define wBAT_CURRENT     0xf902  /* *15.625/120, mA   */
-+#define wBAT_TEMP        0xf906  /* *256/1000,   Â°C  */
-+#define wAMB_TEMP        0xf908  /* *256/1000,   Â°C  */
-+#define SOC              0xf910  /* percentage        */
-+#define sMBAT_STATUS     0xfaa4
-+#define sBAT_PRESENT          1
-+#define sBAT_FULL             2
-+#define sBAT_DESTROY          4  /* what is this exactly? */
-+#define sBAT_LOW             32
-+#define sBAT_DISCHG          64
-+#define sMCHARGE_STATUS  0xfaa5
-+#define sBAT_CHARGE           1
-+#define sBAT_OVERTEMP         4
-+#define sBAT_NiMH             8
-+#define sPOWER_FLAG      0xfa40
-+#define ADAPTER_IN            1
-+
-+/*********************************************************************
-+ *            EC locking and access
-+ *********************************************************************/
-+
-+static int lock_ec(void)
-+{
-+      unsigned long timeo = jiffies + HZ / 20;
-+
-+      while (1) {
-+              unsigned char lock = inb(0x6c) & 0x80;
-+              if (!lock)
-+                      return 0;
-+              if (time_after(jiffies, timeo)) {
-+                      printk(KERN_ERR "olpc_battery: failed to lock EC for "
-+                             "battery access\n");
-+                      return 1;
-+              }
-+              yield();
-+      }
-+}
-+
-+static void unlock_ec(void)
-+{
-+      outb(0xff, 0x6c);
-+      return;
-+}
-+
-+static unsigned char read_ec_byte(unsigned short adr)
-+{
-+      outb(adr >> 8, 0x381);
-+      outb(adr, 0x382);
-+      return inb(0x383);
-+}
-+
-+static unsigned short read_ec_word(unsigned short adr)
-+{
-+      return (read_ec_byte(adr) << 8) | read_ec_byte(adr + 1);
-+}
-+
-+/*********************************************************************
-+ *            Power
-+ *********************************************************************/
-+
-+static int olpc_ac_get_prop(struct power_supply *psy,
-+                            enum power_supply_property psp,
-+                            union power_supply_propval *val)
-+{
-+      int ret = 0;
-+
-+      if (lock_ec())
-+              return -EIO;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_ONLINE:
-+              if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
-+                      ret = -ENODEV;
-+                      goto out;
-+              }
-+              val->intval = !!(read_ec_byte(sPOWER_FLAG) & ADAPTER_IN);
-+              break;
-+      default:
-+              ret = -EINVAL;
-+              break;
-+      }
-+out:
-+      unlock_ec();
-+      return ret;
-+}
-+
-+static enum power_supply_property olpc_ac_props[] = {
-+      POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static struct power_supply olpc_ac = {
-+      .name = "olpc-ac",
-+      .type = POWER_SUPPLY_TYPE_MAINS,
-+      .properties = olpc_ac_props,
-+      .num_properties = ARRAY_SIZE(olpc_ac_props),
-+      .get_property = olpc_ac_get_prop,
-+};
-+
-+/*********************************************************************
-+ *            Battery properties
-+ *********************************************************************/
-+
-+static int olpc_bat_get_property(struct power_supply *psy,
-+                                 enum power_supply_property psp,
-+                                 union power_supply_propval *val)
-+{
-+      int ret = 0;
-+
-+      if (lock_ec())
-+              return -EIO;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              {
-+                      int status = POWER_SUPPLY_STATUS_UNKNOWN;
-+
-+                      val->intval = read_ec_byte(sMBAT_STATUS);
-+
-+                      if (!(val->intval & sBAT_PRESENT)) {
-+                              ret = -ENODEV;
-+                              goto out;
-+                      }
-+
-+                      if (val->intval & sBAT_DISCHG)
-+                              status = POWER_SUPPLY_STATUS_DISCHARGING;
-+                      else if (val->intval & sBAT_FULL)
-+                              status = POWER_SUPPLY_STATUS_FULL;
-+
-+                      val->intval = read_ec_byte(sMCHARGE_STATUS);
-+                      if (val->intval & sBAT_CHARGE)
-+                              status = POWER_SUPPLY_STATUS_CHARGING;
-+
-+                      val->intval = status;
-+                      break;
-+              }
-+      case POWER_SUPPLY_PROP_PRESENT:
-+              val->intval = !!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT);
-+              break;
-+      case POWER_SUPPLY_PROP_HEALTH:
-+              val->intval = read_ec_byte(sMCHARGE_STATUS);
-+              if (val->intval & sBAT_OVERTEMP)
-+                      val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
-+              else
-+                      val->intval = POWER_SUPPLY_HEALTH_GOOD;
-+              break;
-+      case POWER_SUPPLY_PROP_TECHNOLOGY:
-+              val->intval = read_ec_byte(sMCHARGE_STATUS);
-+              if (val->intval & sBAT_NiMH)
-+                      val->intval = POWER_SUPPLY_TECHNOLOGY_NIMH;
-+              else
-+                      val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_AVG:
-+              val->intval = read_ec_byte(wBAT_VOLTAGE) * 9760L / 32;
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_AVG:
-+              val->intval = read_ec_byte(wBAT_CURRENT) * 15625L / 120;
-+              break;
-+      case POWER_SUPPLY_PROP_CAPACITY:
-+              val->intval = read_ec_byte(SOC);
-+              break;
-+      case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
-+              val->intval = read_ec_byte(sMBAT_STATUS);
-+              if (val->intval & sBAT_FULL)
-+                      val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-+              else if (val->intval & sBAT_LOW)
-+                      val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
-+              else
-+                      val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP:
-+              val->intval = read_ec_byte(wBAT_TEMP) * 256 / 100;
-+              break;
-+      case POWER_SUPPLY_PROP_TEMP_AMBIENT:
-+              val->intval = read_ec_byte(wAMB_TEMP) * 256 / 100;
-+              break;
-+      default:
-+              ret = -EINVAL;
-+              break;
-+      }
-+
-+out:
-+      unlock_ec();
-+      return ret;
-+}
-+
-+static enum power_supply_property olpc_bat_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_PRESENT,
-+      POWER_SUPPLY_PROP_HEALTH,
-+      POWER_SUPPLY_PROP_TECHNOLOGY,
-+      POWER_SUPPLY_PROP_VOLTAGE_AVG,
-+      POWER_SUPPLY_PROP_CURRENT_AVG,
-+      POWER_SUPPLY_PROP_CAPACITY,
-+      POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-+      POWER_SUPPLY_PROP_TEMP,
-+      POWER_SUPPLY_PROP_TEMP_AMBIENT,
-+};
-+
-+/*********************************************************************
-+ *            Initialisation
-+ *********************************************************************/
-+
-+static struct platform_device *bat_pdev;
-+
-+static struct power_supply olpc_bat = {
-+      .properties = olpc_bat_props,
-+      .num_properties = ARRAY_SIZE(olpc_bat_props),
-+      .get_property = olpc_bat_get_property,
-+      .use_for_apm = 1,
-+};
-+
-+static int __init olpc_bat_init(void)
-+{
-+      int ret = 0;
-+      unsigned short tmp;
-+
-+      if (!request_region(0x380, 4, "olpc-battery")) {
-+              ret = -EIO;
-+              goto region_failed;
-+      }
-+
-+      if (lock_ec()) {
-+              ret = -EIO;
-+              goto lock_failed;
-+      }
-+
-+      tmp = read_ec_word(0xfe92);
-+      unlock_ec();
-+
-+      if (tmp != 0x380) {
-+              /* Doesn't look like OLPC EC */
-+              ret = -ENODEV;
-+              goto not_olpc_ec;
-+      }
-+
-+      bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
-+      if (IS_ERR(bat_pdev)) {
-+              ret = PTR_ERR(bat_pdev);
-+              goto pdev_failed;
-+      }
-+
-+      ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
-+      if (ret)
-+              goto ac_failed;
-+
-+      olpc_bat.name = bat_pdev->name;
-+
-+      ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
-+      if (ret)
-+              goto battery_failed;
-+
-+      goto success;
-+
-+battery_failed:
-+      power_supply_unregister(&olpc_ac);
-+ac_failed:
-+      platform_device_unregister(bat_pdev);
-+pdev_failed:
-+not_olpc_ec:
-+lock_failed:
-+      release_region(0x380, 4);
-+region_failed:
-+success:
-+      return ret;
-+}
-+
-+static void __exit olpc_bat_exit(void)
-+{
-+      power_supply_unregister(&olpc_bat);
-+      power_supply_unregister(&olpc_ac);
-+      platform_device_unregister(bat_pdev);
-+      release_region(0x380, 4);
-+      return;
-+}
-+
-+module_init(olpc_bat_init);
-+module_exit(olpc_bat_exit);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Battery driver for One Laptop Per Child "
-+                   "($100 laptop) board.");
-Index: linux-2.6.22/drivers/power/pda_power.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/pda_power.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,263 @@
-+/*
-+ * Common power driver for PDAs and phones with one or two external
-+ * power supplies (AC/USB) connected to main and backup batteries,
-+ * and optional builtin charger.
-+ *
-+ * Copyright 2007 Anton Vorontsov <cbou@mail.ru>
-+ *
-+ * 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/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/interrupt.h>
-+#include <linux/power_supply.h>
-+#include <linux/pda_power.h>
-+#include <linux/timer.h>
-+#include <linux/jiffies.h>
-+
-+static inline unsigned int get_irq_flags(struct resource *res)
-+{
-+      unsigned int flags = IRQF_DISABLED | IRQF_SHARED;
-+
-+      flags |= res->flags & IRQF_TRIGGER_MASK;
-+
-+      return flags;
-+}
-+
-+static struct device *dev;
-+static struct pda_power_pdata *pdata;
-+static struct resource *ac_irq, *usb_irq;
-+static struct timer_list charger_timer;
-+static struct timer_list supply_timer;
-+
-+static int pda_power_get_property(struct power_supply *psy,
-+                                  enum power_supply_property psp,
-+                                  union power_supply_propval *val)
-+{
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_ONLINE:
-+              if (psy->type == POWER_SUPPLY_TYPE_MAINS)
-+                      val->intval = pdata->is_ac_online ?
-+                                    pdata->is_ac_online() : 0;
-+              else
-+                      val->intval = pdata->is_usb_online ?
-+                                    pdata->is_usb_online() : 0;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+      return 0;
-+}
-+
-+static enum power_supply_property pda_power_props[] = {
-+      POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static char *pda_power_supplied_to[] = {
-+      "main-battery",
-+      "backup-battery",
-+};
-+
-+static struct power_supply pda_power_supplies[] = {
-+      {
-+              .name = "ac",
-+              .type = POWER_SUPPLY_TYPE_MAINS,
-+              .supplied_to = pda_power_supplied_to,
-+              .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
-+              .properties = pda_power_props,
-+              .num_properties = ARRAY_SIZE(pda_power_props),
-+              .get_property = pda_power_get_property,
-+      },
-+      {
-+              .name = "usb",
-+              .type = POWER_SUPPLY_TYPE_USB,
-+              .supplied_to = pda_power_supplied_to,
-+              .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
-+              .properties = pda_power_props,
-+              .num_properties = ARRAY_SIZE(pda_power_props),
-+              .get_property = pda_power_get_property,
-+      },
-+};
-+
-+static void update_charger(void)
-+{
-+      if (!pdata->set_charge)
-+              return;
-+
-+      if (pdata->is_ac_online && pdata->is_ac_online()) {
-+              dev_dbg(dev, "charger on (AC)\n");
-+              pdata->set_charge(PDA_POWER_CHARGE_AC);
-+      }
-+      else if (pdata->is_usb_online && pdata->is_usb_online()) {
-+              dev_dbg(dev, "charger on (USB)\n");
-+              pdata->set_charge(PDA_POWER_CHARGE_USB);
-+      }
-+      else {
-+              dev_dbg(dev, "charger off\n");
-+              pdata->set_charge(0);
-+      }
-+
-+      return;
-+}
-+
-+static void supply_timer_func(unsigned long irq)
-+{
-+      if (ac_irq && irq == ac_irq->start)
-+              power_supply_changed(&pda_power_supplies[0]);
-+      else if (usb_irq && irq == usb_irq->start)
-+              power_supply_changed(&pda_power_supplies[1]);
-+      return;
-+}
-+
-+static void charger_timer_func(unsigned long irq)
-+{
-+      update_charger();
-+
-+      /* Okay, charger set. Now wait a bit before notifying supplicants,
-+       * charge power should stabilize. */
-+      supply_timer.data = irq;
-+      mod_timer(&supply_timer,
-+                jiffies + msecs_to_jiffies(pdata->wait_for_charger));
-+      return;
-+}
-+
-+static irqreturn_t power_changed_isr(int irq, void *unused)
-+{
-+      /* Wait a bit before reading ac/usb line status and setting charger,
-+       * because ac/usb status readings may lag from irq. */
-+      charger_timer.data = irq;
-+      mod_timer(&charger_timer,
-+                jiffies + msecs_to_jiffies(pdata->wait_for_status));
-+      return IRQ_HANDLED;
-+}
-+
-+static int pda_power_probe(struct platform_device *pdev)
-+{
-+      int ret = 0;
-+
-+      dev = &pdev->dev;
-+
-+      if (pdev->id != -1) {
-+              dev_err(dev, "it's meaningless to register several "
-+                      "pda_powers, use id = -1\n");
-+              ret = -EINVAL;
-+              goto wrongid;
-+      }
-+
-+      pdata = pdev->dev.platform_data;
-+
-+      update_charger();
-+
-+      if (!pdata->wait_for_status)
-+              pdata->wait_for_status = 500;
-+
-+      if (!pdata->wait_for_charger)
-+              pdata->wait_for_charger = 500;
-+
-+      setup_timer(&charger_timer, charger_timer_func, 0);
-+      setup_timer(&supply_timer, supply_timer_func, 0);
-+
-+      ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
-+      usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
-+      if (!ac_irq && !usb_irq) {
-+              dev_err(dev, "no ac/usb irq specified\n");
-+              ret = -ENODEV;
-+              goto noirqs;
-+      }
-+
-+      if (pdata->supplied_to) {
-+              pda_power_supplies[0].supplied_to = pdata->supplied_to;
-+              pda_power_supplies[1].supplied_to = pdata->supplied_to;
-+              pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
-+              pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
-+      }
-+
-+      ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
-+      if (ret) {
-+              dev_err(dev, "failed to register %s power supply\n",
-+                      pda_power_supplies[0].name);
-+              goto supply0_failed;
-+      }
-+
-+      ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
-+      if (ret) {
-+              dev_err(dev, "failed to register %s power supply\n",
-+                      pda_power_supplies[1].name);
-+              goto supply1_failed;
-+      }
-+
-+      if (ac_irq) {
-+              ret = request_irq(ac_irq->start, power_changed_isr,
-+                                get_irq_flags(ac_irq), ac_irq->name,
-+                                &pda_power_supplies[0]);
-+              if (ret) {
-+                      dev_err(dev, "request ac irq failed\n");
-+                      goto ac_irq_failed;
-+              }
-+      }
-+
-+      if (usb_irq) {
-+              ret = request_irq(usb_irq->start, power_changed_isr,
-+                                get_irq_flags(usb_irq), usb_irq->name,
-+                                &pda_power_supplies[1]);
-+              if (ret) {
-+                      dev_err(dev, "request usb irq failed\n");
-+                      goto usb_irq_failed;
-+              }
-+      }
-+
-+      goto success;
-+
-+usb_irq_failed:
-+      if (ac_irq)
-+              free_irq(ac_irq->start, &pda_power_supplies[0]);
-+ac_irq_failed:
-+      power_supply_unregister(&pda_power_supplies[1]);
-+supply1_failed:
-+      power_supply_unregister(&pda_power_supplies[0]);
-+supply0_failed:
-+noirqs:
-+wrongid:
-+success:
-+      return ret;
-+}
-+
-+static int pda_power_remove(struct platform_device *pdev)
-+{
-+      if (usb_irq)
-+              free_irq(usb_irq->start, &pda_power_supplies[1]);
-+      if (ac_irq)
-+              free_irq(ac_irq->start, &pda_power_supplies[0]);
-+      del_timer_sync(&charger_timer);
-+      del_timer_sync(&supply_timer);
-+      power_supply_unregister(&pda_power_supplies[1]);
-+      power_supply_unregister(&pda_power_supplies[0]);
-+      return 0;
-+}
-+
-+static struct platform_driver pda_power_pdrv = {
-+      .driver = {
-+              .name = "pda-power",
-+      },
-+      .probe = pda_power_probe,
-+      .remove = pda_power_remove,
-+};
-+
-+static int __init pda_power_init(void)
-+{
-+      return platform_driver_register(&pda_power_pdrv);
-+}
-+
-+static void __exit pda_power_exit(void)
-+{
-+      platform_driver_unregister(&pda_power_pdrv);
-+      return;
-+}
-+
-+module_init(pda_power_init);
-+module_exit(pda_power_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
-Index: linux-2.6.22/drivers/power/pmu_battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/pmu_battery.c   2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,215 @@
-+/*
-+ * Battery class driver for Apple PMU
-+ *
-+ *    Copyright Â© 2006  David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * 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/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/power_supply.h>
-+#include <linux/adb.h>
-+#include <linux/pmu.h>
-+
-+static struct pmu_battery_dev {
-+      struct power_supply bat;
-+      struct pmu_battery_info *pbi;
-+      char name[16];
-+      int propval;
-+} *pbats[PMU_MAX_BATTERIES];
-+
-+#define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
-+
-+/*********************************************************************
-+ *            Power
-+ *********************************************************************/
-+
-+static int pmu_get_ac_prop(struct power_supply *psy,
-+                           enum power_supply_property psp,
-+                           union power_supply_propval *val)
-+{
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_ONLINE:
-+              val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
-+                            (pmu_battery_count == 0);
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property pmu_ac_props[] = {
-+      POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static struct power_supply pmu_ac = {
-+      .name = "pmu-ac",
-+      .type = POWER_SUPPLY_TYPE_MAINS,
-+      .properties = pmu_ac_props,
-+      .num_properties = ARRAY_SIZE(pmu_ac_props),
-+      .get_property = pmu_get_ac_prop,
-+};
-+
-+/*********************************************************************
-+ *            Battery properties
-+ *********************************************************************/
-+
-+static char *pmu_batt_types[] = {
-+      "Smart", "Comet", "Hooper", "Unknown"
-+};
-+
-+static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
-+{
-+      switch (pbi->flags & PMU_BATT_TYPE_MASK) {
-+      case PMU_BATT_TYPE_SMART:
-+              return pmu_batt_types[0];
-+      case PMU_BATT_TYPE_COMET:
-+              return pmu_batt_types[1];
-+      case PMU_BATT_TYPE_HOOPER:
-+              return pmu_batt_types[2];
-+      default: break;
-+      }
-+      return pmu_batt_types[3];
-+}
-+
-+static int pmu_bat_get_property(struct power_supply *psy,
-+                                enum power_supply_property psp,
-+                                union power_supply_propval *val)
-+{
-+      struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
-+      struct pmu_battery_info *pbi = pbat->pbi;
-+
-+      switch (psp) {
-+      case POWER_SUPPLY_PROP_STATUS:
-+              if (pbi->flags & PMU_BATT_CHARGING)
-+                      val->intval = POWER_SUPPLY_STATUS_CHARGING;
-+              else
-+                      val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-+              break;
-+      case POWER_SUPPLY_PROP_PRESENT:
-+              val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
-+              break;
-+      case POWER_SUPPLY_PROP_MODEL_NAME:
-+              val->strval = pmu_bat_get_model_name(pbi);
-+              break;
-+      case POWER_SUPPLY_PROP_ENERGY_AVG:
-+              val->intval = pbi->charge     * 1000; /* mWh -> ÂµWh */
-+              break;
-+      case POWER_SUPPLY_PROP_ENERGY_FULL:
-+              val->intval = pbi->max_charge * 1000; /* mWh -> ÂµWh */
-+              break;
-+      case POWER_SUPPLY_PROP_CURRENT_AVG:
-+              val->intval = pbi->amperage   * 1000; /* mA -> ÂµA */
-+              break;
-+      case POWER_SUPPLY_PROP_VOLTAGE_AVG:
-+              val->intval = pbi->voltage    * 1000; /* mV -> ÂµV */
-+              break;
-+      case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
-+              val->intval = pbi->time_remaining;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static enum power_supply_property pmu_bat_props[] = {
-+      POWER_SUPPLY_PROP_STATUS,
-+      POWER_SUPPLY_PROP_PRESENT,
-+      POWER_SUPPLY_PROP_MODEL_NAME,
-+      POWER_SUPPLY_PROP_ENERGY_AVG,
-+      POWER_SUPPLY_PROP_ENERGY_FULL,
-+      POWER_SUPPLY_PROP_CURRENT_AVG,
-+      POWER_SUPPLY_PROP_VOLTAGE_AVG,
-+      POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
-+};
-+
-+/*********************************************************************
-+ *            Initialisation
-+ *********************************************************************/
-+
-+static struct platform_device *bat_pdev;
-+
-+static int __init pmu_bat_init(void)
-+{
-+      int ret;
-+      int i;
-+
-+      bat_pdev = platform_device_register_simple("pmu-battery",
-+                                                 0, NULL, 0);
-+      if (IS_ERR(bat_pdev)) {
-+              ret = PTR_ERR(bat_pdev);
-+              goto pdev_register_failed;
-+      }
-+
-+      ret = power_supply_register(&bat_pdev->dev, &pmu_ac);
-+      if (ret)
-+              goto ac_register_failed;
-+
-+      for (i = 0; i < pmu_battery_count; i++) {
-+              struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
-+                                                     GFP_KERNEL);
-+              if (!pbat)
-+                      break;
-+
-+              sprintf(pbat->name, "PMU battery %d", i);
-+              pbat->bat.name = pbat->name;
-+              pbat->bat.properties = pmu_bat_props;
-+              pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
-+              pbat->bat.get_property = pmu_bat_get_property;
-+              pbat->pbi = &pmu_batteries[i];
-+
-+              ret = power_supply_register(&bat_pdev->dev, &pbat->bat);
-+              if (ret) {
-+                      kfree(pbat);
-+                      goto battery_register_failed;
-+              }
-+              pbats[i] = pbat;
-+      }
-+
-+      goto success;
-+
-+battery_register_failed:
-+      while (i--) {
-+              if (!pbats[i])
-+                      continue;
-+              power_supply_unregister(&pbats[i]->bat);
-+              kfree(pbats[i]);
-+      }
-+      power_supply_unregister(&pmu_ac);
-+ac_register_failed:
-+      platform_device_unregister(bat_pdev);
-+pdev_register_failed:
-+success:
-+      return ret;
-+}
-+
-+static void __exit pmu_bat_exit(void)
-+{
-+      int i;
-+
-+      for (i = 0; i < PMU_MAX_BATTERIES; i++) {
-+              if (!pbats[i])
-+                      continue;
-+              power_supply_unregister(&pbats[i]->bat);
-+              kfree(pbats[i]);
-+      }
-+      power_supply_unregister(&pmu_ac);
-+      platform_device_unregister(bat_pdev);
-+
-+      return;
-+}
-+
-+module_init(pmu_bat_init);
-+module_exit(pmu_bat_exit);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("PMU battery driver");
-Index: linux-2.6.22/drivers/power/power_supply_core.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply_core.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,168 @@
-+/*
-+ *  Universal power supply monitor class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/err.h>
-+#include <linux/power_supply.h>
-+#include "power_supply.h"
-+
-+struct class *power_supply_class;
-+
-+static void power_supply_changed_work(struct work_struct *work)
-+{
-+      struct power_supply *psy = container_of(work, struct power_supply,
-+                                              changed_work);
-+      int i;
-+
-+      dev_dbg(psy->dev, "%s\n", __FUNCTION__);
-+
-+      for (i = 0; i < psy->num_supplicants; i++) {
-+              struct device *dev;
-+
-+              down(&power_supply_class->sem);
-+              list_for_each_entry(dev, &power_supply_class->devices, node) {
-+                      struct power_supply *pst = dev_get_drvdata(dev);
-+
-+                      if (!strcmp(psy->supplied_to[i], pst->name)) {
-+                              if (pst->external_power_changed)
-+                                      pst->external_power_changed(pst);
-+                      }
-+              }
-+              up(&power_supply_class->sem);
-+      }
-+
-+      power_supply_update_leds(psy);
-+
-+      kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
-+
-+      return;
-+}
-+
-+void power_supply_changed(struct power_supply *psy)
-+{
-+      dev_dbg(psy->dev, "%s\n", __FUNCTION__);
-+
-+      schedule_work(&psy->changed_work);
-+
-+      return;
-+}
-+
-+int power_supply_am_i_supplied(struct power_supply *psy)
-+{
-+      union power_supply_propval ret = {0,};
-+      struct device *dev;
-+
-+      down(&power_supply_class->sem);
-+      list_for_each_entry(dev, &power_supply_class->devices, node) {
-+              struct power_supply *epsy = dev_get_drvdata(dev);
-+              int i;
-+
-+              for (i = 0; i < epsy->num_supplicants; i++) {
-+                      if (!strcmp(epsy->supplied_to[i], psy->name)) {
-+                              if (epsy->get_property(epsy,
-+                                        POWER_SUPPLY_PROP_ONLINE, &ret))
-+                                      continue;
-+                              if (ret.intval)
-+                                      goto out;
-+                      }
-+              }
-+      }
-+out:
-+      up(&power_supply_class->sem);
-+
-+      dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
-+
-+      return ret.intval;
-+}
-+
-+int power_supply_register(struct device *parent, struct power_supply *psy)
-+{
-+      int rc = 0;
-+
-+      psy->dev = device_create(power_supply_class, parent, 0,
-+                               "%s", psy->name);
-+      if (IS_ERR(psy->dev)) {
-+              rc = PTR_ERR(psy->dev);
-+              goto dev_create_failed;
-+      }
-+
-+      dev_set_drvdata(psy->dev, psy);
-+
-+      INIT_WORK(&psy->changed_work, power_supply_changed_work);
-+
-+      rc = power_supply_create_attrs(psy);
-+      if (rc)
-+              goto create_attrs_failed;
-+
-+      rc = power_supply_create_triggers(psy);
-+      if (rc)
-+              goto create_triggers_failed;
-+
-+      power_supply_changed(psy);
-+
-+      goto success;
-+
-+create_triggers_failed:
-+      power_supply_remove_attrs(psy);
-+create_attrs_failed:
-+      device_unregister(psy->dev);
-+dev_create_failed:
-+success:
-+      return rc;
-+}
-+
-+void power_supply_unregister(struct power_supply *psy)
-+{
-+      flush_scheduled_work();
-+      power_supply_remove_triggers(psy);
-+      power_supply_remove_attrs(psy);
-+      device_unregister(psy->dev);
-+      return;
-+}
-+
-+static int __init power_supply_class_init(void)
-+{
-+      power_supply_class = class_create(THIS_MODULE, "power_supply");
-+
-+      if (IS_ERR(power_supply_class))
-+              return PTR_ERR(power_supply_class);
-+
-+      power_supply_class->dev_uevent = power_supply_uevent;
-+
-+      return 0;
-+}
-+
-+static void __exit power_supply_class_exit(void)
-+{
-+      class_destroy(power_supply_class);
-+      return;
-+}
-+
-+EXPORT_SYMBOL_GPL(power_supply_changed);
-+EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
-+EXPORT_SYMBOL_GPL(power_supply_register);
-+EXPORT_SYMBOL_GPL(power_supply_unregister);
-+
-+/* exported for the APM Power driver, APM emulation */
-+EXPORT_SYMBOL_GPL(power_supply_class);
-+
-+subsys_initcall(power_supply_class_init);
-+module_exit(power_supply_class_exit);
-+
-+MODULE_DESCRIPTION("Universal power supply monitor class");
-+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
-+              "Szabolcs Gyurko, "
-+              "Anton Vorontsov <cbou@mail.ru>");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/drivers/power/power_supply.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply.h  2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,42 @@
-+/*
-+ *  Functions private to power supply class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#ifdef CONFIG_SYSFS
-+
-+extern int power_supply_create_attrs(struct power_supply *psy);
-+extern void power_supply_remove_attrs(struct power_supply *psy);
-+extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-+                               char *buffer, int buffer_size);
-+
-+#else
-+
-+static inline int power_supply_create_attrs(struct power_supply *psy)
-+{ return 0; }
-+static inline void power_supply_remove_attrs(struct power_supply *psy) {}
-+#define power_supply_uevent NULL
-+
-+#endif /* CONFIG_SYSFS */
-+
-+#ifdef CONFIG_LEDS_TRIGGERS
-+
-+extern void power_supply_update_leds(struct power_supply *psy);
-+extern int power_supply_create_triggers(struct power_supply *psy);
-+extern void power_supply_remove_triggers(struct power_supply *psy);
-+
-+#else
-+
-+static inline void power_supply_update_leds(struct power_supply *psy) {}
-+static inline int power_supply_create_triggers(struct power_supply *psy)
-+{ return 0; }
-+static inline void power_supply_remove_triggers(struct power_supply *psy) {}
-+
-+#endif /* CONFIG_LEDS_TRIGGERS */
-Index: linux-2.6.22/drivers/power/power_supply_leds.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply_leds.c     2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,188 @@
-+/*
-+ *  LEDs triggers for power supply class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#include <linux/power_supply.h>
-+
-+/* If we have hwtimer trigger, then use it to blink charging LED */
-+
-+#if defined(CONFIG_LEDS_TRIGGER_HWTIMER) ||                  \
-+               (defined(CONFIG_BATTERY_MODULE) &&            \
-+                defined(CONFIG_LEDS_TRIGGER_HWTIMER_MODULE))
-+       #define led_trigger_register_charging led_trigger_register_hwtimer
-+       #define led_trigger_unregister_charging led_trigger_unregister_hwtimer
-+#else
-+       #define led_trigger_register_charging led_trigger_register_simple
-+       #define led_trigger_unregister_charging led_trigger_unregister_simple
-+#endif
-+
-+/* Battery specific LEDs triggers. */
-+
-+static void power_supply_update_bat_leds(struct power_supply *psy)
-+{
-+      union power_supply_propval status;
-+
-+      if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
-+              return;
-+
-+      dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
-+
-+      switch(status.intval) {
-+      case POWER_SUPPLY_STATUS_FULL:
-+              led_trigger_event(psy->charging_full_trig, LED_FULL);
-+              led_trigger_event(psy->charging_trig, LED_OFF);
-+              led_trigger_event(psy->full_trig, LED_FULL);
-+              break;
-+      case POWER_SUPPLY_STATUS_CHARGING:
-+              led_trigger_event(psy->charging_full_trig, LED_FULL);
-+              led_trigger_event(psy->charging_trig, LED_FULL);
-+              led_trigger_event(psy->full_trig, LED_OFF);
-+              break;
-+      default:
-+              led_trigger_event(psy->charging_full_trig, LED_OFF);
-+              led_trigger_event(psy->charging_trig, LED_OFF);
-+              led_trigger_event(psy->full_trig, LED_OFF);
-+              break;
-+      }
-+
-+      return;
-+}
-+
-+static int power_supply_create_bat_triggers(struct power_supply *psy)
-+{
-+      int rc = 0;
-+
-+      psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
-+                                sizeof("-charging-or-full"), GFP_KERNEL);
-+      if (!psy->charging_full_trig_name)
-+              goto charging_full_failed;
-+
-+      psy->charging_trig_name = kmalloc(strlen(psy->name) +
-+                                        sizeof("-charging"), GFP_KERNEL);
-+      if (!psy->charging_trig_name)
-+              goto charging_failed;
-+
-+      psy->full_trig_name = kmalloc(strlen(psy->name) +
-+                                    sizeof("-full"), GFP_KERNEL);
-+      if (!psy->full_trig_name)
-+              goto full_failed;
-+
-+      strcpy(psy->charging_full_trig_name, psy->name);
-+      strcat(psy->charging_full_trig_name, "-charging-or-full");
-+      strcpy(psy->charging_trig_name, psy->name);
-+      strcat(psy->charging_trig_name, "-charging");
-+      strcpy(psy->full_trig_name, psy->name);
-+      strcat(psy->full_trig_name, "-full");
-+
-+      led_trigger_register_simple(psy->charging_full_trig_name,
-+                                  &psy->charging_full_trig);
-+      led_trigger_register_charging(psy->charging_trig_name,
-+                                    &psy->charging_trig);
-+      led_trigger_register_simple(psy->full_trig_name,
-+                                  &psy->full_trig);
-+
-+      goto success;
-+
-+full_failed:
-+      kfree(psy->charging_trig_name);
-+charging_failed:
-+      kfree(psy->charging_full_trig_name);
-+charging_full_failed:
-+      rc = -ENOMEM;
-+success:
-+      return rc;
-+}
-+
-+static void power_supply_remove_bat_triggers(struct power_supply *psy)
-+{
-+      led_trigger_unregister_simple(psy->charging_full_trig);
-+      led_trigger_unregister_charging(psy->charging_trig);
-+      led_trigger_unregister_simple(psy->full_trig);
-+      kfree(psy->full_trig_name);
-+      kfree(psy->charging_trig_name);
-+      kfree(psy->charging_full_trig_name);
-+      return;
-+}
-+
-+/* Generated power specific LEDs triggers. */
-+
-+static void power_supply_update_gen_leds(struct power_supply *psy)
-+{
-+      union power_supply_propval online;
-+
-+      if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
-+              return;
-+
-+      dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
-+
-+      if (online.intval)
-+              led_trigger_event(psy->online_trig, LED_FULL);
-+      else
-+              led_trigger_event(psy->online_trig, LED_OFF);
-+
-+      return;
-+}
-+
-+static int power_supply_create_gen_triggers(struct power_supply *psy)
-+{
-+      int rc = 0;
-+
-+      psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
-+                                      GFP_KERNEL);
-+      if (!psy->online_trig_name)
-+              goto online_failed;
-+
-+      strcpy(psy->online_trig_name, psy->name);
-+      strcat(psy->online_trig_name, "-online");
-+
-+      led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
-+
-+      goto success;
-+
-+online_failed:
-+      rc = -ENOMEM;
-+success:
-+      return rc;
-+}
-+
-+static void power_supply_remove_gen_triggers(struct power_supply *psy)
-+{
-+      led_trigger_unregister_simple(psy->online_trig);
-+      kfree(psy->online_trig_name);
-+      return;
-+}
-+
-+/* Choice what triggers to create&update. */
-+
-+void power_supply_update_leds(struct power_supply *psy)
-+{
-+      if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
-+              power_supply_update_bat_leds(psy);
-+      else
-+              power_supply_update_gen_leds(psy);
-+      return;
-+}
-+
-+int power_supply_create_triggers(struct power_supply *psy)
-+{
-+      if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
-+              return power_supply_create_bat_triggers(psy);
-+      return power_supply_create_gen_triggers(psy);
-+}
-+
-+void power_supply_remove_triggers(struct power_supply *psy)
-+{
-+      if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
-+              power_supply_remove_bat_triggers(psy);
-+      else
-+              power_supply_remove_gen_triggers(psy);
-+      return;
-+}
-Index: linux-2.6.22/drivers/power/power_supply_sysfs.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/power_supply_sysfs.c    2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,289 @@
-+/*
-+ *  Sysfs interface for the universal power supply monitor class
-+ *
-+ *  Copyright Â©  2007  David Woodhouse <dwmw2@infradead.org>
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#include <linux/ctype.h>
-+#include <linux/power_supply.h>
-+
-+/*
-+ * This is because the name "current" breaks the device attr macro.
-+ * The "current" word resolvs to "(get_current())" so instead of
-+ * "current" "(get_current())" appears in the sysfs.
-+ *
-+ * The source of this definition is the device.h which calls __ATTR
-+ * macro in sysfs.h which calls the __stringify macro.
-+ *
-+ * Only modification that the name is not tried to be resolved
-+ * (as a macro let's say).
-+ */
-+
-+#define POWER_SUPPLY_ATTR(_name)                                        \
-+{                                                                       \
-+      .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \
-+      .show = power_supply_show_property,                             \
-+      .store = NULL,                                                  \
-+}
-+
-+static struct device_attribute power_supply_attrs[];
-+
-+static ssize_t power_supply_show_property(struct device *dev,
-+                                          struct device_attribute *attr,
-+                                          char *buf) {
-+      static char *status_text[] = {
-+              "Unknown", "Charging", "Discharging", "Not charging", "Full"
-+      };
-+      static char *health_text[] = {
-+              "Unknown", "Good", "Overheat", "Dead"
-+      };
-+      static char *technology_text[] = {
-+              "Unknown", "NiMH", "Li-ion", "Li-poly"
-+      };
-+      static char *capacity_level_text[] = {
-+              "Unknown", "Critical", "Low", "Normal", "High", "Full"
-+      };
-+      ssize_t ret;
-+      struct power_supply *psy = dev_get_drvdata(dev);
-+      const ptrdiff_t off = attr - power_supply_attrs;
-+      union power_supply_propval value;
-+
-+      ret = psy->get_property(psy, off, &value);
-+
-+      if (ret < 0) {
-+              dev_err(dev, "driver failed to report `%s' property\n",
-+                      attr->attr.name);
-+              return ret;
-+      }
-+
-+      if (off == POWER_SUPPLY_PROP_STATUS)
-+              return sprintf(buf, "%s\n", status_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_HEALTH)
-+              return sprintf(buf, "%s\n", health_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
-+              return sprintf(buf, "%s\n", technology_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
-+              return sprintf(buf, "%s\n",
-+                             capacity_level_text[value.intval]);
-+      else if (off == POWER_SUPPLY_PROP_MODEL_NAME)
-+              return sprintf(buf, "%s\n", value.strval);
-+
-+      return sprintf(buf, "%d\n", value.intval);
-+}
-+
-+/* Must be in the same order as POWER_SUPPLY_PROP_* */
-+static struct device_attribute power_supply_attrs[] = {
-+      /* Properties of type `int' */
-+      POWER_SUPPLY_ATTR(status),
-+      POWER_SUPPLY_ATTR(health),
-+      POWER_SUPPLY_ATTR(present),
-+      POWER_SUPPLY_ATTR(online),
-+      POWER_SUPPLY_ATTR(technology),
-+      POWER_SUPPLY_ATTR(voltage_max_design),
-+      POWER_SUPPLY_ATTR(voltage_min_design),
-+      POWER_SUPPLY_ATTR(voltage_now),
-+      POWER_SUPPLY_ATTR(voltage_avg),
-+      POWER_SUPPLY_ATTR(current_now),
-+      POWER_SUPPLY_ATTR(current_avg),
-+      POWER_SUPPLY_ATTR(charge_full_design),
-+      POWER_SUPPLY_ATTR(charge_empty_design),
-+      POWER_SUPPLY_ATTR(charge_full),
-+      POWER_SUPPLY_ATTR(charge_empty),
-+      POWER_SUPPLY_ATTR(charge_now),
-+      POWER_SUPPLY_ATTR(charge_avg),
-+      POWER_SUPPLY_ATTR(energy_full_design),
-+      POWER_SUPPLY_ATTR(energy_empty_design),
-+      POWER_SUPPLY_ATTR(energy_full),
-+      POWER_SUPPLY_ATTR(energy_empty),
-+      POWER_SUPPLY_ATTR(energy_now),
-+      POWER_SUPPLY_ATTR(energy_avg),
-+      POWER_SUPPLY_ATTR(capacity),
-+      POWER_SUPPLY_ATTR(capacity_level),
-+      POWER_SUPPLY_ATTR(temp),
-+      POWER_SUPPLY_ATTR(temp_ambient),
-+      POWER_SUPPLY_ATTR(time_to_empty_now),
-+      POWER_SUPPLY_ATTR(time_to_empty_avg),
-+      POWER_SUPPLY_ATTR(time_to_full_now),
-+      POWER_SUPPLY_ATTR(time_to_full_avg),
-+      /* Properties of type `const char *' */
-+      POWER_SUPPLY_ATTR(model_name),
-+};
-+
-+static ssize_t power_supply_show_static_attrs(struct device *dev,
-+                                              struct device_attribute *attr,
-+                                              char *buf) {
-+      static char *type_text[] = { "Battery", "UPS", "Mains", "USB" };
-+      struct power_supply *psy = dev_get_drvdata(dev);
-+
-+      return sprintf(buf, "%s\n", type_text[psy->type]);
-+}
-+
-+static struct device_attribute power_supply_static_attrs[] = {
-+      __ATTR(type, 0444, power_supply_show_static_attrs, NULL),
-+};
-+
-+int power_supply_create_attrs(struct power_supply *psy)
-+{
-+      int rc = 0;
-+      int i, j;
-+
-+      for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
-+              rc = device_create_file(psy->dev,
-+                          &power_supply_static_attrs[i]);
-+              if (rc)
-+                      goto statics_failed;
-+      }
-+
-+      for (j = 0; j < psy->num_properties; j++) {
-+              rc = device_create_file(psy->dev,
-+                          &power_supply_attrs[psy->properties[j]]);
-+              if (rc)
-+                      goto dynamics_failed;
-+      }
-+
-+      goto succeed;
-+
-+dynamics_failed:
-+      while (j--)
-+              device_remove_file(psy->dev,
-+                         &power_supply_attrs[psy->properties[j]]);
-+statics_failed:
-+      while (i--)
-+              device_remove_file(psy->dev,
-+                         &power_supply_static_attrs[psy->properties[i]]);
-+succeed:
-+      return rc;
-+}
-+
-+void power_supply_remove_attrs(struct power_supply *psy)
-+{
-+      int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
-+              device_remove_file(psy->dev,
-+                          &power_supply_static_attrs[i]);
-+
-+      for (i = 0; i < psy->num_properties; i++)
-+              device_remove_file(psy->dev,
-+                          &power_supply_attrs[psy->properties[i]]);
-+
-+      return;
-+}
-+
-+static char *kstruprdup(const char *str, gfp_t gfp)
-+{
-+      char *ret, *ustr;
-+
-+      ustr = ret = kmalloc(strlen(str) + 1, gfp);
-+
-+      if (!ret)
-+              return NULL;
-+
-+      while (*str)
-+              *ustr++ = toupper(*str++);
-+
-+      *ustr = 0;
-+
-+      return ret;
-+}
-+
-+int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-+                        char *buffer, int buffer_size)
-+{
-+      struct power_supply *psy = dev_get_drvdata(dev);
-+      int i = 0, length = 0, ret = 0, j;
-+      char *prop_buf;
-+      char *attrname;
-+
-+      dev_dbg(dev, "uevent\n");
-+
-+      if (!psy) {
-+              dev_dbg(dev, "No power supply yet\n");
-+              return ret;
-+      }
-+
-+      dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
-+
-+      ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                           &length, "POWER_SUPPLY_NAME=%s", psy->name);
-+      if (ret)
-+              return ret;
-+
-+      prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
-+      if (!prop_buf)
-+              return -ENOMEM;
-+
-+      for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
-+              struct device_attribute *attr;
-+              char *line;
-+
-+              attr = &power_supply_static_attrs[j];
-+
-+              ret = power_supply_show_static_attrs(dev, attr, prop_buf);
-+              if (ret < 0)
-+                      goto out;
-+
-+              line = strchr(prop_buf, '\n');
-+              if (line)
-+                      *line = 0;
-+
-+              attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
-+              if (!attrname) {
-+                      ret = -ENOMEM;
-+                      goto out;
-+              }
-+
-+              dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
-+
-+              ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                                   &length, "POWER_SUPPLY_%s=%s",
-+                                   attrname, prop_buf);
-+              kfree(attrname);
-+              if (ret)
-+                      goto out;
-+      }
-+
-+      dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
-+
-+      for (j = 0; j < psy->num_properties; j++) {
-+              struct device_attribute *attr;
-+              char *line;
-+
-+              attr = &power_supply_attrs[psy->properties[j]];
-+
-+              ret = power_supply_show_property(dev, attr, prop_buf);
-+              if (ret < 0)
-+                      goto out;
-+
-+              line = strchr(prop_buf, '\n');
-+              if (line)
-+                      *line = 0;
-+
-+              attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
-+              if (!attrname) {
-+                      ret = -ENOMEM;
-+                      goto out;
-+              }
-+
-+              dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
-+
-+              ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                                   &length, "POWER_SUPPLY_%s=%s",
-+                                   attrname, prop_buf);
-+              kfree(attrname);
-+              if (ret)
-+                      goto out;
-+      }
-+
-+out:
-+      free_page((unsigned long)prop_buf);
-+
-+      return ret;
-+}
-Index: linux-2.6.22/drivers/power/simpad-battery.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/drivers/power/simpad-battery.c        2007-08-23 12:13:52.000000000 +0200
-@@ -0,0 +1,242 @@
-+/*
-+ *  linux/drivers/misc/simpad-battery.c
-+ *
-+ *  Copyright (C) 2005 Holger Hans Peter Freyther
-+ *  Copyright (C) 2001 Juergen Messerer
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is
-+ * unsupported for now.
-+ *
-+ */
-+
-+#include <linux/battery.h>
-+#include <asm/dma.h>
-+#include "ucb1x00.h"
-+
-+
-+/*
-+ * Conversion from AD -> mV
-+ * 7.5V = 1023   7.3313mV/Digit
-+ *
-+ * 400 Units == 9.7V
-+ * a     = ADC value
-+ * 21    = ADC error
-+ * 12600 = Divident to get 2*7.3242
-+ * 860   = Divider to get 2*7.3242
-+ * 170   = Voltagedrop over
-+ */
-+#define CALIBRATE_BATTERY(a)   ((((a + 21)*12600)/860) + 170)
-+
-+/*
-+ * We have two types of batteries a small and a large one
-+ * To get the right value we to distinguish between those two
-+ * 450 Units == 15 V
-+ */
-+#define CALIBRATE_SUPPLY(a)   (((a) * 1500) / 45)
-+#define MIN_SUPPLY            12000 /* Less then 12V means no powersupply */
-+
-+/*
-+ * Charging Current
-+ * if value is >= 50 then charging is on
-+ */
-+#define CALIBRATE_CHARGING(a)    (((a)* 1000)/(152/4)))
-+
-+struct simpad_battery_t {
-+      struct battery  battery;
-+      struct ucb1x00* ucb;
-+
-+        /*
-+       * Variables for the values to one time support
-+       * T-Sinuspad as well
-+       */
-+      int min_voltage;
-+      int min_current;
-+      int min_charge;
-+
-+      int max_voltage;
-+      int max_current;
-+      int max_charge;
-+
-+      int min_supply;
-+      int charging_led_label;
-+      int charging_max_label;
-+      int batt_full;
-+      int batt_low;
-+      int batt_critical;
-+      int batt_empty;
-+};
-+
-+static int simpad_get_min_voltage(struct battery* _battery )
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return  battery->min_voltage;
-+}
-+
-+static int simpad_get_min_current(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->min_current;
-+}
-+
-+static int simpad_get_min_charge(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->min_charge;
-+}
-+
-+static int simpad_get_max_voltage(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->max_voltage;
-+}
-+
-+static int simpad_get_max_current(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->max_current;
-+}
-+
-+static int simpad_get_max_charge(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+      return battery->max_charge;
-+}
-+
-+static int simpad_get_temp(struct battery* _battery)
-+{
-+      return 0;
-+}
-+
-+static int simpad_get_voltage(struct battery* _battery)
-+{
-+      int val;
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+
-+
-+      ucb1x00_adc_enable(battery->ucb);
-+      val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD1, UCB_NOSYNC);
-+      ucb1x00_adc_disable(battery->ucb);
-+
-+      return CALIBRATE_BATTERY(val);
-+}
-+
-+static int simpad_get_current(struct battery* _battery)
-+{
-+      int val;
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+
-+      ucb1x00_adc_enable(battery->ucb);
-+      val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD3, UCB_NOSYNC);
-+      ucb1x00_adc_disable(battery->ucb);
-+
-+      return val;
-+}
-+
-+static int simpad_get_charge(struct battery* _battery)
-+{
-+      int val;
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
-+
-+      ucb1x00_adc_enable(battery->ucb);
-+      val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD2, UCB_NOSYNC);
-+      ucb1x00_adc_disable(battery->ucb);
-+
-+      return CALIBRATE_SUPPLY(val);
-+
-+}
-+
-+static int simpad_get_status(struct battery* _battery)
-+{
-+      struct simpad_battery_t* battery = (struct simpad_battery_t*)(_battery);
-+      int vcharger = simpad_get_voltage(_battery);
-+      int icharger = simpad_get_current(_battery);
-+
-+      int status = BATTERY_STATUS_UNKNOWN;
-+      if(icharger > battery->charging_led_label)
-+              status = BATTERY_STATUS_CHARGING;
-+      else if(vcharger > battery->min_supply)
-+              status = BATTERY_STATUS_NOT_CHARGING;
-+      else
-+              status = BATTERY_STATUS_DISCHARGING;
-+
-+      return status;
-+}
-+
-+static struct simpad_battery_t simpad_battery  = {
-+      .battery = {
-+              .get_min_voltage = simpad_get_min_voltage,
-+              .get_min_current = simpad_get_min_current,
-+              .get_min_charge  = simpad_get_min_charge,
-+              .get_max_voltage = simpad_get_max_voltage,
-+              .get_max_current = simpad_get_max_current,
-+              .get_max_charge  = simpad_get_max_charge,
-+              .get_temp        = simpad_get_temp,
-+              .get_voltage     = simpad_get_voltage,
-+              .get_current     = simpad_get_current,
-+              .get_charge      = simpad_get_charge,
-+              .get_status      = simpad_get_status,
-+      },
-+      .min_voltage = 0,
-+      .min_current = 0,
-+      .min_charge  = 0,
-+      .max_voltage = 0,
-+      .max_current = 0,
-+      .max_charge  = 0,
-+
-+      .min_supply         = 1200,
-+      .charging_led_label = 18,
-+      .charging_max_label = 265,
-+      .batt_full          = 8300,
-+      .batt_low           = 7300,
-+      .batt_critical      = 6800,
-+      .batt_empty         = 6500,
-+};
-+
-+
-+
-+/*
-+ * UCB glue code
-+ */
-+static int ucb1x00_battery_add(struct class_device *dev)
-+{
-+      struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+      simpad_battery.ucb  = ucb;
-+
-+      battery_class_register(&simpad_battery.battery);
-+
-+      return 0;
-+}
-+
-+static void ucb1x00_battery_remove(struct class_device *dev)
-+{
-+      return battery_class_unregister(&simpad_battery.battery);
-+}
-+
-+
-+static struct ucb1x00_class_interface ucb1x00_battery_interface = {
-+      .interface   = {
-+              .add    = ucb1x00_battery_add,
-+              .remove = ucb1x00_battery_remove,
-+      },
-+};
-+
-+
-+static int __init battery_register(void)
-+{
-+      return ucb1x00_register_interface(&ucb1x00_battery_interface);
-+}
-+
-+static void __exit battery_unregister(void)
-+{
-+      ucb1x00_unregister_interface(&ucb1x00_battery_interface);
-+}
-+
-+module_init(battery_register);
-+module_exit(battery_unregister);
-+
-+MODULE_AUTHOR("Holger Hans Peter Freyther");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.22/arch/arm/Kconfig
-===================================================================
---- linux-2.6.22.orig/arch/arm/Kconfig 2007-08-23 12:17:42.000000000 +0200
-+++ linux-2.6.22/arch/arm/Kconfig      2007-08-23 12:22:28.000000000 +0200
-@@ -1016,6 +1016,8 @@
- source "drivers/w1/Kconfig"
-+source "drivers/power/Kconfig"
-+
- source "drivers/hwmon/Kconfig"
- #source "drivers/l3/Kconfig"
-Index: linux-2.6.22/drivers/Kconfig
-===================================================================
---- linux-2.6.22.orig/drivers/Kconfig  2007-08-23 12:21:27.000000000 +0200
-+++ linux-2.6.22/drivers/Kconfig       2007-08-23 12:22:03.000000000 +0200
-@@ -54,6 +54,8 @@
- source "drivers/w1/Kconfig"
-+source "drivers/power/Kconfig"
-+
- source "drivers/hwmon/Kconfig"
- source "drivers/mfd/Kconfig"
-Index: linux-2.6.22/drivers/Makefile
-===================================================================
---- linux-2.6.22.orig/drivers/Makefile 2007-08-23 12:33:58.000000000 +0200
-+++ linux-2.6.22/drivers/Makefile      2007-08-23 12:34:34.000000000 +0200
-@@ -61,6 +61,7 @@
- obj-$(CONFIG_RTC_LIB)         += rtc/
- obj-y                         += i2c/
- obj-$(CONFIG_W1)              += w1/
-+obj-$(CONFIG_POWER_SUPPLY)    += power/
- obj-$(CONFIG_HWMON)           += hwmon/
- obj-$(CONFIG_PHONE)           += telephony/
- obj-$(CONFIG_MD)              += md/
-Index: linux-2.6.22/include/linux/power_supply.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.22/include/linux/power_supply.h  2007-08-23 12:37:10.000000000 +0200
-@@ -0,0 +1,175 @@
-+/*
-+ *  Universal power supply monitor class
-+ *
-+ *  Copyright (c) 2007  Anton Vorontsov <cbou@mail.ru>
-+ *  Copyright (c) 2004  Szabolcs Gyurko
-+ *  Copyright (c) 2003  Ian Molton <spyro@f2s.com>
-+ *
-+ *  Modified: 2004, Oct     Szabolcs Gyurko
-+ *
-+ *  You may use this code as per GPL version 2
-+ */
-+
-+#ifndef __LINUX_POWER_SUPPLY_H__
-+#define __LINUX_POWER_SUPPLY_H__
-+
-+#include <linux/device.h>
-+#include <linux/workqueue.h>
-+#include <linux/leds.h>
-+
-+/*
-+ * All voltages, currents, charges, energies, time and temperatures in uV,
-+ * uA, uAh, uWh, seconds and tenths of degree Celsius unless otherwise
-+ * stated. It's driver's job to convert its raw values to units in which
-+ * this class operates.
-+ */
-+
-+/*
-+ * For systems where the charger determines the maximum battery capacity
-+ * the min and max fields should be used to present these values to user
-+ * space. Unused/unknown fields will not appear in sysfs.
-+ */
-+
-+enum {
-+      POWER_SUPPLY_STATUS_UNKNOWN = 0,
-+      POWER_SUPPLY_STATUS_CHARGING,
-+      POWER_SUPPLY_STATUS_DISCHARGING,
-+      POWER_SUPPLY_STATUS_NOT_CHARGING,
-+      POWER_SUPPLY_STATUS_FULL,
-+};
-+
-+enum {
-+      POWER_SUPPLY_HEALTH_UNKNOWN = 0,
-+      POWER_SUPPLY_HEALTH_GOOD,
-+      POWER_SUPPLY_HEALTH_OVERHEAT,
-+      POWER_SUPPLY_HEALTH_DEAD,
-+};
-+
-+enum {
-+      POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,
-+      POWER_SUPPLY_TECHNOLOGY_NIMH,
-+      POWER_SUPPLY_TECHNOLOGY_LION,
-+      POWER_SUPPLY_TECHNOLOGY_LIPO,
-+};
-+
-+enum {
-+      POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
-+      POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
-+      POWER_SUPPLY_CAPACITY_LEVEL_LOW,
-+      POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
-+      POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
-+      POWER_SUPPLY_CAPACITY_LEVEL_FULL,
-+};
-+
-+enum power_supply_property {
-+      /* Properties of type `int' */
-+      POWER_SUPPLY_PROP_STATUS = 0,
-+      POWER_SUPPLY_PROP_HEALTH,
-+      POWER_SUPPLY_PROP_PRESENT,
-+      POWER_SUPPLY_PROP_ONLINE,
-+      POWER_SUPPLY_PROP_TECHNOLOGY,
-+      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-+      POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+      POWER_SUPPLY_PROP_VOLTAGE_AVG,
-+      POWER_SUPPLY_PROP_CURRENT_NOW,
-+      POWER_SUPPLY_PROP_CURRENT_AVG,
-+      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+      POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
-+      POWER_SUPPLY_PROP_CHARGE_FULL,
-+      POWER_SUPPLY_PROP_CHARGE_EMPTY,
-+      POWER_SUPPLY_PROP_CHARGE_NOW,
-+      POWER_SUPPLY_PROP_CHARGE_AVG,
-+      POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
-+      POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
-+      POWER_SUPPLY_PROP_ENERGY_FULL,
-+      POWER_SUPPLY_PROP_ENERGY_EMPTY,
-+      POWER_SUPPLY_PROP_ENERGY_NOW,
-+      POWER_SUPPLY_PROP_ENERGY_AVG,
-+      POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
-+      POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-+      POWER_SUPPLY_PROP_TEMP,
-+      POWER_SUPPLY_PROP_TEMP_AMBIENT,
-+      POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-+      POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
-+      POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
-+      POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
-+      /* Properties of type `const char *' */
-+      POWER_SUPPLY_PROP_MODEL_NAME,
-+};
-+
-+enum power_supply_type {
-+      POWER_SUPPLY_TYPE_BATTERY = 0,
-+      POWER_SUPPLY_TYPE_UPS,
-+      POWER_SUPPLY_TYPE_MAINS,
-+      POWER_SUPPLY_TYPE_USB,
-+};
-+
-+union power_supply_propval {
-+      int intval;
-+      const char *strval;
-+};
-+
-+struct power_supply {
-+      const char *name;
-+      enum power_supply_type type;
-+      enum power_supply_property *properties;
-+      size_t num_properties;
-+
-+      char **supplied_to;
-+      size_t num_supplicants;
-+
-+      int (*get_property)(struct power_supply *psy,
-+                          enum power_supply_property psp,
-+                          union power_supply_propval *val);
-+      void (*external_power_changed)(struct power_supply *psy);
-+
-+      /* For APM emulation, think legacy userspace. */
-+      int use_for_apm;
-+
-+      /* private */
-+      struct device *dev;
-+      struct work_struct changed_work;
-+
-+#ifdef CONFIG_LEDS_TRIGGERS
-+      struct led_trigger *charging_full_trig;
-+      char *charging_full_trig_name;
-+      struct led_trigger *charging_trig;
-+      char *charging_trig_name;
-+      struct led_trigger *full_trig;
-+      char *full_trig_name;
-+      struct led_trigger *online_trig;
-+      char *online_trig_name;
-+#endif
-+};
-+
-+/*
-+ * This is recommended structure to specify static power supply parameters.
-+ * Generic one, parametrizable for different power supplies. Power supply
-+ * class itself does not use it, but that's what implementing most platform
-+ * drivers, should try reuse for consistency.
-+ */
-+
-+struct power_supply_info {
-+      const char *name;
-+      int technology;
-+      int voltage_max_design;
-+      int voltage_min_design;
-+      int charge_full_design;
-+      int charge_empty_design;
-+      int energy_full_design;
-+      int energy_empty_design;
-+      int use_for_apm;
-+};
-+
-+extern void power_supply_changed(struct power_supply *psy);
-+extern int power_supply_am_i_supplied(struct power_supply *psy);
-+
-+extern int power_supply_register(struct device *parent,
-+                                 struct power_supply *psy);
-+extern void power_supply_unregister(struct power_supply *psy);
-+
-+/* For APM emulation, think legacy userspace. */
-+extern struct class *power_supply_class;
-+
-+#endif /* __LINUX_POWER_SUPPLY_H__ */
diff --git a/meta/packages/linux/linux-rp-2.6.23/versatile-armv6.patch b/meta/packages/linux/linux-rp-2.6.23/versatile-armv6.patch
new file mode 100644 (file)
index 0000000..e2d0060
--- /dev/null
@@ -0,0 +1,19 @@
+---
+ arch/arm/mm/Kconfig |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-2.6.23.orig/arch/arm/mm/Kconfig
++++ linux-2.6.23/arch/arm/mm/Kconfig
+@@ -343,11 +343,11 @@ config CPU_XSC3
+       select IO_36
+ # ARMv6
+ config CPU_V6
+       bool "Support ARM V6 processor"
+-      depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
++      depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_VERSATILE_PB
+       default y if ARCH_MX3
+       select CPU_32v6
+       select CPU_ABRT_EV6
+       select CPU_CACHE_V6
+       select CPU_CACHE_VIPT
diff --git a/meta/packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch b/meta/packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch
deleted file mode 100644 (file)
index 5a51d1c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
----
- drivers/char/vt_ioctl.c |    8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-Index: linux-2.6.22/drivers/char/vt_ioctl.c
-===================================================================
---- linux-2.6.22.orig/drivers/char/vt_ioctl.c  2007-07-09 01:32:17.000000000 +0200
-+++ linux-2.6.22/drivers/char/vt_ioctl.c       2007-09-27 11:58:42.000000000 +0200
-@@ -770,6 +770,7 @@
-               /*
-                * Switching-from response
-                */
-+              acquire_console_sem();
-               if (vc->vt_newvt >= 0) {
-                       if (arg == 0)
-                               /*
-@@ -784,7 +785,6 @@
-                                * complete the switch.
-                                */
-                               int newvt;
--                              acquire_console_sem();
-                               newvt = vc->vt_newvt;
-                               vc->vt_newvt = -1;
-                               i = vc_allocate(newvt);
-@@ -798,7 +798,6 @@
-                                * other console switches..
-                                */
-                               complete_change_console(vc_cons[newvt].d);
--                              release_console_sem();
-                       }
-               }
-@@ -810,9 +809,12 @@
-                       /*
-                        * If it's just an ACK, ignore it
-                        */
--                      if (arg != VT_ACKACQ)
-+                      if (arg != VT_ACKACQ) {
-+                              release_console_sem();
-                               return -EINVAL;
-+                      }
-               }
-+              release_console_sem();
-               return 0;
diff --git a/meta/packages/linux/linux-rp-2.6.23/w100fb-unused-var.patch b/meta/packages/linux/linux-rp-2.6.23/w100fb-unused-var.patch
deleted file mode 100644 (file)
index 8cbbb6b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-From: Marcin Juszkiewicz <openembedded@haerwu.biz>
-
-drivers/video/w100fb.c: In function â€˜w100fb_imageblit’:
-drivers/video/w100fb.c:507: warning: unused variable â€˜par’
-
-Signed-off-by: Marcin Juszkiewicz <openembedded@haerwu.biz>
-
---- linux-2.6.23/drivers/video/w100fb.c        2007-10-11 16:52:30.000000000 +0200
-+++ linux-2.6.23/drivers/video/w100fb.c        2007-10-15 12:56:01.000000000 +0200
-@@ -504,7 +504,6 @@ static void w100_hostdata(u32 width, u32
- static void w100fb_imageblit(struct fb_info *info,
-                              const struct fb_image *image)
- {
--      struct w100fb_par *par = info->par;
-       union dp_gui_master_cntl_u gmc;
-       u32 fgcolor, bgcolor;
diff --git a/meta/packages/linux/linux-rp-2.6.23/wm9712-reset-loop-r2.patch b/meta/packages/linux/linux-rp-2.6.23/wm9712-reset-loop-r2.patch
new file mode 100644 (file)
index 0000000..78e81ea
--- /dev/null
@@ -0,0 +1,44 @@
+ sound/soc/codecs/wm9712.c |   28 ++++++++++++++++++----------
+ 1 file changed, 18 insertions(+), 10 deletions(-)
+
+Index: git/sound/soc/codecs/wm9712.c
+===================================================================
+--- git.orig/sound/soc/codecs/wm9712.c 2006-11-07 22:10:01.000000000 +0000
++++ git/sound/soc/codecs/wm9712.c      2006-11-07 22:11:50.000000000 +0000
+@@ -618,18 +618,26 @@ static int wm9712_dapm_event(struct snd_
+ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
+ {
+-      if (try_warm && soc_ac97_ops.warm_reset) {
+-              soc_ac97_ops.warm_reset(codec->ac97);
+-              if (!(ac97_read(codec, 0) & 0x8000))
+-                      return 1;
+-      }
++      int retry = 3;
+-      soc_ac97_ops.reset(codec->ac97);
+-      if (ac97_read(codec, 0) & 0x8000)
+-              goto err;
+-      return 0;
++      while (retry--)
++      {
++              if(try_warm && soc_ac97_ops.warm_reset) {
++                      soc_ac97_ops.warm_reset(codec->ac97);
++                      if(ac97_read(codec, 0) & 0x8000)
++                              continue;
++                      else
++                              return 1;
++              }
++
++              soc_ac97_ops.reset(codec->ac97);
++              if(ac97_read(codec, 0) & 0x8000)
++                      continue;
++              else
++                      return 0;
++
++      }
+-err:
+       printk(KERN_ERR "WM9712 AC97 reset failed\n");
+       return -EIO;
+ }
diff --git a/meta/packages/linux/linux-rp-2.6.23/wm9712-suspend-cold-res-r2.patch b/meta/packages/linux/linux-rp-2.6.23/wm9712-suspend-cold-res-r2.patch
new file mode 100644 (file)
index 0000000..5179b47
--- /dev/null
@@ -0,0 +1,16 @@
+ sound/soc/codecs/wm9712.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: git/sound/soc/codecs/wm9712.c
+===================================================================
+--- git.orig/sound/soc/codecs/wm9712.c 2006-11-07 21:57:34.000000000 +0000
++++ git/sound/soc/codecs/wm9712.c      2006-11-07 21:59:30.000000000 +0000
+@@ -651,7 +651,7 @@ static int wm9712_soc_resume(struct plat
+       int i, ret;
+       u16 *cache = codec->reg_cache;
+-      ret = wm9712_reset(codec, 1);
++      ret = wm9712_reset(codec, 0);
+       if (ret < 0){
+               printk(KERN_ERR "could not reset AC97 codec\n");
+               return ret;
diff --git a/meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0-fix-r0.patch b/meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0-fix-r0.patch
new file mode 100644 (file)
index 0000000..5ad0d87
--- /dev/null
@@ -0,0 +1,128 @@
+ drivers/input/power.c                   |    2 +-
+ drivers/input/touchscreen/Kconfig       |    2 +-
+ drivers/input/touchscreen/wm97xx-core.c |   35 ++++++++++++++++---------------
+ include/linux/wm97xx.h                  |    2 +-
+ 4 files changed, 21 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/input/power.c b/drivers/input/power.c
+index 4443e34..7aac875 100644
+--- a/drivers/input/power.c
++++ b/drivers/input/power.c
+@@ -156,7 +156,7 @@ static void power_event(struct input_handle *handle, unsigned int type,
+       }
+ }
+-static struct input_handle *power_connect(struct input_handler *handler,
++static int power_connect(struct input_handler *handler,
+                                         struct input_dev *dev,
+                                         const struct input_device_id *id)
+ {
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 6862e8f..9b532e9 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -247,7 +247,7 @@ config TOUCHSCREEN_TSC2101
+ config TOUCHSCREEN_WM97XX
+       tristate "Support for WM97xx AC97 touchscreen controllers"
+-      depends SND_AC97_BUS
++      depends AC97_BUS
+ choice
+       prompt "WM97xx codec type"
+diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
+index 9b2710e..d3ce3f3 100644
+--- a/drivers/input/touchscreen/wm97xx-core.c
++++ b/drivers/input/touchscreen/wm97xx-core.c
+@@ -84,6 +84,7 @@
+ #include <linux/bitops.h>
+ #include <linux/workqueue.h>
+ #include <linux/device.h>
++#include <linux/freezer.h>
+ #include <linux/wm97xx.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -241,14 +242,15 @@ WM97XX_STATUS_ATTR(gpio);
+ static int wm97xx_sys_add(struct device *dev)
+ {
++      int err;
+       if (aux_sys) {
+-              device_create_file(dev, &dev_attr_aux1);
+-              device_create_file(dev, &dev_attr_aux2);
+-              device_create_file(dev, &dev_attr_aux3);
+-              device_create_file(dev, &dev_attr_aux4);
++              err = device_create_file(dev, &dev_attr_aux1);    
++              err = device_create_file(dev, &dev_attr_aux2);
++              err = device_create_file(dev, &dev_attr_aux3);
++              err = device_create_file(dev, &dev_attr_aux4);
+       }
+       if (status_sys)
+-              device_create_file(dev, &dev_attr_gpio);
++              err = device_create_file(dev, &dev_attr_gpio);
+       return 0;
+ }
+@@ -366,12 +368,12 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, wm97xx_gpio_dir_t dir,
+ /*
+  * Handle a pen down interrupt.
+- */
+-static void wm97xx_pen_irq_worker(void *ptr)
+-{
+-      struct wm97xx *wm = (struct wm97xx *) ptr;
+-
+-      /* do we need to enable the touch panel reader */
++ */ 
++static void wm97xx_pen_irq_worker(struct work_struct *work) 
++{                  
++      struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work);
++      
++      /* do we need to enable the touch panel reader */ 
+       if (wm->id == WM9705_ID2) {
+               if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN)
+                       wm->pen_is_down = 1;
+@@ -411,9 +413,8 @@ static void wm97xx_pen_irq_worker(void *ptr)
+  * We have to disable the codec interrupt in the handler because it can
+  * take upto 1ms to clear the interrupt source. The interrupt is then enabled
+  * again in the slow handler when the source has been cleared.
+- */
+-static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id,
+-                                      struct pt_regs *regs)
++ */ 
++static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
+ {
+       struct wm97xx *wm = (struct wm97xx *) dev_id;
+       disable_irq(wm->pen_irq);
+@@ -428,15 +429,15 @@ static int wm97xx_init_pen_irq(struct wm97xx *wm)
+ {
+       u16 reg;
+-      INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker, wm);
+-      if ((wm->pen_irq_workq =
++      INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker);
++      if ((wm->pen_irq_workq = 
+               create_singlethread_workqueue("kwm97pen")) == NULL) {
+               err("could not create pen irq work queue");
+               wm->pen_irq = 0;
+               return -EINVAL;
+       }
+-      if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, SA_SHIRQ, "wm97xx-pen", wm)) {
++      if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED, "wm97xx-pen", wm)) {
+               err("could not register codec pen down interrupt, will poll for pen down");
+               destroy_workqueue(wm->pen_irq_workq);
+               wm->pen_irq = 0;
+diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h
+index b1c1740..a9bd57e 100644
+--- a/include/linux/wm97xx.h
++++ b/include/linux/wm97xx.h
+@@ -243,7 +243,7 @@ struct wm97xx {
+       u16 dig_save[3];                /* saved during aux reading */
+       struct wm97xx_codec_drv *codec; /* attached codec driver*/
+       struct input_dev* input_dev;    /* touchscreen input device */
+-      ac97_t *ac97;                   /* ALSA codec access */
++      struct snd_ac97 *ac97;                  /* ALSA codec access */
+       struct device *dev;             /* ALSA device */
+     struct device *battery_dev;
+     struct device *touch_dev;
diff --git a/meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0.patch b/meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0.patch
new file mode 100644 (file)
index 0000000..c918c5d
--- /dev/null
@@ -0,0 +1,2899 @@
+Index: linux-2.6.17/drivers/input/touchscreen/Kconfig
+===================================================================
+--- linux-2.6.17.orig/drivers/input/touchscreen/Kconfig        2006-09-19 20:35:35.060495500 +0200
++++ linux-2.6.17/drivers/input/touchscreen/Kconfig     2006-09-19 20:36:47.965051750 +0200
+@@ -121,4 +121,57 @@ config TOUCHSCREEN_TSC2101
+         To compile this driver as a module, choose M here: the
+         module will be called ads7846_ts.
++config TOUCHSCREEN_WM97XX
++      tristate "Support for WM97xx AC97 touchscreen controllers"
++      depends SND_AC97_BUS
++
++choice
++      prompt "WM97xx codec type"
++
++config TOUCHSCREEN_WM9705
++      bool "WM9705 Touchscreen interface support"
++      depends on TOUCHSCREEN_WM97XX
++      help
++        Say Y here if you have the wm9705 touchscreen.
++
++        If unsure, say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called wm9705.
++
++config TOUCHSCREEN_WM9712
++      bool "WM9712 Touchscreen interface support"
++      depends on TOUCHSCREEN_WM97XX
++      help
++        Say Y here if you have the wm9712 touchscreen.
++
++        If unsure, say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called wm9712.
++
++config TOUCHSCREEN_WM9713
++      bool "WM9713 Touchscreen interface support"
++      depends on TOUCHSCREEN_WM97XX
++      help
++        Say Y here if you have the wm9713 touchscreen.
++
++        If unsure, say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called wm9713.
++
++endchoice
++
++config TOUCHSCREEN_WM97XX_PXA
++      tristate "WM97xx PXA accelerated touch"
++      depends on TOUCHSCREEN_WM97XX && ARCH_PXA
++      help
++        Say Y here for continuous mode touch on the PXA
++
++        If unsure, say N
++
++        To compile this driver as a module, choose M here: the
++        module will be called pxa-wm97xx
++
+ endif
+Index: linux-2.6.17/drivers/input/touchscreen/Makefile
+===================================================================
+--- linux-2.6.17.orig/drivers/input/touchscreen/Makefile       2006-09-19 20:35:35.072496250 +0200
++++ linux-2.6.17/drivers/input/touchscreen/Makefile    2006-09-19 20:37:40.540337500 +0200
+@@ -4,6 +4,8 @@
+ # Each configuration option enables a list of files.
++wm97xx-ts-objs := wm97xx-core.o
++
+ obj-$(CONFIG_TOUCHSCREEN_ADS7846)     += ads7846.o
+ obj-$(CONFIG_TOUCHSCREEN_BITSY)       += h3600_ts_input.o
+ obj-$(CONFIG_TOUCHSCREEN_CORGI)       += corgi_ts.o
+@@ -13,3 +15,16 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtou
+ obj-$(CONFIG_TOUCHSCREEN_MK712)       += mk712.o
+ obj-$(CONFIG_TOUCHSCREEN_HP600)       += hp680_ts_input.o
+ obj-$(CONFIG_TOUCHSCREEN_TSC2101)     += tsc2101_ts.o
++obj-$(CONFIG_TOUCHSCREEN_WM97XX)      += wm97xx-ts.o
++obj-$(CONFIG_TOUCHSCREEN_WM97XX_PXA)    += pxa-wm97xx.o
++
++ifeq ($(CONFIG_TOUCHSCREEN_WM9713),y)
++wm97xx-ts-objs += wm9713.o
++endif
++
++ifeq ($(CONFIG_TOUCHSCREEN_WM9712),y)
++wm97xx-ts-objs += wm9712.o
++endif
++ifeq ($(CONFIG_TOUCHSCREEN_WM9705),y)
++wm97xx-ts-objs += wm9705.o
++endif
+Index: linux-2.6.17/drivers/input/touchscreen/pxa-wm97xx.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.17/drivers/input/touchscreen/pxa-wm97xx.c        2006-09-19 20:36:47.965051750 +0200
+@@ -0,0 +1,289 @@
++/*
++ * pxa-wm97xx.c  --  pxa-wm97xx Continuous Touch screen driver for
++ *                   Wolfson WM97xx AC97 Codecs.
++ *
++ * Copyright 2004 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ * Notes:
++ *     This is a wm97xx extended touch driver to capture touch
++ *     data in a continuous manner on the Intel XScale archictecture
++ *
++ *  Features:
++ *       - codecs supported:- WM9705, WM9712, WM9713
++ *       - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
++ *
++ *  Revision history
++ *    18th Aug 2004   Initial version.
++ *    26th Jul 2005   Improved continous read back and added FIFO flushing.
++ *    06th Sep 2005   Mike Arthur <linux@wolfsonmicro.com>
++ *                    Moved to using the wm97xx bus
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/wm97xx.h>
++#include <asm/io.h>
++#include <asm/arch/pxa-regs.h>
++
++#define VERSION               "0.13"
++
++struct continuous {
++      u16 id;    /* codec id */
++      u8 code;   /* continuous code */
++      u8 reads;  /* number of coord reads per read cycle */
++      u32 speed; /* number of coords per second */
++};
++
++#define WM_READS(sp) ((sp / HZ) + 1)
++
++static const struct continuous cinfo[] = {
++      {WM9705_ID2, 0, WM_READS(94), 94},
++      {WM9705_ID2, 1, WM_READS(188), 188},
++      {WM9705_ID2, 2, WM_READS(375), 375},
++      {WM9705_ID2, 3, WM_READS(750), 750},
++      {WM9712_ID2, 0, WM_READS(94), 94},
++      {WM9712_ID2, 1, WM_READS(188), 188},
++      {WM9712_ID2, 2, WM_READS(375), 375},
++      {WM9712_ID2, 3, WM_READS(750), 750},
++      {WM9713_ID2, 0, WM_READS(94), 94},
++      {WM9713_ID2, 1, WM_READS(120), 120},
++      {WM9713_ID2, 2, WM_READS(154), 154},
++      {WM9713_ID2, 3, WM_READS(188), 188},
++};
++
++/* continuous speed index */
++static int sp_idx = 0;
++static u16 last = 0, tries = 0;
++
++/*
++ * Pen sampling frequency (Hz) in continuous mode.
++ */
++static int cont_rate = 200;
++module_param(cont_rate, int, 0);
++MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
++
++/*
++ * Pen down detection.
++ *
++ * This driver can either poll or use an interrupt to indicate a pen down
++ * event. If the irq request fails then it will fall back to polling mode.
++ */
++static int pen_int = 1;
++module_param(pen_int, int, 0);
++MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
++
++/*
++ * Pressure readback.
++ *
++ * Set to 1 to read back pen down pressure
++ */
++static int pressure = 0;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
++
++/*
++ * AC97 touch data slot.
++ *
++ * Touch screen readback data ac97 slot
++ */
++static int ac97_touch_slot = 5;
++module_param(ac97_touch_slot, int, 0);
++MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
++
++
++/* flush AC97 slot 5 FIFO on pxa machines */
++#ifdef CONFIG_PXA27x
++void wm97xx_acc_pen_up (struct wm97xx* wm)
++{
++      set_current_state(TASK_INTERRUPTIBLE);
++      schedule_timeout(1);
++
++      while (MISR & (1 << 2))
++              MODR;
++}
++#else
++void wm97xx_acc_pen_up (struct wm97xx* wm)
++{
++      int count = 16;
++      set_current_state(TASK_INTERRUPTIBLE);
++      schedule_timeout(1);
++
++      while (count < 16) {
++              MODR;
++              count--;
++      }
++}
++#endif
++
++int wm97xx_acc_pen_down (struct wm97xx* wm)
++{
++      u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
++      int reads = 0;
++
++      /* data is never immediately available after pen down irq */
++      set_current_state(TASK_INTERRUPTIBLE);
++      schedule_timeout(1);
++
++      if (tries > 5){
++              tries = 0;
++              return RC_PENUP;
++      }
++
++      x = MODR;
++      if (x == last) {
++              tries++;
++              return RC_AGAIN;
++      }
++      last = x;
++      do {
++              if (reads)
++                      x= MODR;
++              y= MODR;
++              if (pressure)
++                      p = MODR;
++
++              /* are samples valid */
++              if ((x & 0x7000) != WM97XX_ADCSEL_X ||
++                      (y & 0x7000) != WM97XX_ADCSEL_Y ||
++                      (p & 0x7000) != WM97XX_ADCSEL_PRES)
++                      goto up;
++
++              /* coordinate is good */
++              tries = 0;
++              //printk("x %x y %x p %x\n", x,y,p);
++              input_report_abs (wm->input_dev, ABS_X, x & 0xfff);
++              input_report_abs (wm->input_dev, ABS_Y, y & 0xfff);
++              input_report_abs (wm->input_dev, ABS_PRESSURE, p & 0xfff);
++              input_sync (wm->input_dev);
++              reads++;
++      } while (reads < cinfo[sp_idx].reads);
++up:
++      return RC_PENDOWN | RC_AGAIN;
++}
++
++int wm97xx_acc_startup(struct wm97xx* wm)
++{
++      int idx = 0;
++
++      /* check we have a codec */
++      if (wm->ac97 == NULL)
++              return -ENODEV;
++
++      /* Go you big red fire engine */
++      for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
++              if (wm->id != cinfo[idx].id)
++                      continue;
++              sp_idx = idx;
++              if (cont_rate <= cinfo[idx].speed)
++                      break;
++      }
++      wm->acc_rate = cinfo[sp_idx].code;
++      wm->acc_slot = ac97_touch_slot;
++      printk(KERN_INFO "pxa2xx accelerated touchscreen driver, %d samples (sec)\n",
++              cinfo[sp_idx].speed);
++
++      /* codec specific irq config */
++      if (pen_int) {
++              switch (wm->id) {
++                      case WM9705_ID2:
++                              wm->pen_irq = IRQ_GPIO(4);
++                              set_irq_type(IRQ_GPIO(4), IRQT_BOTHEDGE);
++                              break;
++                      case WM9712_ID2:
++                      case WM9713_ID2:
++                              /* enable pen down interrupt */
++                              /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
++                              wm->pen_irq = MAINSTONE_AC97_IRQ;
++                              wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
++                                      WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, WM97XX_GPIO_WAKE);
++                              wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
++                                      WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_NOTSTICKY, WM97XX_GPIO_NOWAKE);
++                              break;
++                      default:
++                              printk(KERN_WARNING "pen down irq not supported on this device\n");
++                              pen_int = 0;
++                              break;
++              }
++      }
++
++      return 0;
++}
++
++void wm97xx_acc_shutdown(struct wm97xx* wm)
++{
++    /* codec specific deconfig */
++      if (pen_int) {
++              switch (wm->id & 0xffff) {
++                      case WM9705_ID2:
++                              wm->pen_irq = 0;
++                              break;
++                      case WM9712_ID2:
++                      case WM9713_ID2:
++                              /* disable interrupt */
++                              wm->pen_irq = 0;
++                              break;
++              }
++      }
++}
++
++static struct wm97xx_mach_ops pxa_mach_ops = {
++      .acc_enabled = 1,
++      .acc_pen_up = wm97xx_acc_pen_up,
++    .acc_pen_down = wm97xx_acc_pen_down,
++    .acc_startup = wm97xx_acc_startup,
++    .acc_shutdown = wm97xx_acc_shutdown,
++};
++
++int pxa_wm97xx_probe(struct device *dev)
++{
++    struct wm97xx *wm = dev->driver_data;
++    return wm97xx_register_mach_ops (wm, &pxa_mach_ops);
++}
++
++int pxa_wm97xx_remove(struct device *dev)
++{
++      struct wm97xx *wm = dev->driver_data;
++    wm97xx_unregister_mach_ops (wm);
++    return 0;
++}
++
++static struct device_driver  pxa_wm97xx_driver = {
++    .name = "wm97xx-touchscreen",
++    .bus = &wm97xx_bus_type,
++    .owner = THIS_MODULE,
++    .probe = pxa_wm97xx_probe,
++    .remove = pxa_wm97xx_remove
++};
++
++static int __init pxa_wm97xx_init(void)
++{
++    return driver_register(&pxa_wm97xx_driver);
++}
++
++static void __exit pxa_wm97xx_exit(void)
++{
++    driver_unregister(&pxa_wm97xx_driver);
++}
++
++module_init(pxa_wm97xx_init);
++module_exit(pxa_wm97xx_exit);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
++MODULE_DESCRIPTION("wm97xx continuous touch driver for pxa2xx");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.17/drivers/input/touchscreen/wm9705.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.17/drivers/input/touchscreen/wm9705.c    2006-09-19 20:36:47.969052000 +0200
+@@ -0,0 +1,360 @@
++/*
++ * wm9705.c  --  Codec driver for Wolfson WM9705 AC97 Codec.
++ *
++ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.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 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  Revision history
++ *     6th Sep 2006  Mike Arthur <linux@wolfsonmicro.com>
++ *                   Added pre and post sample calls.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/wm97xx.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM9705_VERSION                "0.62"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * Debug
++ */
++#if 0
++#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
++#else
++#define dbg(format, arg...)
++#endif
++#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
++#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
++
++/*
++ * Module parameters
++ */
++
++/*
++ * Set current used for pressure measurement.
++ *
++ * Set pil = 2 to use 400uA
++ *     pil = 1 to use 200uA and
++ *     pil = 0 to disable pressure measurement.
++ *
++ * This is used to increase the range of values returned by the adc
++ * when measureing touchpanel pressure.
++ */
++static int pil = 0;
++module_param(pil, int, 0);
++MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
++
++/*
++ * Set threshold for pressure measurement.
++ *
++ * Pen down pressure below threshold is ignored.
++ */
++static int pressure = DEFAULT_PRESSURE & 0xfff;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
++
++/*
++ * Set adc sample delay.
++ *
++ * For accurate touchpanel measurements, some settling time may be
++ * required between the switch matrix applying a voltage across the
++ * touchpanel plate and the ADC sampling the signal.
++ *
++ * This delay can be set by setting delay = n, where n is the array
++ * position of the delay in the array delay_table below.
++ * Long delays > 1ms are supported for completeness, but are not
++ * recommended.
++ */
++static int delay = 4;
++module_param(delay, int, 0);
++MODULE_PARM_DESC(delay, "Set adc sample delay.");
++
++/*
++ * Pen detect comparator threshold.
++ *
++ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
++ * i.e. 1 =  Vmid/15 threshold
++ *      15 =  Vmid/1 threshold
++ *
++ * Adjust this value if you are having problems with pen detect not
++ * detecting any down events.
++ */
++static int pdd = 8;
++module_param(pdd, int, 0);
++MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
++
++/*
++ * Set adc mask function.
++ *
++ * Sources of glitch noise, such as signals driving an LCD display, may feed
++ * through to the touch screen plates and affect measurement accuracy. In
++ * order to minimise this, a signal may be applied to the MASK pin to delay or
++ * synchronise the sampling.
++ *
++ * 0 = No delay or sync
++ * 1 = High on pin stops conversions
++ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
++ * 3 = Edge triggered, edge on pin starts conversion after delay param
++ */
++static int mask = 0;
++module_param(mask, int, 0);
++MODULE_PARM_DESC(mask, "Set adc mask function.");
++
++/*
++ * ADC sample delay times in uS
++ */
++static const int delay_table[] = {
++      21,    // 1 AC97 Link frames
++      42,    // 2
++      84,    // 4
++      167,   // 8
++      333,   // 16
++      667,   // 32
++      1000,  // 48
++      1333,  // 64
++      2000,  // 96
++      2667,  // 128
++      3333,  // 160
++      4000,  // 192
++      4667,  // 224
++      5333,  // 256
++      6000,  // 288
++      0      // No delay, switch matrix always on
++};
++
++/*
++ * Delay after issuing a POLL command.
++ *
++ * The delay is 3 AC97 link frames + the touchpanel settling delay
++ */
++static inline void poll_delay(int d)
++{
++      udelay (3 * AC97_LINK_FRAME + delay_table [d]);
++}
++
++/*
++ * set up the physical settings of the WM9705
++ */
++static void init_wm9705_phy(struct wm97xx* wm)
++{
++      u16 dig1 = 0, dig2 = WM97XX_RPR;
++
++      /*
++      * mute VIDEO and AUX as they share X and Y touchscreen
++      * inputs on the WM9705
++      */
++      wm97xx_reg_write(wm, AC97_AUX, 0x8000);
++      wm97xx_reg_write(wm, AC97_VIDEO, 0x8000);
++
++      /* touchpanel pressure current*/
++      if  (pil == 2) {
++              dig2 |= WM9705_PIL;
++              dbg("setting pressure measurement current to 400uA.");
++      } else if (pil)
++              dbg("setting pressure measurement current to 200uA.");
++      if(!pil)
++              pressure = 0;
++
++      /* polling mode sample settling delay */
++      if (delay!=4) {
++              if (delay < 0 || delay > 15) {
++                  dbg("supplied delay out of range.");
++                  delay = 4;
++              }
++      }
++      dig1 &= 0xff0f;
++      dig1 |= WM97XX_DELAY(delay);
++      dbg("setting adc sample delay to %d u Secs.", delay_table[delay]);
++
++      /* WM9705 pdd */
++      dig2 |= (pdd & 0x000f);
++      dbg("setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
++
++      /* mask */
++      dig2 |= ((mask & 0x3) << 4);
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++}
++
++static int wm9705_digitiser_ioctl(struct wm97xx* wm, int cmd)
++{
++      switch(cmd) {
++      case WM97XX_DIG_START:
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig[2] | WM97XX_PRP_DET_DIG);
++              wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
++              break;
++      case WM97XX_DIG_STOP:
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig[2] & ~WM97XX_PRP_DET_DIG);
++              break;
++      case WM97XX_AUX_PREPARE:
++              memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
++              break;
++      case WM97XX_DIG_RESTORE:
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
++              break;
++      case WM97XX_PHY_INIT:
++              init_wm9705_phy(wm);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++static inline int is_pden (struct wm97xx* wm)
++{
++      return wm->dig[2] & WM9705_PDEN;
++}
++
++/*
++ * Read a sample from the WM9705 adc in polling mode.
++ */
++static int wm9705_poll_sample (struct wm97xx* wm, int adcsel, int *sample)
++{
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (adcsel & 0x8000)
++              adcsel = ((adcsel & 0x7fff) + 3) << 12;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(adcsel);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay (delay);
++
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dbg ("adc sample timeout");
++              return RC_PENUP;
++      }
++
++      *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(adcsel);
++
++      /* check we have correct sample */
++      if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
++              dbg ("adc wrong sample, read %x got %x", adcsel,
++              *sample & WM97XX_ADCSEL_MASK);
++              return RC_PENUP;
++      }
++
++      if (!(*sample & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++
++      return RC_VALID;
++}
++
++/*
++ * Sample the WM9705 touchscreen in polling mode
++ */
++static int wm9705_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
++{
++      int rc;
++
++      if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID)
++              return rc;
++      if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID)
++              return rc;
++      if (pil) {
++              if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID)
++                      return rc;
++      } else
++              data->p = DEFAULT_PRESSURE;
++
++      return RC_VALID;
++}
++
++/*
++ * Enable WM9705 continuous mode, i.e. touch data is streamed across an AC97 slot
++ */
++static int wm9705_acc_enable (struct wm97xx* wm, int enable)
++{
++      u16 dig1, dig2;
++      int ret = 0;
++
++      dig1 = wm->dig[1];
++      dig2 = wm->dig[2];
++
++      if (enable) {
++              /* continous mode */
++              if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0)
++                      return ret;
++              dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
++                      WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
++              dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
++                      WM97XX_DELAY (delay) |
++                      WM97XX_SLT (wm->acc_slot) |
++                      WM97XX_RATE (wm->acc_rate);
++              if (pil)
++                      dig1 |= WM97XX_ADCSEL_PRES;
++              dig2 |= WM9705_PDEN;
++      } else {
++              dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
++              dig2 &= ~WM9705_PDEN;
++              if (wm->mach_ops->acc_shutdown)
++                      wm->mach_ops->acc_shutdown(wm);
++      }
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++      return ret;
++}
++
++struct wm97xx_codec_drv wm97xx_codec = {
++      .id =   WM9705_ID2,
++      .name = "wm9705",
++      .poll_sample = wm9705_poll_sample,
++      .poll_touch = wm9705_poll_touch,
++      .acc_enable = wm9705_acc_enable,
++      .digitiser_ioctl = wm9705_digitiser_ioctl,
++};
++
++EXPORT_SYMBOL_GPL(wm97xx_codec);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
++MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.17/drivers/input/touchscreen/wm9712.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.17/drivers/input/touchscreen/wm9712.c    2006-09-19 20:36:47.969052000 +0200
+@@ -0,0 +1,464 @@
++/*
++ * wm9712.c  --  Codec driver for Wolfson WM9712 AC97 Codecs.
++ *
++ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.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 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  Revision history
++ *     4th Jul 2005  Initial version.
++ *     6th Sep 2006  Mike Arthur <linux@wolfsonmicro.com>
++ *                   Added pre and post sample calls.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/wm97xx.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM9712_VERSION                "0.61"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * Debug
++ */
++#if 0
++#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
++#else
++#define dbg(format, arg...)
++#endif
++#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
++#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
++
++/*
++ * Module parameters
++ */
++
++/*
++ * Set internal pull up for pen detect.
++ *
++ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
++ * i.e. pull up resistance = 64k Ohms / rpu.
++ *
++ * Adjust this value if you are having problems with pen detect not
++ * detecting any down event.
++ */
++static int rpu = 3;
++module_param(rpu, int, 0);
++MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
++
++/*
++ * Set current used for pressure measurement.
++ *
++ * Set pil = 2 to use 400uA
++ *     pil = 1 to use 200uA and
++ *     pil = 0 to disable pressure measurement.
++ *
++ * This is used to increase the range of values returned by the adc
++ * when measureing touchpanel pressure.
++ */
++static int pil = 0;
++module_param(pil, int, 0);
++MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
++
++/*
++ * Set threshold for pressure measurement.
++ *
++ * Pen down pressure below threshold is ignored.
++ */
++static int pressure = DEFAULT_PRESSURE & 0xfff;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
++
++/*
++ * Set adc sample delay.
++ *
++ * For accurate touchpanel measurements, some settling time may be
++ * required between the switch matrix applying a voltage across the
++ * touchpanel plate and the ADC sampling the signal.
++ *
++ * This delay can be set by setting delay = n, where n is the array
++ * position of the delay in the array delay_table below.
++ * Long delays > 1ms are supported for completeness, but are not
++ * recommended.
++ */
++static int delay = 3;
++module_param(delay, int, 0);
++MODULE_PARM_DESC(delay, "Set adc sample delay.");
++
++/*
++ * Set five_wire = 1 to use a 5 wire touchscreen.
++ *
++ * NOTE: Five wire mode does not allow for readback of pressure.
++ */
++static int five_wire;
++module_param(five_wire, int, 0);
++MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
++
++/*
++ * Set adc mask function.
++ *
++ * Sources of glitch noise, such as signals driving an LCD display, may feed
++ * through to the touch screen plates and affect measurement accuracy. In
++ * order to minimise this, a signal may be applied to the MASK pin to delay or
++ * synchronise the sampling.
++ *
++ * 0 = No delay or sync
++ * 1 = High on pin stops conversions
++ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
++ * 3 = Edge triggered, edge on pin starts conversion after delay param
++ */
++static int mask = 0;
++module_param(mask, int, 0);
++MODULE_PARM_DESC(mask, "Set adc mask function.");
++
++/*
++ * Coordinate Polling Enable.
++ *
++ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
++ * for every poll.
++ */
++static int coord = 0;
++module_param(coord, int, 0);
++MODULE_PARM_DESC(coord, "Polling coordinate mode");
++
++/*
++ * ADC sample delay times in uS
++ */
++static const int delay_table[] = {
++      21,    // 1 AC97 Link frames
++      42,    // 2
++      84,    // 4
++      167,   // 8
++      333,   // 16
++      667,   // 32
++      1000,  // 48
++      1333,  // 64
++      2000,  // 96
++      2667,  // 128
++      3333,  // 160
++      4000,  // 192
++      4667,  // 224
++      5333,  // 256
++      6000,  // 288
++      0      // No delay, switch matrix always on
++};
++
++/*
++ * Delay after issuing a POLL command.
++ *
++ * The delay is 3 AC97 link frames + the touchpanel settling delay
++ */
++static inline void poll_delay(int d)
++{
++      udelay (3 * AC97_LINK_FRAME + delay_table [d]);
++}
++
++/*
++ * set up the physical settings of the WM9712
++ */
++static void init_wm9712_phy(struct wm97xx* wm)
++{
++      u16 dig1 = 0;
++      u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
++
++      /* WM9712 rpu */
++      if (rpu) {
++              dig2 &= 0xffc0;
++              dig2 |= WM9712_RPU(rpu);
++              dbg("setting pen detect pull-up to %d Ohms",64000 / rpu);
++      }
++
++      /* touchpanel pressure current*/
++      if (pil == 2) {
++              dig2 |= WM9712_PIL;
++              dbg("setting pressure measurement current to 400uA.");
++      } else if (pil)
++              dbg("setting pressure measurement current to 200uA.");
++      if(!pil)
++              pressure = 0;
++
++      /* WM9712 five wire */
++      if (five_wire) {
++              dig2 |= WM9712_45W;
++              dbg("setting 5-wire touchscreen mode.");
++      }
++
++      /* polling mode sample settling delay */
++      if (delay < 0 || delay > 15) {
++              dbg("supplied delay out of range.");
++              delay = 4;
++      }
++      dig1 &= 0xff0f;
++      dig1 |= WM97XX_DELAY(delay);
++      dbg("setting adc sample delay to %d u Secs.", delay_table[delay]);
++
++      /* mask */
++      dig2 |= ((mask & 0x3) << 6);
++      if (mask) {
++              u16 reg;
++              /* Set GPIO4 as Mask Pin*/
++              reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
++              wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
++              reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
++              wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
++      }
++
++      /* wait - coord mode */
++      if(coord)
++              dig2 |= WM9712_WAIT;
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++}
++
++static int wm9712_digitiser_ioctl(struct wm97xx* wm, int cmd)
++{
++      u16 dig2 = wm->dig[2];
++
++      switch(cmd) {
++      case WM97XX_DIG_START:
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2 | WM97XX_PRP_DET_DIG);
++              wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
++              break;
++      case WM97XX_DIG_STOP:
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2 & ~WM97XX_PRP_DET_DIG);
++              break;
++      case WM97XX_AUX_PREPARE:
++              memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
++              break;
++      case WM97XX_DIG_RESTORE:
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
++              break;
++      case WM97XX_PHY_INIT:
++              init_wm9712_phy(wm);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++static inline int is_pden (struct wm97xx* wm)
++{
++      return wm->dig[2] & WM9712_PDEN;
++}
++
++/*
++ * Read a sample from the WM9712 adc in polling mode.
++ */
++static int wm9712_poll_sample (struct wm97xx* wm, int adcsel, int *sample)
++{
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (adcsel & 0x8000)
++              adcsel = ((adcsel & 0x7fff) + 3) << 12;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(adcsel);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay (delay);
++
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dbg ("adc sample timeout");
++              return RC_PENUP;
++      }
++
++      *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(adcsel);
++
++      /* check we have correct sample */
++      if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
++              dbg ("adc wrong sample, read %x got %x", adcsel,
++              *sample & WM97XX_ADCSEL_MASK);
++              return RC_PENUP;
++      }
++
++      if (!(*sample & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++
++      return RC_VALID;
++}
++
++/*
++ * Read a coord from the WM9712 adc in polling mode.
++ */
++static int wm9712_poll_coord (struct wm97xx* wm, struct wm97xx_data *data)
++{
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
++              WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
++
++      /* wait 3 AC97 time slots + delay for conversion and read x */
++      poll_delay(delay);
++      data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dbg ("adc sample timeout");
++              return RC_PENUP;
++      }
++
++      /* read back y data */
++      data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (pil)
++              data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      else
++              data->p = DEFAULT_PRESSURE;
++
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++
++      /* check we have correct sample */
++      if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
++              goto err;
++      if(pil && !(data->p & WM97XX_ADCSEL_PRES))
++              goto err;
++
++      if (!(data->x & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++      return RC_VALID;
++err:
++      return RC_PENUP;
++}
++
++/*
++ * Sample the WM9712 touchscreen in polling mode
++ */
++static int wm9712_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
++{
++      int rc;
++
++      if(coord) {
++              if((rc = wm9712_poll_coord(wm, data)) != RC_VALID)
++                      return rc;
++      } else {
++              if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID)
++                      return rc;
++
++              if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID)
++                      return rc;
++
++              if (pil && !five_wire) {
++                      if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID)
++                              return rc;
++              } else
++                      data->p = DEFAULT_PRESSURE;
++      }
++      return RC_VALID;
++}
++
++/*
++ * Enable WM9712 continuous mode, i.e. touch data is streamed across an AC97 slot
++ */
++static int wm9712_acc_enable (struct wm97xx* wm, int enable)
++{
++      u16 dig1, dig2;
++      int ret = 0;
++
++      dig1 = wm->dig[1];
++      dig2 = wm->dig[2];
++
++      if (enable) {
++              /* continous mode */
++              if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0)
++                      return ret;
++              dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
++                      WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
++              dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
++                      WM97XX_DELAY (delay) |
++                      WM97XX_SLT (wm->acc_slot) |
++                      WM97XX_RATE (wm->acc_rate);
++              if (pil)
++                      dig1 |= WM97XX_ADCSEL_PRES;
++              dig2 |= WM9712_PDEN;
++      } else {
++              dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
++              dig2 &= ~WM9712_PDEN;
++              if (wm->mach_ops->acc_shutdown)
++                      wm->mach_ops->acc_shutdown(wm);
++      }
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++      return 0;
++}
++
++struct wm97xx_codec_drv wm97xx_codec = {
++      .id =   WM9712_ID2,
++      .name = "wm9712",
++      .poll_sample = wm9712_poll_sample,
++      .poll_touch = wm9712_poll_touch,
++      .acc_enable = wm9712_acc_enable,
++      .digitiser_ioctl = wm9712_digitiser_ioctl,
++};
++
++EXPORT_SYMBOL_GPL(wm97xx_codec);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
++MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.17/drivers/input/touchscreen/wm9713.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.17/drivers/input/touchscreen/wm9713.c    2006-09-19 20:36:47.969052000 +0200
+@@ -0,0 +1,461 @@
++/*
++ * wm9713.c  --  Codec touch driver for Wolfson WM9713 AC97 Codec.
++ *
++ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.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 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  Revision history
++ *     6th Sep 2006  Mike Arthur <linux@wolfsonmicro.com>
++ *                   Added pre and post sample calls.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/wm97xx.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM9713_VERSION                "0.53"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * Debug
++ */
++#if 0
++#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
++#else
++#define dbg(format, arg...)
++#endif
++#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
++#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
++
++/*
++ * Module parameters
++ */
++
++/*
++ * Set internal pull up for pen detect.
++ *
++ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
++ * i.e. pull up resistance = 64k Ohms / rpu.
++ *
++ * Adjust this value if you are having problems with pen detect not
++ * detecting any down event.
++ */
++static int rpu = 1;
++module_param(rpu, int, 0);
++MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
++
++/*
++ * Set current used for pressure measurement.
++ *
++ * Set pil = 2 to use 400uA
++ *     pil = 1 to use 200uA and
++ *     pil = 0 to disable pressure measurement.
++ *
++ * This is used to increase the range of values returned by the adc
++ * when measureing touchpanel pressure.
++ */
++static int pil = 0;
++module_param(pil, int, 0);
++MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
++
++/*
++ * Set threshold for pressure measurement.
++ *
++ * Pen down pressure below threshold is ignored.
++ */
++static int pressure = DEFAULT_PRESSURE & 0xfff;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
++
++/*
++ * Set adc sample delay.
++ *
++ * For accurate touchpanel measurements, some settling time may be
++ * required between the switch matrix applying a voltage across the
++ * touchpanel plate and the ADC sampling the signal.
++ *
++ * This delay can be set by setting delay = n, where n is the array
++ * position of the delay in the array delay_table below.
++ * Long delays > 1ms are supported for completeness, but are not
++ * recommended.
++ */
++static int delay = 4;
++module_param(delay, int, 0);
++MODULE_PARM_DESC(delay, "Set adc sample delay.");
++
++/*
++ * Set adc mask function.
++ *
++ * Sources of glitch noise, such as signals driving an LCD display, may feed
++ * through to the touch screen plates and affect measurement accuracy. In
++ * order to minimise this, a signal may be applied to the MASK pin to delay or
++ * synchronise the sampling.
++ *
++ * 0 = No delay or sync
++ * 1 = High on pin stops conversions
++ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
++ * 3 = Edge triggered, edge on pin starts conversion after delay param
++ */
++static int mask = 0;
++module_param(mask, int, 0);
++MODULE_PARM_DESC(mask, "Set adc mask function.");
++
++/*
++ * Coordinate Polling Enable.
++ *
++ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
++ * for every poll.
++ */
++static int coord = 1;
++module_param(coord, int, 0);
++MODULE_PARM_DESC(coord, "Polling coordinate mode");
++
++/*
++ * ADC sample delay times in uS
++ */
++static const int delay_table[] = {
++      21,    // 1 AC97 Link frames
++      42,    // 2
++      84,    // 4
++      167,   // 8
++      333,   // 16
++      667,   // 32
++      1000,  // 48
++      1333,  // 64
++      2000,  // 96
++      2667,  // 128
++      3333,  // 160
++      4000,  // 192
++      4667,  // 224
++      5333,  // 256
++      6000,  // 288
++      0      // No delay, switch matrix always on
++};
++
++/*
++ * Delay after issuing a POLL command.
++ *
++ * The delay is 3 AC97 link frames + the touchpanel settling delay
++ */
++static inline void poll_delay(int d)
++{
++      udelay (3 * AC97_LINK_FRAME + delay_table [d]);
++}
++
++/*
++ * set up the physical settings of the WM9713
++ */
++static void init_wm9713_phy(struct wm97xx* wm)
++{
++      u16 dig1 = 0, dig2, dig3;
++
++      /* default values */
++      dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
++      dig3= WM9712_RPU(1);
++
++      /* rpu */
++      if (rpu) {
++              dig3 &= 0xffc0;
++              dig3 |= WM9712_RPU(rpu);
++              info("setting pen detect pull-up to %d Ohms",64000 / rpu);
++      }
++
++      /* touchpanel pressure */
++      if (pil == 2) {
++              dig3 |= WM9712_PIL;
++              info("setting pressure measurement current to 400uA.");
++      } else if (pil)
++              info ("setting pressure measurement current to 200uA.");
++      if(!pil)
++              pressure = 0;
++
++      /* sample settling delay */
++      if (delay < 0 || delay > 15) {
++              info ("supplied delay out of range.");
++              delay = 4;
++              info("setting adc sample delay to %d u Secs.", delay_table[delay]);
++      }
++      dig2 &= 0xff0f;
++      dig2 |= WM97XX_DELAY(delay);
++
++      /* mask */
++      dig3 |= ((mask & 0x3) << 4);
++      if(coord)
++              dig3 |= WM9713_WAIT;
++
++      wm->misc = wm97xx_reg_read(wm, 0x5a);
++
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
++      wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
++}
++
++static int wm9713_digitiser_ioctl(struct wm97xx* wm, int cmd)
++{
++      u16 val = 0;
++
++      switch(cmd){
++      case WM97XX_DIG_START:
++              val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
++              wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] | WM97XX_PRP_DET_DIG);
++              wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
++              break;
++      case WM97XX_DIG_STOP:
++              wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] & ~WM97XX_PRP_DET_DIG);
++              val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
++              break;
++      case WM97XX_AUX_PREPARE:
++              memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
++              wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
++              wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
++              wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
++              break;
++      case WM97XX_DIG_RESTORE:
++              wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
++              wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
++              wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
++              break;
++      case WM97XX_PHY_INIT:
++              init_wm9713_phy(wm);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++static inline int is_pden (struct wm97xx* wm)
++{
++      return wm->dig[2] & WM9713_PDEN;
++}
++
++/*
++ * Read a sample from the WM9713 adc in polling mode.
++ */
++static int wm9713_poll_sample (struct wm97xx* wm, int adcsel, int *sample)
++{
++      u16 dig1;
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (adcsel & 0x8000)
++              adcsel = 1 << ((adcsel & 0x7fff) + 3);
++
++      dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
++      dig1 &= ~WM9713_ADCSEL_MASK;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(adcsel);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel |WM9713_POLL);
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay(delay);
++
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dbg ("adc sample timeout");
++              return RC_PENUP;
++      }
++
++      *sample =wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(adcsel);
++
++      /* check we have correct sample */
++      if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
++              dbg ("adc wrong sample, read %x got %x", adcsel,
++                   *sample & WM97XX_ADCSRC_MASK);
++              return RC_PENUP;
++      }
++
++      if (!(*sample & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++
++      return RC_VALID;
++}
++
++/*
++ * Read a coordinate from the WM9713 adc in polling mode.
++ */
++static int wm9713_poll_coord (struct wm97xx* wm, struct wm97xx_data *data)
++{
++      u16 dig1;
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
++      dig1 &= ~WM9713_ADCSEL_MASK;
++      if(pil)
++              dig1 |= WM97XX_ADCSEL_PRES;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL | WM9713_COO);
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay(delay);
++      data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dbg ("adc sample timeout");
++              return RC_PENUP;
++      }
++
++      /* read back data */
++      data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (pil)
++              data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      else
++              data->p = DEFAULT_PRESSURE;
++
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++
++      /* check we have correct sample */
++      if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
++              goto err;
++      if(pil && !(data->p & WM97XX_ADCSEL_PRES))
++              goto err;
++
++      if (!(data->x & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++      return RC_VALID;
++err:
++      return RC_PENUP;
++}
++
++/*
++ * Sample the WM9713 touchscreen in polling mode
++ */
++static int wm9713_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
++{
++      int rc;
++
++      if(coord) {
++              if((rc = wm9713_poll_coord(wm, data)) != RC_VALID)
++                      return rc;
++      } else {
++              if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x)) != RC_VALID)
++                      return rc;
++              if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y)) != RC_VALID)
++                      return rc;
++              if (pil) {
++                      if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES, &data->p)) != RC_VALID)
++                              return rc;
++              } else
++                      data->p = DEFAULT_PRESSURE;
++      }
++      return RC_VALID;
++}
++
++/*
++ * Enable WM9713 continuous mode, i.e. touch data is streamed across an AC97 slot
++ */
++static int wm9713_acc_enable (struct wm97xx* wm, int enable)
++{
++      u16 dig1, dig2, dig3;
++      int ret = 0;
++
++      dig1 = wm->dig[0];
++      dig2 = wm->dig[1];
++      dig3 = wm->dig[2];
++
++      if (enable) {
++              /* continous mode */
++              if (wm->mach_ops->acc_startup &&
++                      (ret = wm->mach_ops->acc_startup(wm)) < 0)
++                      return ret;
++
++              dig1 &= ~WM9713_ADCSEL_MASK;
++              dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X | WM9713_ADCSEL_Y;
++        if (pil)
++              dig1 |= WM9713_ADCSEL_PRES;
++              dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK  | WM97XX_CM_RATE_MASK);
++              dig2 |= WM97XX_SLEN | WM97XX_DELAY (delay) |
++              WM97XX_SLT (wm->acc_slot) | WM97XX_RATE (wm->acc_rate);
++              dig3 |= WM9713_PDEN;
++      } else {
++              dig1 &= ~(WM9713_CTC | WM9713_COO);
++              dig2 &= ~WM97XX_SLEN;
++              dig3 &= ~WM9713_PDEN;
++        if (wm->mach_ops->acc_shutdown)
++            wm->mach_ops->acc_shutdown(wm);
++      }
++
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
++      return ret;
++}
++
++struct wm97xx_codec_drv wm97xx_codec = {
++      .id =   WM9713_ID2,
++    .name = "wm9713",
++      .poll_sample = wm9713_poll_sample,
++      .poll_touch = wm9713_poll_touch,
++      .acc_enable = wm9713_acc_enable,
++      .digitiser_ioctl = wm9713_digitiser_ioctl,
++};
++
++EXPORT_SYMBOL_GPL(wm97xx_codec);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
++MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.17/drivers/input/touchscreen/wm97xx-core.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.17/drivers/input/touchscreen/wm97xx-core.c       2006-09-19 20:36:47.969052000 +0200
+@@ -0,0 +1,912 @@
++/*
++ * wm97xx-core.c  --  Touch screen driver core for Wolfson WM9705, WM9712
++ *                    and WM9713 AC97 Codecs.
++ *
++ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.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 of the  License, or (at your
++ *  option) any later version.
++ *
++ * Notes:
++ *
++ *  Features:
++ *       - supports WM9705, WM9712, WM9713
++ *       - polling mode
++ *       - continuous mode (arch-dependent)
++ *       - adjustable rpu/dpp settings
++ *       - adjustable pressure current
++ *       - adjustable sample settle delay
++ *       - 4 and 5 wire touchscreens (5 wire is WM9712 only)
++ *       - pen down detection
++ *       - battery monitor
++ *       - sample AUX adc's
++ *       - power management
++ *       - codec GPIO
++ *       - codec event notification
++ * Todo
++ *       - Support for async sampling control for noisy LCD's.
++ *
++ *  Revision history
++ *    7th May 2003   Initial version.
++ *    6th June 2003  Added non module support and AC97 registration.
++ *   18th June 2003  Added AUX adc sampling.
++ *   23rd June 2003  Did some minimal reformatting, fixed a couple of
++ *                   codec_mutexing bugs and noted a race to fix.
++ *   24th June 2003  Added power management and fixed race condition.
++ *   10th July 2003  Changed to a misc device.
++ *   31st July 2003  Moved TS_EVENT and TS_CAL to wm97xx.h
++ *    8th Aug  2003  Added option for read() calling wm97xx_sample_touch()
++ *                   because some ac97_read/ac_97_write call schedule()
++ *    7th Nov  2003  Added Input touch event interface, stanley.cai@intel.com
++ *   13th Nov  2003  Removed h3600 touch interface, added interrupt based
++ *                   pen down notification and implemented continous mode
++ *                   on XScale arch.
++ *   16th Nov  2003  Ian Molton <spyro@f2s.com>
++ *                   Modified so that it suits the new 2.6 driver model.
++ *   25th Jan  2004  Andrew Zabolotny <zap@homelink.ru>
++ *                   Implemented IRQ-driven pen down detection, implemented
++ *                   the private API meant to be exposed to platform-specific
++ *                   drivers, reorganized the driver so that it supports
++ *                   an arbitrary number of devices.
++ *    1st Feb  2004  Moved continuous mode handling to a separate
++ *                   architecture-dependent file. For now only PXA
++ *                   built-in AC97 controller is supported (pxa-ac97-wm97xx.c).
++ *    11th Feb 2004  Reduced CPU usage by keeping a cached copy of both
++ *                   digitizer registers instead of reading them every time.
++ *                   A reorganization of the whole code for better
++ *                   error handling.
++ *    17th Apr 2004  Added BMON support.
++ *    17th Nov 2004  Added codec GPIO, codec event handling (real and virtual
++ *                   GPIOs) and 2.6 power management.
++ *    29th Nov 2004  Added WM9713 support.
++ *     4th Jul 2005  Moved codec specific code out to seperate files.
++ *     6th Sep 2006  Mike Arthur <linux@wolfsonmicro.com>
++ *                   Added bus interface.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/proc_fs.h>
++#include <linux/pm.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++#include <linux/workqueue.h>
++#include <linux/device.h>
++#include <linux/wm97xx.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM_CORE_VERSION               "0.63"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * WM97xx - enable/disable AUX ADC sysfs
++ */
++static int aux_sys = 1;
++module_param(aux_sys, int, 0);
++MODULE_PARM_DESC(aux_sys, "enable AUX ADC sysfs entries");
++
++/*
++ * WM97xx - enable/disable codec status sysfs
++ */
++static int status_sys = 1;
++module_param(status_sys, int, 0);
++MODULE_PARM_DESC(status_sys, "enable codec status sysfs entries");
++
++/*
++ * Touchscreen absolute values
++ *
++ * These parameters are used to help the input layer discard out of
++ * range readings and reduce jitter etc.
++ *
++ *   o min, max:- indicate the min and max values your touch screen returns
++ *   o fuzz:- use a higher number to reduce jitter
++ *
++ * The default values correspond to Mainstone II in QVGA mode
++ *
++ * Please read
++ * Documentation/input/input-programming.txt for more details.
++ */
++
++static int abs_x[3] = {350,3900,5};
++module_param_array(abs_x, int, NULL, 0);
++MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
++
++static int abs_y[3] = {320,3750,40};
++module_param_array(abs_y, int, NULL, 0);
++MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
++
++static int abs_p[3] = {0,150,4};
++module_param_array(abs_p, int, NULL, 0);
++MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz");
++
++/*
++ * Debug
++ */
++#if 0
++#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
++#else
++#define dbg(format, arg...)
++#endif
++#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
++#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
++
++/* codec AC97 IO access */
++int wm97xx_reg_read(struct wm97xx *wm, u16 reg)
++{
++      if (wm->ac97)
++              return wm->ac97->bus->ops->read(wm->ac97, reg);
++      else
++              return -1;
++}
++
++void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val)
++{
++      /* cache digitiser registers */
++      if(reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3)
++              wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val;
++
++      /* cache gpio regs */
++      if(reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE)
++              wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val;
++
++      /* wm9713 irq reg */
++      if(reg == 0x5a)
++              wm->misc = val;
++
++      if (wm->ac97)
++              wm->ac97->bus->ops->write(wm->ac97, reg, val);
++}
++
++
++/**
++ *    wm97xx_read_aux_adc - Read the aux adc.
++ *    @wm: wm97xx device.
++ *  @adcsel: codec ADC to be read
++ *
++ *    Reads the selected AUX ADC.
++ */
++
++int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
++{
++      int power_adc = 0, auxval;
++      u16 power = 0;
++
++      /* get codec */
++      mutex_lock(&wm->codec_mutex);
++
++      /* When the touchscreen is not in use, we may have to power up the AUX ADC
++       * before we can use sample the AUX inputs->
++       */
++      if (wm->id == WM9713_ID2 &&
++          (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) {
++              power_adc = 1;
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff);
++      }
++
++      /* Prepare the codec for AUX reading */
++      wm->codec->digitiser_ioctl(wm, WM97XX_AUX_PREPARE);
++
++      /* Turn polling mode on to read AUX ADC */
++      wm->pen_probably_down = 1;
++      wm->codec->poll_sample(wm, adcsel, &auxval);
++
++      if (power_adc)
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
++
++      wm->codec->digitiser_ioctl(wm, WM97XX_DIG_RESTORE);
++
++      wm->pen_probably_down = 0;
++
++      mutex_unlock(&wm->codec_mutex);
++      return auxval & 0xfff;
++}
++
++#define WM97XX_AUX_ATTR(name,input) \
++static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf)   \
++{ \
++      struct wm97xx *wm = (struct wm97xx*)dev->driver_data; \
++      return sprintf(buf, "%d\n", wm97xx_read_aux_adc(wm, input)); \
++} \
++static DEVICE_ATTR(name, 0444, name##_show, NULL)
++
++WM97XX_AUX_ATTR(aux1, WM97XX_AUX_ID1);
++WM97XX_AUX_ATTR(aux2, WM97XX_AUX_ID2);
++WM97XX_AUX_ATTR(aux3, WM97XX_AUX_ID3);
++WM97XX_AUX_ATTR(aux4, WM97XX_AUX_ID4);
++
++#define WM97XX_STATUS_ATTR(name) \
++static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf)   \
++{ \
++      struct wm97xx *wm = (struct wm97xx*)dev->driver_data; \
++      return sprintf(buf, "%d\n", wm97xx_reg_read(wm, AC97_GPIO_STATUS)); \
++} \
++static DEVICE_ATTR(name, 0444, name##_show, NULL)
++
++WM97XX_STATUS_ATTR(gpio);
++
++static int wm97xx_sys_add(struct device *dev)
++{
++      if (aux_sys) {
++              device_create_file(dev, &dev_attr_aux1);
++              device_create_file(dev, &dev_attr_aux2);
++              device_create_file(dev, &dev_attr_aux3);
++              device_create_file(dev, &dev_attr_aux4);
++      }
++      if (status_sys)
++              device_create_file(dev, &dev_attr_gpio);
++      return 0;
++}
++
++static void wm97xx_sys_remove(struct device *dev)
++{
++      if (status_sys)
++              device_remove_file(dev, &dev_attr_gpio);
++      if (aux_sys) {
++              device_remove_file(dev, &dev_attr_aux1);
++              device_remove_file(dev, &dev_attr_aux2);
++              device_remove_file(dev, &dev_attr_aux3);
++              device_remove_file(dev, &dev_attr_aux4);
++      }
++}
++
++/**
++ *    wm97xx_get_gpio - Get the status of a codec GPIO.
++ *    @wm: wm97xx device.
++ *  @gpio: gpio
++ *
++ *    Get the status of a codec GPIO pin
++ */
++
++wm97xx_gpio_status_t wm97xx_get_gpio(struct wm97xx *wm, u32 gpio)
++{
++      u16 status;
++      wm97xx_gpio_status_t ret;
++
++      mutex_lock(&wm->codec_mutex);
++      status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++
++      if (status & gpio)
++              ret = WM97XX_GPIO_HIGH;
++      else
++              ret = WM97XX_GPIO_LOW;
++
++      mutex_unlock(&wm->codec_mutex);
++      return ret;
++}
++
++/**
++ *    wm97xx_set_gpio - Set the status of a codec GPIO.
++ *    @wm: wm97xx device.
++ *  @gpio: gpio
++ *
++ *
++ *    Set the status of a codec GPIO pin
++ */
++
++void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
++                              wm97xx_gpio_status_t status)
++{
++      u16 reg;
++
++      mutex_lock(&wm->codec_mutex);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++
++      if (status & WM97XX_GPIO_HIGH)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      if (wm->id == WM9712_ID2)
++              wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
++      else
++              wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
++      mutex_unlock(&wm->codec_mutex);
++}
++
++/*
++ * Codec GPIO pin configuration, this set's pin direction, polarity,
++ * stickyness and wake up.
++ */
++void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, wm97xx_gpio_dir_t dir,
++                 wm97xx_gpio_pol_t pol, wm97xx_gpio_sticky_t sticky,
++                 wm97xx_gpio_wake_t wake)
++{
++      u16 reg;
++
++      mutex_lock(&wm->codec_mutex);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
++
++      if (pol == WM97XX_GPIO_POL_HIGH)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
++
++      if (sticky == WM97XX_GPIO_STICKY)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
++
++      if (wake == WM97XX_GPIO_WAKE)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
++
++      if (dir == WM97XX_GPIO_IN)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_CFG, reg);
++      mutex_unlock(&wm->codec_mutex);
++}
++
++/*
++ * Handle a pen down interrupt.
++ */
++static void wm97xx_pen_irq_worker(void *ptr)
++{
++      struct wm97xx *wm = (struct wm97xx *) ptr;
++
++      /* do we need to enable the touch panel reader */
++      if (wm->id == WM9705_ID2) {
++              if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN)
++                      wm->pen_is_down = 1;
++              else
++                      wm->pen_is_down = 0;
++              wake_up_interruptible(&wm->pen_irq_wait);
++      } else {
++              u16 status, pol;
++              mutex_lock(&wm->codec_mutex);
++              status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++              pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
++
++              if (WM97XX_GPIO_13 & pol & status) {
++                      wm->pen_is_down = 1;
++                      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol & ~WM97XX_GPIO_13);
++              } else {
++                      wm->pen_is_down = 0;
++                  wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol | WM97XX_GPIO_13);
++              }
++
++              if (wm->id == WM9712_ID2)
++                      wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & ~WM97XX_GPIO_13) << 1);
++              else
++                      wm97xx_reg_write(wm, AC97_GPIO_STATUS, status & ~WM97XX_GPIO_13);
++              mutex_unlock(&wm->codec_mutex);
++              wake_up_interruptible(&wm->pen_irq_wait);
++      }
++
++      if (!wm->pen_is_down && wm->mach_ops && wm->mach_ops->acc_enabled)
++              wm->mach_ops->acc_pen_up(wm);
++      enable_irq(wm->pen_irq);
++}
++
++/*
++ * Codec PENDOWN irq handler
++ *
++ * We have to disable the codec interrupt in the handler because it can
++ * take upto 1ms to clear the interrupt source. The interrupt is then enabled
++ * again in the slow handler when the source has been cleared.
++ */
++static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id,
++                                      struct pt_regs *regs)
++{
++      struct wm97xx *wm = (struct wm97xx *) dev_id;
++      disable_irq(wm->pen_irq);
++      queue_work(wm->pen_irq_workq, &wm->pen_event_work);
++      return IRQ_HANDLED;
++}
++
++/*
++ * initialise pen IRQ handler and workqueue
++ */
++static int wm97xx_init_pen_irq(struct wm97xx *wm)
++{
++      u16 reg;
++
++      INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker, wm);
++      if ((wm->pen_irq_workq =
++              create_singlethread_workqueue("kwm97pen")) == NULL) {
++              err("could not create pen irq work queue");
++              wm->pen_irq = 0;
++              return -EINVAL;
++      }
++
++      if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, SA_SHIRQ, "wm97xx-pen", wm)) {
++              err("could not register codec pen down interrupt, will poll for pen down");
++              destroy_workqueue(wm->pen_irq_workq);
++              wm->pen_irq = 0;
++              return -EINVAL;
++      }
++
++      /* enable PEN down on wm9712/13 */
++      if (wm->id != WM9705_ID2) {
++              reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
++              wm97xx_reg_write(wm, AC97_MISC_AFE, reg & 0xfffb);
++              reg = wm97xx_reg_read(wm, 0x5a);
++              wm97xx_reg_write(wm, 0x5a, reg & ~0x0001);
++      }
++
++      return 0;
++}
++
++/* Private struct for communication between struct wm97xx_tshread
++ * and wm97xx_read_samples */
++struct ts_state {
++      int sleep_time;
++      int min_sleep_time;
++};
++
++static int wm97xx_read_samples(struct wm97xx *wm, struct ts_state *state)
++{
++      struct wm97xx_data data;
++      int rc;
++
++      mutex_lock(&wm->codec_mutex);
++
++    if (wm->mach_ops && wm->mach_ops->acc_enabled)
++         rc = wm->mach_ops->acc_pen_down(wm);
++    else
++        rc = wm->codec->poll_touch(wm, &data);
++
++      if (rc & RC_PENUP) {
++              if (wm->pen_is_down) {
++                      wm->pen_is_down = 0;
++                      dbg("pen up");
++                      input_report_abs(wm->input_dev, ABS_PRESSURE, 0);
++                      input_sync(wm->input_dev);
++              } else if (!(rc & RC_AGAIN)) {
++                      /* We need high frequency updates only while pen is down,
++                      * the user never will be able to touch screen faster than
++                      * a few times per second... On the other hand, when the
++                      * user is actively working with the touchscreen we don't
++                      * want to lose the quick response. So we will slowly
++                      * increase sleep time after the pen is up and quicky
++                      * restore it to ~one task switch when pen is down again.
++                      */
++                      if (state->sleep_time < HZ / 10)
++                              state->sleep_time++;
++              }
++
++      } else if (rc & RC_VALID) {
++              dbg("pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
++                      data.x >> 12, data.x & 0xfff, data.y >> 12,
++                      data.y & 0xfff, data.p >> 12, data.p & 0xfff);
++              input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
++              input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
++              input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
++              input_sync(wm->input_dev);
++              wm->pen_is_down = 1;
++              state->sleep_time = state->min_sleep_time;
++      } else if (rc & RC_PENDOWN) {
++              dbg("pen down");
++              wm->pen_is_down = 1;
++              state->sleep_time = state->min_sleep_time;
++      }
++
++      mutex_unlock(&wm->codec_mutex);
++      return rc;
++}
++
++/*
++* The touchscreen sample reader thread.
++*/
++static int wm97xx_ts_read(void *data)
++{
++      int rc;
++      struct ts_state state;
++      struct wm97xx *wm = (struct wm97xx *) data;
++
++      /* set up thread context */
++      wm->ts_task = current;
++      daemonize("kwm97xxts");
++
++      if (wm->codec == NULL) {
++              wm->ts_task = NULL;
++              printk(KERN_ERR "codec is NULL, bailing\n");
++      }
++
++      complete(&wm->ts_init);
++      wm->pen_is_down = 0;
++      state.min_sleep_time = HZ >= 100 ? HZ / 100 : 1;
++      if (state.min_sleep_time < 1)
++              state.min_sleep_time = 1;
++      state.sleep_time = state.min_sleep_time;
++
++      /* touch reader loop */
++      while (wm->ts_task) {
++              do {
++                      try_to_freeze();
++                      rc = wm97xx_read_samples(wm, &state);
++              } while (rc & RC_AGAIN);
++              if (!wm->pen_is_down && wm->pen_irq) {
++                      /* Nice, we don't have to poll for pen down event */
++                      wait_event_interruptible(wm->pen_irq_wait, wm->pen_is_down);
++              } else {
++                      set_task_state(current, TASK_INTERRUPTIBLE);
++                      schedule_timeout(state.sleep_time);
++              }
++      }
++      complete_and_exit(&wm->ts_exit, 0);
++}
++
++/**
++ *    wm97xx_ts_input_open - Open the touch screen input device.
++ *    @idev:  Input device to be opened.
++ *
++ *    Called by the input sub system to open a wm97xx touchscreen device.
++ *  Starts the touchscreen thread and touch digitiser.
++ */
++static int wm97xx_ts_input_open(struct input_dev *idev)
++{
++      int ret = 0;
++      struct wm97xx *wm = (struct wm97xx *) idev->private;
++
++      mutex_lock(&wm->codec_mutex);
++      /* first time opened ? */
++      if (wm->ts_use_count++ == 0) {
++              /* start touchscreen thread */
++              init_completion(&wm->ts_init);
++              init_completion(&wm->ts_exit);
++              ret = kernel_thread(wm97xx_ts_read, wm, CLONE_KERNEL);
++
++              if (ret >= 0) {
++                      wait_for_completion(&wm->ts_init);
++                      if (wm->ts_task == NULL)
++                              ret = -EINVAL;
++              } else {
++                      mutex_unlock(&wm->codec_mutex);
++                      return ret;
++              }
++
++              /* start digitiser */
++        if (wm->mach_ops && wm->mach_ops->acc_enabled)
++            wm->codec->acc_enable(wm, 1);
++              wm->codec->digitiser_ioctl(wm, WM97XX_DIG_START);
++
++              /* init pen down/up irq handling */
++              if (wm->pen_irq) {
++                      wm97xx_init_pen_irq(wm);
++
++                      if (wm->pen_irq == 0) {
++                              /* we failed to get an irq for pen down events,
++                               * so we resort to polling. kickstart the reader */
++                              wm->pen_is_down = 1;
++                              wake_up_interruptible(&wm->pen_irq_wait);
++                      }
++              }
++      }
++
++      mutex_unlock(&wm->codec_mutex);
++      return 0;
++}
++
++/**
++ *    wm97xx_ts_input_close - Close the touch screen input device.
++ *    @idev:  Input device to be closed.
++ *
++ *    Called by the input sub system to close a wm97xx touchscreen device.
++ *  Kills the touchscreen thread and stops the touch digitiser.
++ */
++
++static void wm97xx_ts_input_close(struct input_dev *idev)
++{
++      struct wm97xx *wm = (struct wm97xx *) idev->private;
++
++      mutex_lock(&wm->codec_mutex);
++      if (--wm->ts_use_count == 0) {
++              /* destroy workqueues and free irqs */
++              if (wm->pen_irq) {
++                      free_irq(wm->pen_irq, wm);
++                      destroy_workqueue(wm->pen_irq_workq);
++              }
++
++              /* kill thread */
++              if (wm->ts_task) {
++                      wm->ts_task = NULL;
++                      wm->pen_is_down = 1;
++                      wake_up_interruptible(&wm->pen_irq_wait);
++                      wait_for_completion(&wm->ts_exit);
++                      wm->pen_is_down = 0;
++              }
++
++              /* stop digitiser */
++              wm->codec->digitiser_ioctl(wm, WM97XX_DIG_STOP);
++              if (wm->mach_ops && wm->mach_ops->acc_enabled)
++                      wm->codec->acc_enable(wm, 0);
++      }
++      mutex_unlock(&wm->codec_mutex);
++}
++
++static int wm97xx_bus_match(struct device *dev, struct device_driver *drv)
++{
++    return !(strcmp(dev->bus_id,drv->name));
++}
++
++/*
++ * The AC97 audio driver will do all the Codec suspend and resume
++ * tasks. This is just for anything machine specific or extra.
++ */
++static int wm97xx_bus_suspend(struct device *dev, pm_message_t state)
++{
++    int ret = 0;
++
++    if (dev->driver && dev->driver->suspend)
++        ret = dev->driver->suspend(dev, state);
++
++    return ret;
++}
++
++static int wm97xx_bus_resume(struct device *dev)
++{
++    int ret = 0;
++
++    if (dev->driver && dev->driver->resume)
++        ret = dev->driver->resume(dev);
++
++    return ret;
++}
++
++struct bus_type wm97xx_bus_type = {
++    .name       = "wm97xx",
++    .match      = wm97xx_bus_match,
++    .suspend    = wm97xx_bus_suspend,
++    .resume     = wm97xx_bus_resume,
++};
++
++static void  wm97xx_release(struct device *dev)
++{
++    kfree(dev);
++}
++
++static int wm97xx_probe(struct device *dev)
++{
++      struct wm97xx* wm;
++      int ret = 0, id = 0;
++
++      if (!(wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL)))
++              return -ENOMEM;
++    mutex_init(&wm->codec_mutex);
++
++      init_waitqueue_head(&wm->pen_irq_wait);
++      wm->dev = dev;
++      dev->driver_data = wm;
++      wm->ac97 = to_ac97_t(dev);
++
++      /* check that we have a supported codec */
++      if ((id = wm97xx_reg_read(wm, AC97_VENDOR_ID1)) != WM97XX_ID1) {
++              err("could not find a wm97xx, found a %x instead\n", id);
++              kfree(wm);
++              return -ENODEV;
++      }
++
++      wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
++      if(wm->id != wm97xx_codec.id) {
++              err("could not find a the selected codec, please build for wm97%2x", wm->id & 0xff);
++              kfree(wm);
++              return -ENODEV;
++      }
++
++      if((wm->input_dev = input_allocate_device()) == NULL) {
++        kfree(wm);
++              return -ENOMEM;
++    }
++
++      /* set up touch configuration */
++      info("detected a wm97%2x codec", wm->id & 0xff);
++      wm->input_dev->name = "wm97xx touchscreen";
++      wm->input_dev->open = wm97xx_ts_input_open;
++      wm->input_dev->close = wm97xx_ts_input_close;
++      set_bit(EV_ABS, wm->input_dev->evbit);
++      set_bit(ABS_X, wm->input_dev->absbit);
++      set_bit(ABS_Y, wm->input_dev->absbit);
++      set_bit(ABS_PRESSURE, wm->input_dev->absbit);
++      wm->input_dev->absmax[ABS_X] = abs_x[1];
++      wm->input_dev->absmax[ABS_Y] = abs_y[1];
++      wm->input_dev->absmax[ABS_PRESSURE] = abs_p[1];
++      wm->input_dev->absmin[ABS_X] = abs_x[0];
++      wm->input_dev->absmin[ABS_Y] = abs_y[0];
++      wm->input_dev->absmin[ABS_PRESSURE] = abs_p[0];
++      wm->input_dev->absfuzz[ABS_X] = abs_x[2];
++      wm->input_dev->absfuzz[ABS_Y] = abs_y[2];
++      wm->input_dev->absfuzz[ABS_PRESSURE] = abs_p[2];
++      wm->input_dev->private = wm;
++      wm->codec = &wm97xx_codec;
++      if((ret = input_register_device(wm->input_dev)) < 0) {
++              kfree(wm);
++              return -ENOMEM;
++    }
++
++      if(aux_sys)
++              wm97xx_sys_add(dev);
++
++      /* set up physical characteristics */
++      wm->codec->digitiser_ioctl(wm, WM97XX_PHY_INIT);
++
++      /* load gpio cache */
++      wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
++      wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
++      wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
++      wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
++      wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++      wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
++
++      /* register our battery device */
++    if (!(wm->battery_dev = kzalloc(sizeof(struct device), GFP_KERNEL))) {
++      ret = -ENOMEM;
++        goto batt_err;
++    }
++    wm->battery_dev->bus = &wm97xx_bus_type;
++    strcpy(wm->battery_dev->bus_id,"wm97xx-battery");
++    wm->battery_dev->driver_data = wm;
++    wm->battery_dev->parent = dev;
++    wm->battery_dev->release = wm97xx_release;
++    if((ret = device_register(wm->battery_dev)) < 0)
++      goto batt_reg_err;
++
++      /* register our extended touch device (for machine specific extensions) */
++    if (!(wm->touch_dev = kzalloc(sizeof(struct device), GFP_KERNEL))) {
++      ret = -ENOMEM;
++        goto touch_err;
++    }
++    wm->touch_dev->bus = &wm97xx_bus_type;
++    strcpy(wm->touch_dev->bus_id,"wm97xx-touchscreen");
++    wm->touch_dev->driver_data = wm;
++    wm->touch_dev->parent = dev;
++    wm->touch_dev->release = wm97xx_release;
++    if((ret = device_register(wm->touch_dev)) < 0)
++      goto touch_reg_err;
++
++    return ret;
++
++touch_reg_err:
++      kfree(wm->touch_dev);
++touch_err:
++    device_unregister(wm->battery_dev);
++batt_reg_err:
++      kfree(wm->battery_dev);
++batt_err:
++    input_unregister_device(wm->input_dev);
++    kfree(wm);
++    return ret;
++}
++
++static int wm97xx_remove(struct device *dev)
++{
++      struct wm97xx *wm = dev_get_drvdata(dev);
++
++      /* Stop touch reader thread */
++      if (wm->ts_task) {
++              wm->ts_task = NULL;
++              wm->pen_is_down = 1;
++              wake_up_interruptible(&wm->pen_irq_wait);
++              wait_for_completion(&wm->ts_exit);
++      }
++      device_unregister(wm->battery_dev);
++      device_unregister(wm->touch_dev);
++    input_unregister_device(wm->input_dev);
++
++      if(aux_sys)
++              wm97xx_sys_remove(dev);
++
++      kfree(wm);
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int wm97xx_resume(struct device* dev)
++{
++      struct wm97xx *wm = dev_get_drvdata(dev);
++
++      /* restore digitiser and gpio's */
++      if(wm->id == WM9713_ID2) {
++              wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
++              wm97xx_reg_write(wm, 0x5a, wm->misc);
++              if(wm->ts_use_count) {
++                      u16 reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff;
++                      wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
++              }
++      }
++
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]);
++
++      wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]);
++      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]);
++      wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]);
++      wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]);
++      wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]);
++      wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]);
++
++      return 0;
++}
++
++#else
++#define wm97xx_resume         NULL
++#endif
++
++int wm97xx_register_mach_ops(struct wm97xx *wm, struct wm97xx_mach_ops *mach_ops)
++{
++      mutex_lock(&wm->codec_mutex);
++    if(wm->mach_ops) {
++      mutex_unlock(&wm->codec_mutex);
++      return -EINVAL;
++    }
++    wm->mach_ops = mach_ops;
++    mutex_unlock(&wm->codec_mutex);
++    return 0;
++}
++
++void wm97xx_unregister_mach_ops(struct wm97xx *wm)
++{
++      mutex_lock(&wm->codec_mutex);
++    wm->mach_ops = NULL;
++    mutex_unlock(&wm->codec_mutex);
++}
++
++static struct device_driver wm97xx_driver = {
++      .name =         "ac97",
++      .bus =          &ac97_bus_type,
++      .owner =        THIS_MODULE,
++      .probe =        wm97xx_probe,
++      .remove =       wm97xx_remove,
++      .resume =       wm97xx_resume,
++};
++
++static int __init wm97xx_init(void)
++{
++      int ret;
++
++      info("version %s liam.girdwood@wolfsonmicro.com", WM_CORE_VERSION);
++    if((ret = bus_register(&wm97xx_bus_type)) < 0)
++      return ret;
++      return driver_register(&wm97xx_driver);
++}
++
++static void __exit wm97xx_exit(void)
++{
++      driver_unregister(&wm97xx_driver);
++    bus_unregister(&wm97xx_bus_type);
++}
++
++EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
++EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
++EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
++EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
++EXPORT_SYMBOL_GPL(wm97xx_reg_read);
++EXPORT_SYMBOL_GPL(wm97xx_reg_write);
++EXPORT_SYMBOL_GPL(wm97xx_bus_type);
++EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops);
++EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
++
++module_init(wm97xx_init);
++module_exit(wm97xx_exit);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
++MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.17/include/linux/wm97xx.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.17/include/linux/wm97xx.h        2006-09-19 20:36:47.973052250 +0200
+@@ -0,0 +1,291 @@
++
++/*
++ * Register bits and API for Wolfson WM97xx series of codecs
++ */
++
++#ifndef _LINUX_WM97XX_H
++#define _LINUX_WM97XX_H
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/ac97_codec.h>
++#include <sound/initval.h>
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/input.h>      /* Input device layer */
++
++/*
++ * WM97xx AC97 Touchscreen registers
++ */
++#define AC97_WM97XX_DIGITISER1                0x76
++#define AC97_WM97XX_DIGITISER2                0x78
++#define AC97_WM97XX_DIGITISER_RD      0x7a
++#define AC97_WM9713_DIG1                      0x74
++#define AC97_WM9713_DIG2                      AC97_WM97XX_DIGITISER1
++#define AC97_WM9713_DIG3                      AC97_WM97XX_DIGITISER2
++
++/*
++ * WM97xx register bits
++ */
++#define WM97XX_POLL                   0x8000  /* initiate a polling measurement */
++#define WM97XX_ADCSEL_X               0x1000  /* x coord measurement */
++#define WM97XX_ADCSEL_Y               0x2000  /* y coord measurement */
++#define WM97XX_ADCSEL_PRES    0x3000  /* pressure measurement */
++#define WM97XX_ADCSEL_MASK    0x7000
++#define WM97XX_COO                    0x0800  /* enable coordinate mode */
++#define WM97XX_CTC                    0x0400  /* enable continuous mode */
++#define WM97XX_CM_RATE_93     0x0000  /* 93.75Hz continuous rate */
++#define WM97XX_CM_RATE_187    0x0100  /* 187.5Hz continuous rate */
++#define WM97XX_CM_RATE_375    0x0200  /* 375Hz continuous rate */
++#define WM97XX_CM_RATE_750    0x0300  /* 750Hz continuous rate */
++#define WM97XX_CM_RATE_8K     0x00f0  /* 8kHz continuous rate */
++#define WM97XX_CM_RATE_12K    0x01f0  /* 12kHz continuous rate */
++#define WM97XX_CM_RATE_24K    0x02f0  /* 24kHz continuous rate */
++#define WM97XX_CM_RATE_48K    0x03f0  /* 48kHz continuous rate */
++#define WM97XX_CM_RATE_MASK   0x03f0
++#define WM97XX_RATE(i)                (((i & 3) << 8) | ((i & 4) ? 0xf0 : 0))
++#define WM97XX_DELAY(i)               ((i << 4) & 0x00f0)     /* sample delay times */
++#define WM97XX_DELAY_MASK     0x00f0
++#define WM97XX_SLEN                   0x0008  /* slot read back enable */
++#define WM97XX_SLT(i)         ((i - 5) & 0x7) /* touchpanel slot selection (5-11) */
++#define WM97XX_SLT_MASK               0x0007
++#define WM97XX_PRP_DETW               0x4000  /* pen detect on, digitiser off, wake up */
++#define WM97XX_PRP_DET                0x8000  /* pen detect on, digitiser off, no wake up */
++#define WM97XX_PRP_DET_DIG    0xc000  /* pen detect on, digitiser on */
++#define WM97XX_RPR                    0x2000  /* wake up on pen down */
++#define WM97XX_PEN_DOWN               0x8000  /* pen is down */
++#define WM97XX_ADCSRC_MASK    0x7000  /* ADC source mask */
++
++#define WM97XX_AUX_ID1                0x8001
++#define WM97XX_AUX_ID2                0x8002
++#define WM97XX_AUX_ID3                0x8003
++#define WM97XX_AUX_ID4                0x8004
++
++
++/* WM9712 Bits */
++#define WM9712_45W                    0x1000  /* set for 5-wire touchscreen */
++#define WM9712_PDEN                   0x0800  /* measure only when pen down */
++#define WM9712_WAIT                   0x0200  /* wait until adc is read before next sample */
++#define WM9712_PIL                    0x0100  /* current used for pressure measurement. set 400uA else 200uA */
++#define WM9712_MASK_HI                0x0040  /* hi on mask pin (47) stops conversions */
++#define WM9712_MASK_EDGE      0x0080  /* rising/falling edge on pin delays sample */
++#define       WM9712_MASK_SYNC        0x00c0  /* rising/falling edge on mask initiates sample */
++#define WM9712_RPU(i)         (i&0x3f)        /* internal pull up on pen detect (64k / rpu) */
++#define WM9712_PD(i)          (0x1 << i)      /* power management */
++
++/* WM9712 Registers */
++#define AC97_WM9712_POWER     0x24
++#define AC97_WM9712_REV               0x58
++
++/* WM9705 Bits */
++#define WM9705_PDEN                   0x1000  /* measure only when pen is down */
++#define WM9705_PINV                   0x0800  /* inverts sense of pen down output */
++#define WM9705_BSEN                   0x0400  /* BUSY flag enable, pin47 is 1 when busy */
++#define WM9705_BINV                   0x0200  /* invert BUSY (pin47) output */
++#define WM9705_WAIT                   0x0100  /* wait until adc is read before next sample */
++#define WM9705_PIL                    0x0080  /* current used for pressure measurement. set 400uA else 200uA */
++#define WM9705_PHIZ                   0x0040  /* set PHONE and PCBEEP inputs to high impedance */
++#define WM9705_MASK_HI                0x0010  /* hi on mask stops conversions */
++#define WM9705_MASK_EDGE      0x0020  /* rising/falling edge on pin delays sample */
++#define       WM9705_MASK_SYNC        0x0030  /* rising/falling edge on mask initiates sample */
++#define WM9705_PDD(i)         (i & 0x000f)    /* pen detect comparator threshold */
++
++
++/* WM9713 Bits */
++#define WM9713_PDPOL          0x0400  /* Pen down polarity */
++#define WM9713_POLL                   0x0200  /* initiate a polling measurement */
++#define WM9713_CTC                    0x0100  /* enable continuous mode */
++#define WM9713_ADCSEL_X               0x0002  /* X measurement */
++#define WM9713_ADCSEL_Y               0x0004  /* Y measurement */
++#define WM9713_ADCSEL_PRES    0x0008  /* Pressure measurement */
++#define WM9713_COO                    0x0001  /* enable coordinate mode */
++#define WM9713_PDEN                   0x0800  /* measure only when pen down */
++#define WM9713_ADCSEL_MASK    0x00fe  /* ADC selection mask */
++#define WM9713_WAIT                   0x0200  /* coordinate wait */
++
++/* AUX ADC ID's */
++#define TS_COMP1                      0x0
++#define TS_COMP2                      0x1
++#define TS_BMON                               0x2
++#define TS_WIPER                      0x3
++
++/* ID numbers */
++#define WM97XX_ID1                    0x574d
++#define WM9712_ID2                    0x4c12
++#define WM9705_ID2                    0x4c05
++#define WM9713_ID2                    0x4c13
++
++/* Codec GPIO's */
++#define WM97XX_MAX_GPIO               16
++#define WM97XX_GPIO_1         (1 << 1)
++#define WM97XX_GPIO_2         (1 << 2)
++#define WM97XX_GPIO_3         (1 << 3)
++#define WM97XX_GPIO_4         (1 << 4)
++#define WM97XX_GPIO_5         (1 << 5)
++#define WM97XX_GPIO_6         (1 << 6)
++#define WM97XX_GPIO_7         (1 << 7)
++#define WM97XX_GPIO_8         (1 << 8)
++#define WM97XX_GPIO_9         (1 << 9)
++#define WM97XX_GPIO_10                (1 << 10)
++#define WM97XX_GPIO_11                (1 << 11)
++#define WM97XX_GPIO_12                (1 << 12)
++#define WM97XX_GPIO_13                (1 << 13)
++#define WM97XX_GPIO_14                (1 << 14)
++#define WM97XX_GPIO_15                (1 << 15)
++
++
++#define AC97_LINK_FRAME               21      /* time in uS for AC97 link frame */
++
++
++/*---------------- Return codes from sample reading functions ---------------*/
++
++/* More data is available; call the sample gathering function again */
++#define RC_AGAIN                      0x00000001
++/* The returned sample is valid */
++#define RC_VALID                      0x00000002
++/* The pen is up (the first RC_VALID without RC_PENUP means pen is down) */
++#define RC_PENUP                      0x00000004
++/* The pen is down (RC_VALID implies RC_PENDOWN, but sometimes it is helpful
++   to tell the handler that the pen is down but we don't know yet his coords,
++   so the handler should not sleep or wait for pendown irq) */
++#define RC_PENDOWN                    0x00000008
++
++/* The wm97xx driver provides a private API for writing platform-specific
++ * drivers.
++ */
++
++/* The structure used to return arch specific sampled data into */
++struct wm97xx_data {
++    int x;
++    int y;
++    int p;
++};
++
++/* Codec GPIO status
++ */
++typedef enum {
++    WM97XX_GPIO_HIGH,
++    WM97XX_GPIO_LOW
++} wm97xx_gpio_status_t;
++
++/* Codec GPIO direction
++ */
++typedef enum {
++    WM97XX_GPIO_IN,
++    WM97XX_GPIO_OUT
++} wm97xx_gpio_dir_t;
++
++/* Codec GPIO polarity
++ */
++typedef enum {
++    WM97XX_GPIO_POL_HIGH,
++    WM97XX_GPIO_POL_LOW
++} wm97xx_gpio_pol_t;
++
++/* Codec GPIO sticky
++ */
++typedef enum {
++    WM97XX_GPIO_STICKY,
++    WM97XX_GPIO_NOTSTICKY
++} wm97xx_gpio_sticky_t;
++
++/* Codec GPIO wake
++ */
++typedef enum {
++    WM97XX_GPIO_WAKE,
++    WM97XX_GPIO_NOWAKE
++} wm97xx_gpio_wake_t;
++
++
++/*
++ * Digitiser ioctl commands
++ */
++#define WM97XX_DIG_START      0x1
++#define WM97XX_DIG_STOP               0x2
++#define WM97XX_PHY_INIT               0x3
++#define WM97XX_AUX_PREPARE    0x4
++#define WM97XX_DIG_RESTORE    0x5
++
++struct wm97xx;
++extern struct wm97xx_codec_drv wm97xx_codec;
++
++/*
++ * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
++ */
++struct wm97xx_codec_drv {
++      u16 id;
++    char *name;
++      int (*poll_sample) (struct wm97xx *, int adcsel, int *sample);  /* read 1 sample */
++      int (*poll_touch) (struct wm97xx *, struct wm97xx_data *);      /* read X,Y,[P] in poll */
++      int (*digitiser_ioctl) (struct wm97xx *, int cmd);
++      int (*acc_enable) (struct wm97xx *, int enable);
++};
++
++
++/* Machine specific and accelerated touch operations */
++struct wm97xx_mach_ops {
++
++      /* accelerated touch readback - coords are transmited on AC97 link */
++      int acc_enabled;
++    void (*acc_pen_up) (struct wm97xx *);
++    int (*acc_pen_down) (struct wm97xx *);
++    int (*acc_startup) (struct wm97xx *);
++    void (*acc_shutdown) (struct wm97xx *);
++
++    /* pre and post sample - can be used to minimise any analog noise */
++    void (*pre_sample) (int);  /* function to run before sampling */
++    void (*post_sample) (int);  /* function to run after sampling */
++};
++
++struct wm97xx {
++      u16 dig[3], id, gpio[6], misc;  /* Cached codec registers */
++      u16 dig_save[3];                /* saved during aux reading */
++      struct wm97xx_codec_drv *codec; /* attached codec driver*/
++      struct input_dev* input_dev;    /* touchscreen input device */
++      ac97_t *ac97;                   /* ALSA codec access */
++      struct device *dev;             /* ALSA device */
++    struct device *battery_dev;
++    struct device *touch_dev;
++    struct wm97xx_mach_ops *mach_ops;
++    struct mutex codec_mutex;
++      struct completion ts_init;
++      struct completion ts_exit;
++      struct task_struct *ts_task;
++      unsigned int pen_irq;   /* Pen IRQ number in use */
++      wait_queue_head_t pen_irq_wait; /* Pen IRQ wait queue */
++      struct workqueue_struct *pen_irq_workq;
++      struct work_struct pen_event_work;
++      u16 acc_slot; /* AC97 slot used for acc touch data */
++      u16 acc_rate; /* acc touch data rate */
++      unsigned int ts_use_count;
++      unsigned pen_is_down:1; /* Pen is down */
++      unsigned aux_waiting:1; /* aux measurement waiting */
++      unsigned pen_probably_down:1;   /* used in polling mode */
++};
++
++/* Codec GPIO access (not supported on WM9705)
++ * This can be used to set/get codec GPIO and Virtual GPIO status.
++ */
++wm97xx_gpio_status_t wm97xx_get_gpio(struct wm97xx *wm, u32 gpio);
++void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
++                        wm97xx_gpio_status_t status);
++void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio,
++                                   wm97xx_gpio_dir_t dir,
++                                   wm97xx_gpio_pol_t pol,
++                                   wm97xx_gpio_sticky_t sticky,
++                                   wm97xx_gpio_wake_t wake);
++
++/* codec AC97 IO access */
++int wm97xx_reg_read(struct wm97xx *wm, u16 reg);
++void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val);
++
++/* aux adc readback */
++int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel);
++
++/* machine ops */
++int wm97xx_register_mach_ops(struct wm97xx *, struct wm97xx_mach_ops *);
++void wm97xx_unregister_mach_ops(struct wm97xx *);
++
++extern struct bus_type wm97xx_bus_type;
++#endif
index 353e8c1fc3a1b9729b484ff18a75fa41b9905244..efffb6e40475d5cf28ed6a9d9a249891d39ff083 100644 (file)
@@ -1,6 +1,6 @@
 require linux-rp.inc
 
-PR = "r2"
+PR = "r4"
 
 DEFAULT_PREFERENCE = "-1"
 
@@ -17,43 +17,44 @@ DEFAULT_PREFERENCE = "-1"
 # Hacks should clearly named and at the bottom
 SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
            ${KERNELORG_MIRROR}pub/linux/kernel/v2.6/testing/patch-2.6.24-rc8.bz2;patch=1 \
-           ${RPSRC}/lzo_crypto-r2.patch;patch=1 \
+           ${RPSRC}/export_atags-r2.patch;patch=1;status=pending \
+           ${RPSRC}/lzo_crypto-r2.patch;patch=1;status=pending \
+           ${RPSRC}/corgi_rearrange_lcd-r0.patch;patch=1;status=pending \
            ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \
-           file://hx2750_base-r31.patch;patch=1 \
+           ${RPSRC}/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-r17.patch;patch=1 \
            ${RPSRC}/hx2750_test1-r7.patch;patch=1 \
            ${RPSRC}/input_power-r10.patch;patch=1 \
-           ${RPSRC}/input_power_fix-r0.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 \
            ${RPSRC}/usb_add_epalloc-r4.patch;patch=1 \
-           ${RPSRC}/usb_pxa27x_udc-r7.patch;patch=1 \
+           ${RPSRC}/usb_pxa27x_udc-r8.patch;patch=1 \
            ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \
-           ${RPSRC}/poodle_pm-r5.patch;patch=1 \
-           file://pxa27x_overlay-r8.patch;patch=1 \
-           ${RPSRC}/w100_extaccel-r1.patch;patch=1 \
+           ${RPSRC}/pxa27x_overlay-r8.patch;patch=1 \
+           ${RPSRC}/w100_extaccel-r2.patch;patch=1 \
            ${RPSRC}/w100_extmem-r1.patch;patch=1 \
-           ${RPSRC}/export_atags-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}/poodle_pm-r5.patch;patch=1 \
+           ${RPSRC}/poodle_lcd_hack-r0.patch;patch=1 \
+           ${RPSRC}/poodle_asoc_fix-r1.patch;patch=1 \
+           file://squashfs3.3.patch;patch=1;status=external \
            ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \
            ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \
+           file://hostap-monitor-mode.patch;patch=1;status=unmergable \
+           file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1;status=unmergable \
            ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \
-           file://mmcsd_no_scr_check-r2.patch;patch=1 \
+           ${RPSRC}/mmcsd_no_scr_check-r2.patch;patch=1;status=hack \
            ${RPSRC}/integrator_rgb-r1.patch;patch=1;status=hack \
            ${RPSRC}/pxa_cf_initorder_hack-r1.patch;patch=1;status=hack \
-           ${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.2-2.6.20-r0.patch;patch=1;status=external \
+           file://connectplus-prevent-oops-HACK.patch;patch=1;status=hack \
 #          file://htcuni.patch;patch=1 \
            file://binutils-buildid-arm.patch;patch=1 \
-          file://versatile-armv6.patch;patch=1 \
+           file://versatile-armv6.patch;patch=1 \
            file://defconfig-c7x0 \
            file://defconfig-hx2000 \
            file://defconfig-collie \
@@ -84,36 +85,51 @@ SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
 # These patches are extracted from Pavel Machek's git tree
 # (diff against vanilla kernel)
 SRC_URI_append_collie = "\
-           ${DOSRC}/collie/mtd-sharp-flash-hack-r0.patch;patch=1 \
-           ${DOSRC}/collie/collie-r0.patch;patch=1 \
-           ${DOSRC}/collie/locomolcd-backlight-r0.patch;patch=1 \
-           ${DOSRC}/collie/ucb1x00-touch-audio-r0.patch;patch=1 \
-           file://collie-mcp-r1.patch;patch=1 \
-           ${DOSRC}/collie/sa1100-udc-r0.patch;patch=1 \
-#          ${DOSRC}/collie/collie-pm-r1.patch;patch=1 \
+       ${TKSRC}/mtd-sharp-flash-hack-r3.patch;patch=1 \
+       ${TKSRC}/mcp-sa11x0-r0.patch;patch=1 \
+       ${TKSRC}/locomo-r0.patch;patch=1 \
+#      ${TKSRC}/locomo_spi-4.patch;patch=1 \
+       ${TKSRC}/collie-kexec.patch;patch=1 \
+       ${TKSRC}/sharpsl_pm-3.patch;patch=1 \
+       ${TKSRC}/collie_pm-2.patch;patch=1 \
+       ${TKSRC}/locomokeyb_suspendkey-2.patch;patch=1 \
+       ${TKSRC}/ucb1x00_suspend.patch;patch=1 \
+       ${TKSRC}/collie-ts.patch;patch=1 \
+       ${TKSRC}/pcmcia_suspend.patch;patch=1 \
+"
+
+SRC_URI_append_poodle = "\
+           ${RPSRC}/poodle_serial_vcc-r0.patch;patch=1 \
 "
 
 SRC_URI_append_tosa = "\
-           ${CHSRC}/usb-ohci-hooks-r1.patch;patch=1 \
            ${CHSRC}/tmio-core-r4.patch;patch=1 \
            file://tmio-tc6393-r8.patch;patch=1 \
-           file://tmio-nand-r7.patch;patch=1 \
-           file://tmio-ohci-r6.patch;patch=1 \
+           file://tmio-nand-r8.patch;patch=1 \
            ${CHSRC}/tmio-fb-r6.patch;patch=1 \
-           file://tosa-keyboard-r18.patch;patch=1 \
+           file://tmio-fb-r6-fix-r0.patch;patch=1 \
+           file://tosa-keyboard-r19.patch;patch=1 \
            ${DOSRC}/tosa-pxaac97-r6.patch;patch=1 \
+           file://tosa-pxaac97-r6-fix-r0.patch;patch=1 \
            ${DOSRC}/tosa-tmio-r6.patch;patch=1 \
-           ${DOSRC}/tosa-power-r17.patch;patch=1 \
+           file://tosa-power-r18.patch;patch=1 \
+           file://tosa-power-r18-fix-r0.patch;patch=1 \
            file://tosa-tmio-lcd-r10.patch;patch=1 \
-           ${DOSRC}/tosa-bluetooth-r8.patch;patch=1 \
-           ${DOSRC}/wm97xx-lg7-r0.patch;patch=1 \
+           file://tosa-tmio-lcd-r10-fix-r0.patch;patch=1 \
+           file://tosa-bluetooth-r8.patch;patch=1 \
+           file://wm97xx-lg13-r0.patch;patch=1 \
+           file://wm97xx-lg13-r0-fix-r0.patch;patch=1 \
            file://wm9712-suspend-cold-res-r2.patch;patch=1 \
            file://sharpsl-pm-postresume-r1.patch;patch=1 \
-           ${DOSRC}/wm97xx-dig-restore-r0.patch;patch=1 \
-           ${DOSRC}/wm97xx-miscdevs-resume-r0.patch;patch=1 \
            file://wm9712-reset-loop-r2.patch;patch=1 \
            file://tosa-lcdnoise-r1.patch;patch=1 \
-           file://wm97xx-lcdnoise-r0.patch;patch=1 "
+           file://tosa-lcdnoise-r1-fix-r0.patch;patch=1 \
+           file://arm-dma-coherent.patch;patch=1 \
+           file://usb-ohci-hooks-r3.patch;patch=1 \
+           file://tmio-ohci-r9.patch;patch=1 \
+           file://pxa2xx_udc_support_inverse_vbus.patch;patch=1 \
+           file://tosa_udc_use_gpio_vbus.patch;patch=1 \
+           "
 #          ${DOSRC}/tosa-asoc-r1.patch;patch=1 "
 
 SRC_URI_append_htcuniversal ="\
index 2de4ad0cf22dd7258389dcddb0517f2a6a4482f0..a8c5f79f67fd932affb43bd49567b870745df800 100644 (file)
@@ -1,6 +1,6 @@
 require linux-rp.inc
 
-PR = "r25"
+PR = "r26"
 
 # Handy URLs
 # git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;protocol=git;tag=ef7d1b244fa6c94fb76d5f787b8629df64ea4046
@@ -14,10 +14,15 @@ PR = "r25"
 # Patches submitted upstream are towards top of this list 
 # Hacks should clearly named and at the bottom
 SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
-           file://hrw-add-wcf11-to-hostap.patch;patch=1;status=pending \
-           ${RPSRC}/lzo_jffs2-r3.patch;patch=1 \
-           ${RPSRC}/lzo_crypto-r2.patch;patch=1 \
-           ${RPSRC}/lzo_jffs2_lzomode-r1.patch;patch=1 \
+           ${RPSRC}/pxa25x_suspend_fixes-r0.patch;patch=1;status=merged \
+           ${RPSRC}/lzo_jffs2-r3.patch;patch=1;status=merged \
+           ${RPSRC}/lzo_jffs2_lzomode-r1.patch;patch=1;status=merged \
+           ${RPSRC}/spitzkbd_fix-r0.patch;patch=1;status=merged \
+           file://uvesafb-0.1-rc3-2.6.22.patch;patch=1;status=merged \
+           ${RPSRC}/locomo_led_fix-r0.patch;patch=1;status=merged \
+           file://hrw-add-wcf11-to-hostap.patch;patch=1;status=merged \
+           ${RPSRC}/export_atags-r0a.patch;patch=1;status=pending \
+           ${RPSRC}/lzo_crypto-r2.patch;patch=1;status=pending \
            ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \
            ${RPSRC}/hx2750_base-r29.patch;patch=1 \
            ${RPSRC}/hx2750_bl-r9.patch;patch=1 \
@@ -32,33 +37,27 @@ SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
            ${RPSRC}/usb_add_epalloc-r3.patch;patch=1 \
            ${RPSRC}/usb_pxa27x_udc-r6.patch;patch=1 \
            ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \
-           ${RPSRC}/poodle_pm-r4.patch;patch=1 \
            ${RPSRC}/pxa27x_overlay-r6.patch;patch=1 \
-           ${RPSRC}/w100_extaccel-r1.patch;patch=1 \
+           ${RPSRC}/w100_extaccel-r2.patch;patch=1 \
            ${RPSRC}/w100_extmem-r1.patch;patch=1 \
-           ${RPSRC}/spitzkbd_fix-r0.patch;patch=1 \
-           ${RPSRC}/export_atags-r0.patch;patch=1 \
-           ${RPSRC}/pxa25x_suspend_fixes-r0.patch;patch=1 \
+           ${RPSRC}/poodle_pm-r4.patch;patch=1 \
            ${RPSRC}/poodle_lcd_hack-r0.patch;patch=1 \
            ${RPSRC}/poodle_asoc_fix-r1.patch;patch=1 \
-           ${RPSRC}/locomo_led_fix-r0.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 \
+           file://squashfs3.0-2.6.15.patch;patch=1;status=external \
            ${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 \
+           file://hostap-monitor-mode.patch;patch=1;status=unmergable \
+           file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1;status=unmergable \
            ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \
-           file://mmcsd_no_scr_check-r2.patch;patch=1 \
+           ${RPSRC}/mmcsd_no_scr_check-r2.patch;patch=1;status=hack \
            ${RPSRC}/integrator_rgb-r1.patch;patch=1;status=hack \
            ${RPSRC}/pxa_cf_initorder_hack-r1.patch;patch=1;status=hack \
            file://pxa-serial-hack.patch;patch=1;status=hack \
            file://connectplus-remove-ide-HACK.patch;patch=1;status=hack \
            file://connectplus-prevent-oops-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://binutils-buildid-arm.patch;patch=1 \
+           file://versatile-armv6.patch;patch=1 \
            file://defconfig-c7x0 \
            file://defconfig-hx2000 \
            file://defconfig-collie \