summaryrefslogtreecommitdiff
path: root/meta/packages
diff options
context:
space:
mode:
Diffstat (limited to 'meta/packages')
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/connectplus-prevent-oops-HACK.patch17
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/hx2750_base-r31.patch1094
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/mmcsd_no_scr_check-r2.patch29
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pda-power.patch3373
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pxa27x_overlay-r8.patch2427
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.0-2.6.15.patch4189
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.3.patch (renamed from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.2-2.6.20-r0.patch)1140
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/uvesafb-0.1-rc3-2.6.22.patch2590
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/vt_ioctl_race.patch46
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/w100fb-unused-var.patch17
-rw-r--r--meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/wm97xx-lcdnoise-r0.patch208
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch29
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/pda-power.patch3373
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/versatile-armv6.patch19
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch46
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/w100fb-unused-var.patch17
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/wm9712-reset-loop-r2.patch44
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/wm9712-suspend-cold-res-r2.patch16
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0-fix-r0.patch128
-rw-r--r--meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0.patch2899
-rw-r--r--meta/packages/linux/linux-rp_2.6.23+2.6.24-rc8.bb84
-rw-r--r--meta/packages/linux/linux-rp_2.6.23.bb35
22 files changed, 3689 insertions, 18131 deletions
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
index 0000000000..b5439c62e7
--- /dev/null
+++ b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/connectplus-prevent-oops-HACK.patch
@@ -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
index 5d58bcf55d..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/hx2750_base-r31.patch
+++ /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);
-+
-+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
-+ resstruct[16]=0xa0000000; //mcr 15, 0, r0, cr2, cr0, {0} 0xa0748000
-+ resstruct[17]=0x00000001; //mcr 15, 0, r0, cr3, cr0, {0} 0x00000015
-+ resstruct[18]=0x00000000; //mcr 15, 0, r0, cr13, cr0, {0} 0x00000000
-+
-+ 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
index ac2245f088..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/mmcsd_no_scr_check-r2.patch
+++ /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
index face2f4ef2..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pda-power.patch
+++ /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
index 693ad20453..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/pxa27x_overlay-r8.patch
+++ /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
index a210afcaf8..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.0-2.6.15.patch
+++ /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
- */
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.2-2.6.20-r0.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.3.patch
index 3870b317e4..cb9a5c49e4 100644
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.2-2.6.20-r0.patch
+++ b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/squashfs3.3.patch
@@ -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),
@@ -31,13 +33,11 @@
+
+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.
+
@@ -55,26 +55,13 @@
+ 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/
@@ -82,14 +69,15 @@
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
@@ -118,9 +106,12 @@
+#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);
@@ -130,7 +121,6 @@
+ 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 *);
@@ -183,10 +173,6 @@
+ .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
@@ -270,30 +256,36 @@
+{
+ 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;
+ }
@@ -302,8 +294,8 @@
+ 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;
@@ -317,7 +309,8 @@
+ 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;
+ }
@@ -337,9 +330,8 @@
+ 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;
@@ -350,8 +342,8 @@
+ 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;
+ }
+
@@ -364,8 +356,9 @@
+
+ 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;
+ }
+
@@ -379,8 +372,8 @@
+
+ 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;
@@ -390,14 +383,13 @@
+
+ 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;
@@ -407,8 +399,9 @@
+
+ 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:
@@ -420,11 +413,12 @@
+
+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)
@@ -435,68 +429,65 @@
+
+ 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);
+ }
+
@@ -512,8 +503,7 @@
+ 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;
@@ -525,9 +515,8 @@
+ 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);
@@ -556,17 +545,13 @@
+ 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;
@@ -579,90 +564,92 @@
+}
+
+
-+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;
+ }
+
@@ -674,7 +661,7 @@
+
+
+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;
@@ -683,6 +670,7 @@
+ 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
@@ -702,11 +690,11 @@
+ 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;
+
@@ -753,7 +741,8 @@
+}
+
+
-+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);
@@ -774,28 +763,23 @@
+ 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);
@@ -808,24 +792,21 @@
+ 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;
@@ -838,10 +819,7 @@
+ 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",
@@ -857,24 +835,21 @@
+ 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;
@@ -887,10 +862,7 @@
+ 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",
@@ -904,17 +876,13 @@
+ 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;
@@ -938,18 +906,13 @@
+ 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;
@@ -960,37 +923,27 @@
+ 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;
@@ -1001,8 +954,7 @@
+ 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;
@@ -1013,29 +965,22 @@
+ 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:
@@ -1044,17 +989,13 @@
+ 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;
@@ -1089,7 +1030,8 @@
+ 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;
+ }
@@ -1106,6 +1048,7 @@
+ 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;
@@ -1126,7 +1069,8 @@
+ 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;
+ }
@@ -1143,6 +1087,7 @@
+ 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;
@@ -1153,6 +1098,34 @@
+}
+
+
++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;
@@ -1165,16 +1138,14 @@
+ 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 >
@@ -1197,16 +1168,17 @@
+ 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;
+ }
@@ -1224,6 +1196,9 @@
+ 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) |
@@ -1233,13 +1208,12 @@
+ }
+
+ /* 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));
@@ -1265,15 +1239,12 @@
+ 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);
@@ -1284,34 +1255,27 @@
+ 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;
+ }
@@ -1343,19 +1307,19 @@
+ 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)
@@ -1377,13 +1341,14 @@
+ 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:
@@ -1391,7 +1356,7 @@
+ 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);
@@ -1426,7 +1391,7 @@
+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);
@@ -1437,11 +1402,10 @@
+ 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;
+ }
+ }
@@ -1452,11 +1416,11 @@
+ 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:
@@ -1480,10 +1444,10 @@
+
+ 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 &&
@@ -1493,6 +1457,7 @@
+ meta = &msblk->meta_index[i];
+ offset = meta->offset;
+ }
++ }
+
+ if (meta)
+ meta->locked = 1;
@@ -1514,25 +1479,26 @@
+
+ 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;
+ }
@@ -1565,7 +1531,7 @@
+
+
+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;
@@ -1576,19 +1542,18 @@
+
+ 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 --)
@@ -1626,25 +1591,26 @@
+
+ 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);
@@ -1655,11 +1621,9 @@
+ 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;
@@ -1706,15 +1670,14 @@
+ 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);
@@ -1724,8 +1687,7 @@
+ 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);
+
@@ -1741,9 +1703,10 @@
+ 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;
@@ -1752,64 +1715,65 @@
+ 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);
@@ -1821,7 +1785,7 @@
+ 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);
@@ -1833,98 +1797,24 @@
+ }
+
+ 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);
@@ -1932,10 +1822,9 @@
+}
+
+
-+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;
@@ -1953,23 +1842,18 @@
+ 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;
@@ -1982,10 +1866,9 @@
+}
+
+
-+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;
@@ -1996,8 +1879,9 @@
+
+ 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;
+ }
@@ -2009,20 +1893,15 @@
+ 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';
+
@@ -2035,6 +1914,7 @@
+
+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+ kfree(str);
++
+failure:
+ return length + 3;
+}
@@ -2047,15 +1927,15 @@
+ 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;
+ }
@@ -2075,14 +1955,12 @@
+ }
+ 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;
+ }
@@ -2090,25 +1968,22 @@
+ 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);
@@ -2118,28 +1993,22 @@
+ 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;
@@ -2150,17 +2019,14 @@
+ 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;
+ }
@@ -2190,15 +2056,15 @@
+ 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;
+ }
@@ -2209,24 +2075,21 @@
+ 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);
@@ -2236,27 +2099,22 @@
+ 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;
@@ -2268,9 +2126,8 @@
+ 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);
@@ -2308,16 +2165,15 @@
+ 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);
@@ -2330,8 +2186,7 @@
+
+
+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);
@@ -2344,10 +2199,11 @@
+ 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:
@@ -2369,9 +2225,7 @@
+{
+ 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;
+}
+
+
@@ -2381,22 +2235,19 @@
+}
+
+
-+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;
@@ -2411,11 +2262,12 @@
+
+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.
@@ -2424,14 +2276,15 @@
+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
@@ -2577,14 +2430,15 @@
+ 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,
@@ -2641,10 +2495,7 @@
+ 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",
@@ -3169,14 +3020,15 @@
+
+ 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
@@ -3224,7 +3076,7 @@
+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);
@@ -3236,7 +3088,6 @@
+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
@@ -3259,9 +3110,10 @@
+ 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
+
@@ -3269,7 +3121,7 @@
+ * 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
@@ -3292,16 +3144,9 @@
+#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
@@ -3311,10 +3156,10 @@
+#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
@@ -3395,9 +3240,8 @@
+
+#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))
+
@@ -3893,6 +3737,15 @@
+ 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);\
@@ -4196,8 +4049,9 @@
+
+#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
@@ -4205,7 +4059,7 @@
+ * 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
@@ -4244,16 +4098,17 @@
+ 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
@@ -4313,6 +4168,8 @@
+ 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 \
@@ -4321,8 +4178,9 @@
+ 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>
@@ -4331,7 +4189,7 @@
#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:
@@ -4339,7 +4197,7 @@
* 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;
@@ -4347,7 +4205,7 @@
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;
@@ -4355,7 +4213,7 @@
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
index 711375114f..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/uvesafb-0.1-rc3-2.6.22.patch
+++ /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
index 5a51d1c3f5..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/vt_ioctl_race.patch
+++ /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
index 8cbbb6bd01..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/w100fb-unused-var.patch
+++ /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
index 191de3af22..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc8/wm97xx-lcdnoise-r0.patch
+++ /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
index ac2245f088..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch
+++ /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
index face2f4ef2..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23/pda-power.patch
+++ /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
index 0000000000..e2d0060ac3
--- /dev/null
+++ b/meta/packages/linux/linux-rp-2.6.23/versatile-armv6.patch
@@ -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
index 5a51d1c3f5..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch
+++ /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
index 8cbbb6bd01..0000000000
--- a/meta/packages/linux/linux-rp-2.6.23/w100fb-unused-var.patch
+++ /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
index 0000000000..78e81ea83a
--- /dev/null
+++ b/meta/packages/linux/linux-rp-2.6.23/wm9712-reset-loop-r2.patch
@@ -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
index 0000000000..5179b47cc4
--- /dev/null
+++ b/meta/packages/linux/linux-rp-2.6.23/wm9712-suspend-cold-res-r2.patch
@@ -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
index 0000000000..5ad0d8703d
--- /dev/null
+++ b/meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0-fix-r0.patch
@@ -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
index 0000000000..c918c5daff
--- /dev/null
+++ b/meta/packages/linux/linux-rp-2.6.23/wm97xx-lg13-r0.patch
@@ -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
diff --git a/meta/packages/linux/linux-rp_2.6.23+2.6.24-rc8.bb b/meta/packages/linux/linux-rp_2.6.23+2.6.24-rc8.bb
index 353e8c1fc3..efffb6e404 100644
--- a/meta/packages/linux/linux-rp_2.6.23+2.6.24-rc8.bb
+++ b/meta/packages/linux/linux-rp_2.6.23+2.6.24-rc8.bb
@@ -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 ="\
diff --git a/meta/packages/linux/linux-rp_2.6.23.bb b/meta/packages/linux/linux-rp_2.6.23.bb
index 2de4ad0cf2..a8c5f79f67 100644
--- a/meta/packages/linux/linux-rp_2.6.23.bb
+++ b/meta/packages/linux/linux-rp_2.6.23.bb
@@ -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 \