summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 @@
1Index: linux-2.6.21/drivers/net/wireless/hostap/hostap_hw.c
2===================================================================
3--- linux-2.6.21.orig/drivers/net/wireless/hostap/hostap_hw.c 2007-07-07 12:45:39.000000000 +0100
4+++ linux-2.6.21/drivers/net/wireless/hostap/hostap_hw.c 2007-07-07 12:47:30.000000000 +0100
5@@ -2666,6 +2666,12 @@
6 iface = netdev_priv(dev);
7 local = iface->local;
8
9+ if(dev->base_addr == 0)
10+ {
11+ printk(KERN_DEBUG "%s: IRQ before base_addr set\n", dev->name);
12+ return IRQ_HANDLED;
13+ }
14+
15 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
16
17 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 @@
1---
2 arch/arm/mach-pxa/Kconfig | 10
3 arch/arm/mach-pxa/Makefile | 1
4 arch/arm/mach-pxa/hx2750.c | 450 ++++++++++++++++++++++++++++++++++++++
5 arch/arm/mach-pxa/hx2750_test.c | 433 ++++++++++++++++++++++++++++++++++++
6 arch/arm/mach-pxa/pm.c | 5
7 arch/arm/mach-pxa/pxa25x.c | 4
8 arch/arm/mach-pxa/pxa27x.c | 4
9 include/asm-arm/arch-pxa/hx2750.h | 90 +++++++
10 8 files changed, 995 insertions(+), 2 deletions(-)
11
12--- /dev/null
13+++ linux-2.6.24-rc1/include/asm-arm/arch-pxa/hx2750.h
14@@ -0,0 +1,90 @@
15+/*
16+ * Hardware specific definitions for iPAQ hx2750
17+ *
18+ * Copyright 2005 Openedhand Ltd.
19+ *
20+ * Author: Richard Purdie <richard@o-hand.com>
21+ *
22+ * This program is free software; you can redistribute it and/or modify
23+ * it under the terms of the GNU General Public License version 2 as
24+ * published by the Free Software Foundation.
25+ *
26+ */
27+#ifndef __ASM_ARCH_HX2750_H
28+#define __ASM_ARCH_HX2750_H 1
29+
30+/*
31+ * HX2750 (Non Standard) GPIO Definitions
32+ */
33+
34+#define HX2750_GPIO_KEYPWR (0) /* Power button */
35+#define HX2750_GPIO_BATTCOVER1 (9) /* Battery Cover Switch */
36+#define HX2750_GPIO_CF_IRQ (11) /* CF IRQ? */
37+#define HX2750_GPIO_USBCONNECT (12) /* USB Connected? */
38+#define HX2750_GPIO_CF_DETECT (13) /* CF Card Detect? */
39+#define HX2750_GPIO_EXTPWR (14) /* External Power Detect */
40+#define HX2750_GPIO_BATLVL (15) /* Battery Level Detect */
41+#define HX2750_GPIO_CF_PWR (17) /* CF Power? */
42+#define HX2750_GPIO_SR_STROBE (18) /* Shift Register Strobe */
43+#define HX2750_GPIO_CHARGE (22) /* Charging Enable (active low) */
44+#define HX2750_GPIO_TSC2101_SS (24) /* TSC2101 SS# */
45+#define HX2750_GPIO_BTPWR (27) /* Bluetooth Power? */
46+#define HX2750_GPIO_BATTCOVER2 (33) /* Battery Cover Switch */
47+#define HX2750_GPIO_SD_DETECT (38) /* MMC Card Detect */
48+#define HX2750_GPIO_SR_CLK1 (52) /* Shift Register Clock */
49+#define HX2750_GPIO_SR_CLK2 (53)
50+#define HX2750_GPIO_CF_WIFIIRQ (54) /* CF Wifi IRQ? */
51+#define HX2750_GPIO_GPIO_DIN (88) /* Shift Register Data */
52+#define HX2750_GPIO_KEYLEFT (90) /* Left button */
53+#define HX2750_GPIO_KEYRIGHT (91) /* Right button */
54+#define HX2750_GPIO_KEYCAL (93) /* Calander button */
55+#define HX2750_GPIO_KEYTASK (94) /* Task button */
56+#define HX2750_GPIO_KEYSIDE (95) /* Side button */
57+#define HX2750_GPIO_KEYENTER (96) /* Enter Button*/
58+#define HX2750_GPIO_KEYCON (97) /* Contacts button */
59+#define HX2750_GPIO_KEYMAIL (98) /* Mail button */
60+#define HX2750_GPIO_BIOPWR (99) /* BIO Reader Power? */
61+#define HX2750_GPIO_KEYUP (100) /* Up button */
62+#define HX2750_GPIO_KEYDOWN (101) /* Down button*/
63+#define HX2750_GPIO_SD_READONLY (103) /* MMC/SD Write Protection */
64+#define HX2750_GPIO_LEDMAIL (106) /* Green Mail LED */
65+#define HX2750_GPIO_HP_JACK (108) /* Head Phone Jack Present */
66+#define HX2750_GPIO_PENDOWN (117) /* Touch Screen Pendown */
67+
68+
69+//#define HX2750_GPIO_ () /* */
70+
71+/*
72+ * HX2750 Interrupts
73+ */
74+#define HX2750_IRQ_GPIO_EXTPWR IRQ_GPIO(HX2750_GPIO_EXTPWR)
75+#define HX2750_IRQ_GPIO_SD_DETECT IRQ_GPIO(HX2750_GPIO_SD_DETECT)
76+#define HX2750_IRQ_GPIO_PENDOWN IRQ_GPIO(HX2750_GPIO_PENDOWN)
77+#define HX2750_IRQ_GPIO_CF_DETECT IRQ_GPIO(HX2750_GPIO_CF_DETECT)
78+#define HX2750_IRQ_GPIO_CF_IRQ IRQ_GPIO(HX2750_GPIO_CF_IRQ)
79+#define HX2750_IRQ_GPIO_CF_WIFIIRQ IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ)
80+
81+/*
82+ * HX2750 Extra GPIO Definitions
83+ */
84+
85+#define HX2750_EGPIO_WIFI_PWR (1 << 11) /* Wifi power */
86+#define HX2750_EGPIO_LCD_PWR (1 << 10) /* LCD Power */
87+#define HX2750_EGPIO_BL_PWR (1 << 9) /* Backlight LED Power */
88+#define HX2750_EGPIO_8 (1 << 8) /* */
89+#define HX2750_EGPIO_7 (1 << 7) /* */
90+#define HX2750_EGPIO_SD_PWR (1 << 6) /* SD Power */
91+#define HX2750_EGPIO_TSC_PWR (1 << 5) /* TS Power */
92+#define HX2750_EGPIO_CF0_RESET (1 << 4) /* CF0 Reset */
93+#define HX2750_EGPIO_CF1_RESET (1 << 3) /* CF1 Reset */
94+#define HX2750_EGPIO_2 (1 << 2) /* Power/Red LED Related?*/
95+#define HX2750_EGPIO_1 (1 << 1) /* Power/Red LED Related?*/
96+#define HX2750_EGPIO_PWRLED (1 << 0) /* Power/Red LED Related?*/
97+
98+
99+void hx2750_set_egpio(unsigned int gpio);
100+void hx2750_clear_egpio(unsigned int gpio);
101+
102+
103+#endif /* __ASM_ARCH_HX2750_H */
104+
105--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/Makefile
106+++ linux-2.6.24-rc1/arch/arm/mach-pxa/Makefile
107@@ -22,6 +22,7 @@
108 obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o
109 obj-$(CONFIG_MACH_TOSA) += tosa.o
110 obj-$(CONFIG_MACH_EM_X270) += em-x270.o
111+obj-$(CONFIG_MACH_HX2750) += hx2750.o hx2750_test.o
112
113 ifeq ($(CONFIG_MACH_ZYLONITE),y)
114 obj-y += zylonite.o
115--- /dev/null
116+++ linux-2.6.24-rc1/arch/arm/mach-pxa/hx2750_test.c
117@@ -0,0 +1,433 @@
118+/*
119+ * HP iPAQ hx2750 Test Development Code
120+ *
121+ * Copyright 2005 Openedhand Ltd.
122+ *
123+ * Author: Richard Purdie <richard@o-hand.com>
124+ *
125+ * This program is free software; you can redistribute it and/or modify
126+ * it under the terms of the GNU General Public License version 2 as
127+ * published by the Free Software Foundation.
128+ *
129+ */
130+
131+#include <linux/init.h>
132+#include <linux/kernel.h>
133+#include <linux/ioport.h>
134+#include <linux/device.h>
135+#include <linux/input.h>
136+#include <linux/delay.h>
137+#include <linux/interrupt.h>
138+
139+#include <asm/mach-types.h>
140+#include <asm/hardware.h>
141+#include <asm/mach/arch.h>
142+
143+#include <asm/arch/hx2750.h>
144+#include <asm/arch/pxa-regs.h>
145+
146+
147+static int prodval;
148+
149+/*
150+ * Sysfs functions
151+ */
152+static ssize_t test1_show(struct device *dev, char *buf)
153+{
154+ unsigned long rp;
155+
156+ asm ("mrc p15, 0, %0, cr1, cr0;\n" :"=r"(rp) );
157+ printk("%lx\n",rp);
158+
159+ asm ("mrc p15, 0, %0, cr1, cr1;\n" :"=r"(rp) );
160+ printk("%lx\n",rp);
161+
162+ asm ("mrc p15, 0, %0, cr2, cr0;\n" :"=r"(rp) );
163+ printk("%lx\n",rp);
164+
165+ asm ("mrc p15, 0, %0, cr3, cr0;\n" :"=r"(rp) );
166+ printk("%lx\n",rp);
167+
168+ asm ("mrc p15, 0, %0, cr13, cr0;\n" :"=r"(rp) );
169+ printk("%lx\n",rp);
170+
171+ return sprintf(buf, "%d\n",prodval);
172+}
173+extern void tsc2101_print_miscdata(struct device *dev);
174+extern struct platform_device tsc2101_device;
175+
176+static ssize_t test1_store(struct device *dev, const char *buf, size_t count)
177+{
178+ prodval = simple_strtoul(buf, NULL, 10);
179+
180+ tsc2101_print_miscdata(&tsc2101_device.dev);
181+
182+ return count;
183+}
184+
185+static DEVICE_ATTR(test1, 0644, test1_show, test1_store);
186+
187+static ssize_t test2_show(struct device *dev, char *buf)
188+{
189+ printk(KERN_ERR "SSCR0_P2: %08x\n", SSCR0_P2);
190+ printk(KERN_ERR "SSCR1_P2: %08x\n", SSCR1_P2);
191+ printk(KERN_ERR "SSSR_P2: %08x\n", SSSR_P2);
192+ printk(KERN_ERR "SSITR_P2: %08x\n", SSITR_P2);
193+ printk(KERN_ERR "SSDR_P2: %08x\n", SSDR_P2);
194+ printk(KERN_ERR "SSTO_P2: %08x\n", SSTO_P2);
195+ printk(KERN_ERR "SSPSP_P2: %08x\n", SSPSP_P2);
196+
197+ hx2750_ssp_init2();
198+
199+ printk(KERN_ERR "SSCR0_P2: %08x\n", SSCR0_P2);
200+ printk(KERN_ERR "SSCR1_P2: %08x\n", SSCR1_P2);
201+ printk(KERN_ERR "SSSR_P2: %08x\n", SSSR_P2);
202+ printk(KERN_ERR "SSITR_P2: %08x\n", SSITR_P2);
203+ printk(KERN_ERR "SSDR_P2: %08x\n", SSDR_P2);
204+ printk(KERN_ERR "SSTO_P2: %08x\n", SSTO_P2);
205+ printk(KERN_ERR "SSPSP_P2: %08x\n", SSPSP_P2);
206+
207+ return sprintf(buf, "%d\n",0);
208+}
209+
210+static DEVICE_ATTR(test2, 0444, test2_show, NULL);
211+
212+extern unsigned int hx2750_egpio_current;
213+
214+static ssize_t setegpio_show(struct device *dev, char *buf)
215+{
216+ return sprintf(buf, "%x\n",hx2750_egpio_current);
217+}
218+
219+static ssize_t setegpio_store(struct device *dev, const char *buf, size_t count)
220+{
221+ unsigned int val = simple_strtoul(buf, NULL, 10);
222+
223+ hx2750_set_egpio(1 << val);
224+
225+ return count;
226+}
227+
228+static DEVICE_ATTR(setegpio, 0644, setegpio_show, setegpio_store);
229+
230+static ssize_t clregpio_show(struct device *dev, char *buf)
231+{
232+ return sprintf(buf, "%x\n",hx2750_egpio_current);
233+}
234+
235+static ssize_t gpio_show(struct device *dev, char *buf)
236+{
237+ int i;
238+
239+ printk(KERN_ERR "GPIO# D S A INTER\n");
240+
241+ for (i=0;i<119;i++) {
242+ printk(KERN_ERR " %3d: ",i);
243+ if (GPDR(i) & GPIO_bit(i))
244+ printk("O ");
245+ else
246+ printk("I ");
247+ printk("%d ",(GPLR(i) & GPIO_bit(i)) != 0);
248+ printk("%d ",((GAFR(i) & (0x3 << (((i) & 0xf)*2)))) >> (((i) & 0xf)*2) );
249+ if (GEDR(i) & GPIO_bit(i))
250+ printk("ED ");
251+ if (GRER(i) & GPIO_bit(i))
252+ printk("RE ");
253+ if (GFER(i) & GPIO_bit(i))
254+ printk("FE ");
255+
256+ printk("\n");
257+ }
258+ return sprintf(buf, "EGPIO: %x\n",hx2750_egpio_current);
259+}
260+
261+static ssize_t clregpio_store(struct device *dev, const char *buf, size_t count)
262+{
263+ unsigned int val = simple_strtoul(buf, NULL, 10);
264+
265+ hx2750_clear_egpio(1 << val);
266+
267+ return count;
268+}
269+
270+static DEVICE_ATTR(clregpio, 0644, clregpio_show, clregpio_store);
271+
272+
273+static ssize_t gpioclr_store(struct device *dev, const char *buf, size_t count)
274+{
275+ int prod;
276+ prod = simple_strtoul(buf, NULL, 10);
277+
278+ GPCR(prod) = GPIO_bit(prod);
279+
280+ return count;
281+}
282+
283+static DEVICE_ATTR(gpioclr, 0644, gpio_show, gpioclr_store);
284+
285+static ssize_t gpioset_store(struct device *dev, const char *buf, size_t count)
286+{
287+ int prod;
288+ prod = simple_strtoul(buf, NULL, 10);
289+
290+ GPSR(prod) = GPIO_bit(prod);
291+
292+ return count;
293+}
294+
295+static DEVICE_ATTR(gpioset, 0644, gpio_show, gpioset_store);
296+
297+
298+static ssize_t ssp2read_store(struct device *dev, const char *buf, size_t count)
299+{
300+ unsigned int val = simple_strtoul(buf, NULL, 16);
301+
302+ printk("Read: %08x\n",hx2750_ssp2_read(val));
303+
304+ return count;
305+}
306+
307+static DEVICE_ATTR(ssp2read, 0200, NULL, ssp2read_store);
308+
309+static ssize_t ssp2write_store(struct device *dev, const char *buf, size_t count)
310+{
311+ unsigned int val = simple_strtoul(buf, NULL, 16);
312+
313+ printk("Write: %08x\n",hx2750_ssp2_write(val));
314+
315+ return count;
316+}
317+
318+static DEVICE_ATTR(ssp2write, 0200, NULL, ssp2write_store);
319+
320+
321+static ssize_t sspr_store(struct device *dev, const char *buf, size_t count)
322+{
323+ unsigned long val,ret;
324+ val = simple_strtoul(buf, NULL, 0);
325+
326+ hx2750_tsc2101_send(1<<15,val,&ret,1);
327+
328+ printk("Response: %x\n",ret);
329+
330+ return count;
331+}
332+
333+static DEVICE_ATTR(sspr, 0200, NULL, sspr_store);
334+
335+static ssize_t sspw_store(struct device *dev, const char *buf, size_t count)
336+{
337+ int val,ret;
338+ sscanf(buf, "%lx %lx", &val, &ret);
339+
340+ hx2750_tsc2101_send(0,val,&ret,1);
341+
342+ return count;
343+}
344+
345+static DEVICE_ATTR(sspw, 0200, NULL, sspw_store);
346+
347+
348+extern struct pm_ops pxa_pm_ops;
349+extern void pxa_cpu_resume(void);
350+extern unsigned long pxa_pm_pspr_value;
351+
352+static int (*pxa_pm_enter_orig)(suspend_state_t state);
353+
354+//static struct {
355+// u32 ffier, fflcr, ffmcr, ffspr, ffisr, ffdll, ffdlh;
356+//} sys_ctx;
357+
358+u32 resstruct[20];
359+
360+static int hx2750_pxa_pm_enter(suspend_state_t state)
361+{
362+ int i;
363+ u32 save[10];
364+
365+ PWER = 0xC0000003;// | PWER_RTC;
366+ PFER = 0x00000003;
367+ PRER = 0x00000003;
368+
369+ PGSR0=0x00000018;
370+ PGSR1=0x00000380;
371+ PGSR2=0x00800000;
372+ PGSR3=0x00500400;
373+
374+ //PVCR=0x494; or 0x14;
375+ //PVCR=0x14;
376+ //PCMD0=0x41f;
377+ //i=PISR;
378+ //PICR=0x00000062;
379+
380+ //PCFR=0x457;
381+ //PCFR=0x70; // Does not resume from sleep
382+ PCFR=0x077; // was 0x477
383+ PSLR=0xff100004;
384+
385+ resstruct[0]=0x0000b4e6;
386+ resstruct[1]=0x00000001;
387+ resstruct[2]=virt_to_phys(pxa_cpu_resume);
388+ resstruct[3]=0xffffffff; //value for r0
389+
390+ resstruct[14]=0x00000078; //mcr 15, 0, r0, cr1, cr0, {0}
391+ resstruct[15]=0x00000000; //mcr 15, 0, r0, cr1, cr1, {0} 0xffffffff
392+ resstruct[16]=0xa0000000; //mcr 15, 0, r0, cr2, cr0, {0} 0xa0748000
393+ resstruct[17]=0x00000001; //mcr 15, 0, r0, cr3, cr0, {0} 0x00000015
394+ resstruct[18]=0x00000000; //mcr 15, 0, r0, cr13, cr0, {0} 0x00000000
395+
396+ pxa_pm_pspr_value=virt_to_phys(&resstruct[0]);
397+
398+ hx2750_send_egpio(3);
399+
400+ pxa_gpio_mode(87 | GPIO_OUT | GPIO_DFLT_HIGH);
401+
402+ //sys_ctx.ffier = FFIER;
403+ //sys_ctx.fflcr = FFLCR;
404+ //sys_ctx.ffmcr = FFMCR;
405+ //sys_ctx.ffspr = FFSPR;
406+ //sys_ctx.ffisr = FFISR;
407+ //FFLCR |= 0x80;
408+ //sys_ctx.ffdll = FFDLL;
409+ //sys_ctx.ffdlh = FFDLH;
410+ //FFLCR &= 0xef;
411+
412+ pxa_pm_enter_orig(state);
413+
414+ //FFMCR = sys_ctx.ffmcr;
415+ //FFSPR = sys_ctx.ffspr;
416+ //FFLCR = sys_ctx.fflcr;
417+ //FFLCR |= 0x80;
418+ //FFDLH = sys_ctx.ffdlh;
419+ //FFDLL = sys_ctx.ffdll;
420+ //FFLCR = sys_ctx.fflcr;
421+ //FFISR = sys_ctx.ffisr;
422+ //FFLCR = 0x07;
423+ //FFIER = sys_ctx.ffier;
424+
425+ return 0;
426+}
427+
428+static irqreturn_t hx2750_charge_int(int irq, void *dev_id, struct pt_regs *regs)
429+{
430+ if ((GPLR(HX2750_GPIO_EXTPWR) & GPIO_bit(HX2750_GPIO_EXTPWR)) == 0) {
431+ printk("Charging On\n");
432+ GPCR(HX2750_GPIO_CHARGE);
433+ } else {
434+ printk("Charging Off\n");
435+ GPSR(HX2750_GPIO_CHARGE);
436+ }
437+
438+ return IRQ_HANDLED;
439+}
440+
441+
442+
443+
444+static irqreturn_t hx2750_interrupt(int irq, void *dev_id, struct pt_regs *regs)
445+{
446+ printk("Input %d changed.\n", irq-32);
447+
448+ return IRQ_HANDLED;
449+}
450+
451+
452+static int __init hx2750_test_probe(struct device *dev)
453+{
454+ pxa_gpio_mode(21 | GPIO_OUT | GPIO_DFLT_HIGH);
455+ pxa_gpio_mode(HX2750_GPIO_CHARGE | GPIO_OUT | GPIO_DFLT_HIGH);
456+ pxa_gpio_mode(83 | GPIO_OUT | GPIO_DFLT_HIGH);
457+ pxa_gpio_mode(HX2750_GPIO_BIOPWR | GPIO_OUT | GPIO_DFLT_HIGH);
458+ pxa_gpio_mode(116 | GPIO_OUT | GPIO_DFLT_HIGH);
459+ pxa_gpio_mode(118 | GPIO_OUT | GPIO_DFLT_HIGH);
460+
461+
462+ //pxa_gpio_mode(HX2750_GPIO_CF_PWR | GPIO_OUT | GPIO_DFLT_LOW);
463+ pxa_gpio_mode(HX2750_GPIO_CF_PWR | GPIO_OUT | GPIO_DFLT_HIGH);
464+ pxa_gpio_mode(HX2750_GPIO_BTPWR | GPIO_OUT | GPIO_DFLT_LOW);
465+ pxa_gpio_mode(79 | GPIO_OUT | GPIO_DFLT_LOW);
466+ pxa_gpio_mode(85 | GPIO_OUT | GPIO_DFLT_LOW);
467+ pxa_gpio_mode(HX2750_GPIO_LEDMAIL | GPIO_OUT | GPIO_DFLT_LOW);
468+ pxa_gpio_mode(107 | GPIO_OUT | GPIO_DFLT_LOW);
469+ pxa_gpio_mode(114 | GPIO_OUT | GPIO_DFLT_LOW);
470+
471+ pxa_gpio_mode(HX2750_GPIO_BATTCOVER1 | GPIO_IN);
472+ pxa_gpio_mode(HX2750_GPIO_BATTCOVER2 | GPIO_IN);
473+ pxa_gpio_mode(HX2750_GPIO_CF_IRQ | GPIO_IN);
474+ pxa_gpio_mode(HX2750_GPIO_USBCONNECT | GPIO_IN);
475+ pxa_gpio_mode(HX2750_GPIO_CF_DETECT | GPIO_IN);
476+ pxa_gpio_mode(HX2750_GPIO_EXTPWR | GPIO_IN);
477+
478+ pxa_gpio_mode(HX2750_GPIO_BATLVL | GPIO_IN);
479+ //pxa_gpio_mode(HX2750_GPIO_CF_WIFIIRQ | GPIO_IN);
480+ pxa_gpio_mode(80 | GPIO_IN);
481+ pxa_gpio_mode(HX2750_GPIO_HP_JACK | GPIO_IN);
482+ pxa_gpio_mode(115 | GPIO_IN);
483+ pxa_gpio_mode(119 | GPIO_IN);
484+
485+ request_irq(IRQ_GPIO(HX2750_GPIO_BATLVL), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
486+ //request_irq(IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
487+ request_irq(IRQ_GPIO(80), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
488+ request_irq(IRQ_GPIO(115), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
489+ request_irq(IRQ_GPIO(119), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
490+ request_irq(IRQ_GPIO(HX2750_GPIO_SR_CLK2), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
491+
492+ //request_irq(IRQ_GPIO(10), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
493+
494+ set_irq_type(IRQ_GPIO(HX2750_GPIO_BATLVL),IRQT_BOTHEDGE);
495+ //set_irq_type(IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ),IRQT_BOTHEDGE);
496+ set_irq_type(IRQ_GPIO(80),IRQT_BOTHEDGE);
497+ set_irq_type(IRQ_GPIO(115),IRQT_BOTHEDGE);
498+ set_irq_type(IRQ_GPIO(119),IRQT_BOTHEDGE);
499+ set_irq_type(IRQ_GPIO(HX2750_GPIO_SR_CLK2),IRQT_BOTHEDGE);
500+
501+ //set_irq_type(IRQ_GPIO(10),IRQT_BOTHEDGE);
502+
503+ printk("hx2750 Test Code Initialized.\n");
504+ device_create_file(dev, &dev_attr_test1);
505+ device_create_file(dev, &dev_attr_test2);
506+ device_create_file(dev, &dev_attr_setegpio);
507+ device_create_file(dev, &dev_attr_clregpio);
508+ device_create_file(dev, &dev_attr_gpioset);
509+ device_create_file(dev, &dev_attr_gpioclr);
510+ device_create_file(dev, &dev_attr_sspr);
511+ device_create_file(dev, &dev_attr_sspw);
512+ device_create_file(dev, &dev_attr_ssp2read);
513+ device_create_file(dev, &dev_attr_ssp2write);
514+
515+ request_irq(HX2750_IRQ_GPIO_EXTPWR, hx2750_charge_int, SA_INTERRUPT, "hx2750_extpwr", NULL);
516+ set_irq_type(HX2750_IRQ_GPIO_EXTPWR, IRQT_BOTHEDGE);
517+
518+ pxa_pm_enter_orig=pxa_pm_ops.enter;
519+ pxa_pm_ops.enter=hx2750_pxa_pm_enter;
520+
521+ return 0;
522+}
523+
524+static struct device_driver hx2750_test_driver = {
525+ .name = "hx2750-test",
526+ .bus = &platform_bus_type,
527+ .probe = hx2750_test_probe,
528+// .remove = hx2750_bl_remove,
529+// .suspend = hx2750_bl_suspend,
530+// .resume = hx2750_bl_resume,
531+};
532+
533+
534+static int __init hx2750_test_init(void)
535+{
536+ return driver_register(&hx2750_test_driver);
537+}
538+
539+
540+static void __exit hx2750_test_exit(void)
541+{
542+ driver_unregister(&hx2750_test_driver);
543+}
544+
545+module_init(hx2750_test_init);
546+module_exit(hx2750_test_exit);
547+
548+MODULE_AUTHOR("Richard Purdie <richard@o-hand.com>");
549+MODULE_DESCRIPTION("iPAQ hx2750 Backlight Driver");
550+MODULE_LICENSE("GPLv2");
551--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/Kconfig
552+++ linux-2.6.24-rc1/arch/arm/mach-pxa/Kconfig
553@@ -83,6 +83,15 @@
554 bool "Sharp PXA270 models (SL-Cxx00)"
555 select PXA27x
556
557+config MACH_HX2750
558+ bool "HP iPAQ hx2750"
559+ select PXA27x
560+ select PXA_KEYS
561+ select MFD_TSC2101
562+ select PXA_SSP
563+ help
564+ This enables support for the HP iPAQ HX2750 handheld.
565+
566 endchoice
567
568 endif
569@@ -181,3 +190,4 @@
570 help
571 Enable support for PXA2xx SSP ports
572 endif
573+
574--- /dev/null
575+++ linux-2.6.24-rc1/arch/arm/mach-pxa/hx2750.c
576@@ -0,0 +1,450 @@
577+/*
578+ * Machine definitions for HP iPAQ hx2750
579+ *
580+ * Copyright 2005 Openedhand Ltd.
581+ *
582+ * Author: Richard Purdie <richard@o-hand.com>
583+ *
584+ * This program is free software; you can redistribute it and/or modify
585+ * it under the terms of the GNU General Public License version 2 as
586+ * published by the Free Software Foundation.
587+ *
588+ */
589+
590+
591+#include <linux/init.h>
592+#include <linux/kernel.h>
593+#include <linux/ioport.h>
594+#include <linux/platform_device.h>
595+#include <linux/delay.h>
596+#include <linux/input.h>
597+#include <linux/irq.h>
598+#include <linux/mmc/host.h>
599+#include <linux/mfd/tsc2101.h>
600+
601+#include <asm/mach-types.h>
602+#include <asm/hardware.h>
603+#include <asm/mach/arch.h>
604+
605+#include <asm/arch/hx2750.h>
606+#include <asm/arch/pxa-regs.h>
607+#include <asm/arch/pxa_keys.h>
608+#include <asm/mach/map.h>
609+#include <asm/arch/udc.h>
610+#include <asm/arch/mmc.h>
611+#include <asm/arch/audio.h>
612+#include <asm/arch/pxafb.h>
613+#include <asm/arch/ssp.h>
614+
615+#include "generic.h"
616+
617+
618+/*
619+ * Keys Support
620+ */
621+static struct pxa_keys_button hx2750_button_table[] = {
622+ { KEY_POWER, HX2750_GPIO_KEYPWR, PXAKEY_PWR_KEY },
623+ { KEY_LEFT, HX2750_GPIO_KEYLEFT, 0 },
624+ { KEY_RIGHT, HX2750_GPIO_KEYRIGHT, 0 },
625+ { KEY_KP0, HX2750_GPIO_KEYCAL, 0 },
626+ { KEY_KP1, HX2750_GPIO_KEYTASK, 0 },
627+ { KEY_KP2, HX2750_GPIO_KEYSIDE, 0 },
628+ { KEY_ENTER, HX2750_GPIO_KEYENTER, 0 },
629+ { KEY_KP3, HX2750_GPIO_KEYCON, 0 }, //KEY_CONTACTS
630+ { KEY_MAIL, HX2750_GPIO_KEYMAIL, 0 },
631+ { KEY_UP, HX2750_GPIO_KEYUP, 0 },
632+ { KEY_DOWN, HX2750_GPIO_KEYDOWN, 0 },
633+};
634+
635+static struct pxa_keys_platform_data hx2750_pxa_keys_data = {
636+ .buttons = hx2750_button_table,
637+ .nbuttons = ARRAY_SIZE(hx2750_button_table),
638+};
639+
640+static struct platform_device hx2750_pxa_keys = {
641+ .name = "pxa2xx-keys",
642+ .dev = {
643+ .platform_data = &hx2750_pxa_keys_data,
644+ },
645+};
646+
647+
648+/*
649+ * Backlight Device
650+ */
651+extern struct platform_device pxafb_device;
652+
653+static struct platform_device hx2750_bl_device = {
654+ .name = "hx2750-bl",
655+ .id = -1,
656+// .dev = {
657+// .parent = &pxafb_device.dev,
658+// }
659+};
660+
661+
662+/*
663+ * UDC/USB
664+ */
665+static int hx2750_udc_is_connected (void)
666+{
667+ return GPLR0 & GPIO_bit(HX2750_GPIO_USBCONNECT);
668+}
669+
670+//static void hx2750_udc_command (int cmd)
671+//{
672+//}
673+
674+static struct pxa2xx_udc_mach_info hx2750_udc_mach_info = {
675+ .udc_is_connected = hx2750_udc_is_connected,
676+// .udc_command = hx2750_udc_command,
677+};
678+
679+
680+/*
681+ * SSP Devices Setup
682+ */
683+static struct ssp_dev hx2750_ssp_dev1;
684+static struct ssp_dev hx2750_ssp_dev2;
685+static struct ssp_dev hx2750_ssp_dev3;
686+
687+void hx2750_ssp_init(void)
688+{
689+ pxa_gpio_mode(HX2750_GPIO_TSC2101_SS | GPIO_OUT | GPIO_DFLT_HIGH);
690+
691+ if (ssp_init(&hx2750_ssp_dev1, 1, 0))
692+ printk(KERN_ERR "Unable to register SSP1 handler!\n");
693+ else {
694+ ssp_disable(&hx2750_ssp_dev1);
695+ ssp_config(&hx2750_ssp_dev1, (SSCR0_Motorola | (SSCR0_DSS & 0x0f )), SSCR1_SPH, 0, SSCR0_SerClkDiv(6));
696+ ssp_enable(&hx2750_ssp_dev1);
697+ hx2750_set_egpio(HX2750_EGPIO_TSC_PWR);
698+ }
699+
700+// if (ssp_init(&hx2750_ssp_dev2, 2, 0))
701+// printk(KERN_ERR "Unable to register SSP2 handler!\n");
702+// else {
703+// ssp_disable(&hx2750_ssp_dev2);
704+// ssp_config(&hx2750_ssp_dev2, (SSCR0_TI | (SSCR0_DSS & 0x09 )), 0, 0, SSCR0_SerClkDiv(140));
705+// ssp_enable(&hx2750_ssp_dev2);
706+// }
707+//
708+ if (ssp_init(&hx2750_ssp_dev3, 3, 0))
709+ printk(KERN_ERR "Unable to register SSP3 handler!\n");
710+ else {
711+ ssp_disable(&hx2750_ssp_dev3);
712+ ssp_config(&hx2750_ssp_dev3, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPO | SSCR1_SPH, 0, SSCR0_SerClkDiv(166));
713+ ssp_enable(&hx2750_ssp_dev3);
714+ }
715+
716+ printk("SSP Devices Initialised\n");
717+
718+ return;
719+}
720+
721+struct ssp_state ssp1;
722+
723+void hx2750_ssp_suspend(void)
724+{
725+ ssp_disable(&hx2750_ssp_dev1);
726+ ssp_save_state(&hx2750_ssp_dev1,&ssp1);
727+ hx2750_clear_egpio(HX2750_EGPIO_TSC_PWR);
728+}
729+
730+void hx2750_ssp_resume(void)
731+{
732+ hx2750_set_egpio(HX2750_EGPIO_TSC_PWR);
733+ ssp_restore_state(&hx2750_ssp_dev1,&ssp1);
734+ ssp_enable(&hx2750_ssp_dev1);
735+}
736+
737+void hx2750_ssp_init2(void)
738+{
739+ printk("Stage 1: %x\n",CKEN);
740+ if (ssp_init(&hx2750_ssp_dev2, 2, 0))
741+ printk(KERN_ERR "Unable to register SSP2 handler!\n");
742+ else {
743+ printk("Stage 2: %x\n",CKEN);
744+ ssp_disable(&hx2750_ssp_dev2);
745+ printk("Stage 3: %x\n",CKEN);
746+ ssp_config(&hx2750_ssp_dev2, (SSCR0_TI | (SSCR0_DSS & 0x09 )) | SSCR0_SSE, 0, 0, SSCR0_SerClkDiv(212));
747+ printk("Stage 4: %x\n",CKEN);
748+ ssp_enable(&hx2750_ssp_dev2);
749+ printk("Stage 5: %x\n",CKEN);
750+ }
751+ printk("SSP Device2 Initialised\n");
752+
753+ printk("Sent: 0x3ff\n");
754+ ssp_write_word(&hx2750_ssp_dev2,0x3ff);
755+
756+ return;
757+}
758+
759+void hx2750_ssp2_reset(void)
760+{
761+ ssp_write_word(&hx2750_ssp_dev2,0x000);
762+ ssp_write_word(&hx2750_ssp_dev2,0x000);
763+
764+}
765+
766+unsigned long hx2750_ssp2_read(void)
767+{
768+ u32 ret = 0;
769+ ssp_read_word(&hx2750_ssp_dev2, &ret);
770+ return ret;
771+}
772+
773+void hx2750_ssp2_write(unsigned long data)
774+{
775+ ssp_write_word(&hx2750_ssp_dev2, data);
776+}
777+
778+
779+/*
780+ * Extra hx2750 Specific GPIOs
781+ */
782+void hx2750_send_egpio(unsigned int val)
783+{
784+ int i;
785+
786+ GPCR0 = GPIO_bit(HX2750_GPIO_SR_STROBE);
787+ GPCR1 = GPIO_bit(HX2750_GPIO_SR_CLK1);
788+
789+ for (i=0;i<12;i++) {
790+ if (val & 0x01)
791+ GPSR2 = GPIO_bit(HX2750_GPIO_GPIO_DIN);
792+ else
793+ GPCR2 = GPIO_bit(HX2750_GPIO_GPIO_DIN);
794+ val >>= 1;
795+ GPSR1 = GPIO_bit(HX2750_GPIO_SR_CLK1);
796+ GPCR1 = GPIO_bit(HX2750_GPIO_SR_CLK1);
797+ }
798+
799+ GPSR0 = GPIO_bit(HX2750_GPIO_SR_STROBE);
800+ GPCR0 = GPIO_bit(HX2750_GPIO_SR_STROBE);
801+}
802+
803+EXPORT_SYMBOL(hx2750_send_egpio);
804+
805+unsigned int hx2750_egpio_current;
806+
807+void hx2750_set_egpio(unsigned int gpio)
808+{
809+ hx2750_egpio_current|=gpio;
810+
811+ hx2750_send_egpio(hx2750_egpio_current);
812+}
813+EXPORT_SYMBOL(hx2750_set_egpio);
814+
815+void hx2750_clear_egpio(unsigned int gpio)
816+{
817+ hx2750_egpio_current&=~gpio;
818+
819+ hx2750_send_egpio(hx2750_egpio_current);
820+}
821+EXPORT_SYMBOL(hx2750_clear_egpio);
822+
823+
824+/*
825+ * Touchscreen/Sound/Battery Status
826+ */
827+void hx2750_tsc2101_send(int read, int command, int *values, int numval)
828+{
829+ u32 ret = 0;
830+ int i;
831+
832+ GPCR0 = GPIO_bit(HX2750_GPIO_TSC2101_SS);
833+
834+ ssp_write_word(&hx2750_ssp_dev1, command | read);
835+ /* dummy read */
836+ ssp_read_word(&hx2750_ssp_dev1, &ret);
837+
838+ for (i=0; i < numval; i++) {
839+ if (read) {
840+ ssp_write_word(&hx2750_ssp_dev1, 0);
841+ ssp_read_word(&hx2750_ssp_dev1, &values[i]);
842+ } else {
843+ ssp_write_word(&hx2750_ssp_dev1, values[i]);
844+ ssp_read_word(&hx2750_ssp_dev1, &ret);
845+ }
846+ }
847+
848+ GPSR0 = GPIO_bit(HX2750_GPIO_TSC2101_SS);
849+}
850+
851+static int hx2750_tsc2101_pendown(void)
852+{
853+ if ((GPLR(HX2750_GPIO_PENDOWN) & GPIO_bit(HX2750_GPIO_PENDOWN)) == 0)
854+ return 1;
855+ return 0;
856+}
857+
858+static struct tsc2101_platform_info hx2750_tsc2101_info = {
859+ .send = hx2750_tsc2101_send,
860+ .suspend = hx2750_ssp_suspend,
861+ .resume = hx2750_ssp_resume,
862+ .irq = HX2750_IRQ_GPIO_PENDOWN,
863+ .pendown = hx2750_tsc2101_pendown,
864+};
865+
866+struct platform_device tsc2101_device = {
867+ .name = "tsc2101",
868+ .dev = {
869+ .platform_data = &hx2750_tsc2101_info,
870+ //.parent = &corgissp_device.dev,
871+ },
872+ .id = -1,
873+};
874+
875+
876+/*
877+ * MMC/SD Device
878+ *
879+ * The card detect interrupt isn't debounced so we delay it by 250ms
880+ * to give the card a chance to fully insert/eject.
881+ */
882+static struct pxamci_platform_data hx2750_mci_platform_data;
883+
884+static int hx2750_mci_init(struct device *dev, irq_handler_t hx2750_detect_int, void *data)
885+{
886+ int err;
887+
888+ /*
889+ * setup GPIO for PXA27x MMC controller
890+ */
891+ pxa_gpio_mode(GPIO32_MMCCLK_MD);
892+ pxa_gpio_mode(GPIO112_MMCCMD_MD);
893+ pxa_gpio_mode(GPIO92_MMCDAT0_MD);
894+ pxa_gpio_mode(GPIO109_MMCDAT1_MD);
895+ pxa_gpio_mode(GPIO110_MMCDAT2_MD);
896+ pxa_gpio_mode(GPIO111_MMCDAT3_MD);
897+ pxa_gpio_mode(HX2750_GPIO_SD_DETECT | GPIO_IN);
898+ pxa_gpio_mode(HX2750_GPIO_SD_READONLY | GPIO_IN);
899+
900+ hx2750_mci_platform_data.detect_delay = msecs_to_jiffies(250);
901+
902+ err = request_irq(HX2750_IRQ_GPIO_SD_DETECT, hx2750_detect_int,
903+ IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
904+ "MMC card detect", data);
905+ if (err) {
906+ printk(KERN_ERR "hx2750_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
907+ return -1;
908+ }
909+
910+ return 0;
911+}
912+
913+static void hx2750_mci_setpower(struct device *dev, unsigned int vdd)
914+{
915+ struct pxamci_platform_data* p_d = dev->platform_data;
916+
917+ if (( 1 << vdd) & p_d->ocr_mask)
918+ hx2750_set_egpio(HX2750_EGPIO_SD_PWR);
919+ else
920+ hx2750_clear_egpio(HX2750_EGPIO_SD_PWR);
921+}
922+
923+static void hx2750_mci_exit(struct device *dev, void *data)
924+{
925+ free_irq(HX2750_IRQ_GPIO_SD_DETECT, data);
926+}
927+
928+static struct pxamci_platform_data hx2750_mci_platform_data = {
929+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
930+ .init = hx2750_mci_init,
931+ .setpower = hx2750_mci_setpower,
932+ .exit = hx2750_mci_exit,
933+};
934+
935+
936+/*
937+ * FrameBuffer
938+ */
939+static struct pxafb_mode_info hx2750_pxafb_modes = {
940+ .pixclock = 288462,
941+ .xres = 240,
942+ .yres = 320,
943+ .bpp = 16,
944+ .hsync_len = 20,
945+ .left_margin = 42,
946+ .right_margin = 18,
947+ .vsync_len = 4,
948+ .upper_margin = 3,
949+ .lower_margin = 4,
950+ .sync = 0,
951+};
952+
953+static struct pxafb_mach_info hx2750_pxafb_info = {
954+ .modes = &hx2750_pxafb_modes,
955+ .num_modes = 1,
956+ .fixed_modes = 1,
957+ .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
958+ .lccr3 = LCCR3_PixFlEdg | LCCR3_OutEnH,
959+ .pxafb_backlight_power = NULL,
960+};
961+
962+
963+/*
964+ * Test Device
965+ */
966+static struct platform_device hx2750_test_device = {
967+ .name = "hx2750-test",
968+ .id = -1,
969+};
970+
971+
972+/* Initialization code */
973+static struct platform_device *devices[] __initdata = {
974+ &hx2750_bl_device,
975+ &hx2750_test_device,
976+ &hx2750_pxa_keys,
977+ &tsc2101_device,
978+};
979+
980+static void __init hx2750_init( void )
981+{
982+ PWER = 0xC0000003;// | PWER_RTC;
983+ PFER = 0x00000003;
984+ PRER = 0x00000003;
985+
986+ PGSR0=0x00000018;
987+ PGSR1=0x00000380;
988+ PGSR2=0x00800000;
989+ PGSR3=0x00500400;
990+
991+ //PCFR |= PCFR_OPDE;
992+ PCFR=0x77;
993+ PSLR=0xff100000;
994+ //PCFR=0x10; - does not return from suspend
995+
996+ //PCFR= 0x00004040;
997+ //PSLR= 0xff400f04;
998+
999+ /* Setup Extra GPIO Bank access */
1000+ pxa_gpio_mode(HX2750_GPIO_GPIO_DIN | GPIO_OUT | GPIO_DFLT_HIGH);
1001+ pxa_gpio_mode(HX2750_GPIO_SR_CLK1 | GPIO_OUT | GPIO_DFLT_LOW);
1002+ pxa_gpio_mode(HX2750_GPIO_SR_CLK2 | GPIO_IN);
1003+ pxa_gpio_mode(HX2750_GPIO_SR_STROBE | GPIO_OUT | GPIO_DFLT_LOW);
1004+
1005+ /* Init Extra GPIOs - Bootloader reset default is 0x484 */
1006+ /* This is 0xe84 */
1007+ hx2750_set_egpio(HX2750_EGPIO_2 | HX2750_EGPIO_7 | HX2750_EGPIO_LCD_PWR | HX2750_EGPIO_BL_PWR | HX2750_EGPIO_WIFI_PWR);
1008+
1009+ pxa_set_udc_info(&hx2750_udc_mach_info);
1010+ pxa_set_mci_info(&hx2750_mci_platform_data);
1011+ set_pxa_fb_info(&hx2750_pxafb_info);
1012+ hx2750_ssp_init();
1013+ platform_add_devices (devices, ARRAY_SIZE (devices));
1014+}
1015+
1016+
1017+MACHINE_START(HX2750, "HP iPAQ HX2750")
1018+ .phys_io = 0x40000000,
1019+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
1020+ .boot_params = 0xa0000100,
1021+ .map_io = pxa_map_io,
1022+ .init_irq = pxa_init_irq,
1023+ .timer = &pxa_timer,
1024+ .init_machine = hx2750_init,
1025+MACHINE_END
1026+
1027--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pm.c
1028+++ linux-2.6.24-rc1/arch/arm/mach-pxa/pm.c
1029@@ -17,6 +17,7 @@
1030 #include <linux/time.h>
1031
1032 #include <asm/hardware.h>
1033+#include <asm/mach-types.h>
1034 #include <asm/memory.h>
1035 #include <asm/system.h>
1036 #include <asm/arch/pm.h>
1037@@ -91,6 +92,9 @@
1038 .enter = pxa_pm_enter,
1039 };
1040
1041+unsigned long pxa_pm_pspr_value;
1042+extern void pxa_cpu_resume(void);
1043+
1044 static int __init pxa_pm_init(void)
1045 {
1046 if (!pxa_cpu_pm_fns) {
1047@@ -104,6 +108,7 @@
1048 return -ENOMEM;
1049 }
1050
1051+ pxa_pm_pspr_value=virt_to_phys(pxa_cpu_resume);
1052 suspend_set_ops(&pxa_pm_ops);
1053 return 0;
1054 }
1055--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pxa27x.c
1056+++ linux-2.6.24-rc1/arch/arm/mach-pxa/pxa27x.c
1057@@ -259,6 +259,8 @@
1058 RESTORE(PSTR);
1059 }
1060
1061+extern unsigned long pxa_pm_pspr_value;
1062+
1063 void pxa27x_cpu_pm_enter(suspend_state_t state)
1064 {
1065 extern void pxa_cpu_standby(void);
1066@@ -281,7 +283,7 @@
1067 break;
1068 case PM_SUSPEND_MEM:
1069 /* set resume return address */
1070- PSPR = virt_to_phys(pxa_cpu_resume);
1071+ PSPR = pxa_pm_pspr_value;
1072 pxa27x_cpu_suspend(PWRMODE_SLEEP);
1073 break;
1074 }
1075--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pxa25x.c
1076+++ linux-2.6.24-rc1/arch/arm/mach-pxa/pxa25x.c
1077@@ -200,6 +200,8 @@
1078 RESTORE(PSTR);
1079 }
1080
1081+extern unsigned long pxa_pm_pspr_value;
1082+
1083 static void pxa25x_cpu_pm_enter(suspend_state_t state)
1084 {
1085 CKEN = 0;
1086@@ -207,7 +209,7 @@
1087 switch (state) {
1088 case PM_SUSPEND_MEM:
1089 /* set resume return address */
1090- PSPR = virt_to_phys(pxa_cpu_resume);
1091+ PSPR = pxa_pm_pspr_value;
1092 pxa25x_cpu_suspend(PWRMODE_SLEEP);
1093 break;
1094 }
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 @@
1---
2 drivers/mmc/core/sd.c | 11 ++++++-----
3 1 file changed, 6 insertions(+), 5 deletions(-)
4
5Index: linux-2.6.23/drivers/mmc/core/sd.c
6===================================================================
7--- linux-2.6.23.orig/drivers/mmc/core/sd.c 2007-10-17 11:33:26.000000000 +0200
8+++ linux-2.6.23/drivers/mmc/core/sd.c 2007-10-17 11:33:49.000000000 +0200
9@@ -173,14 +173,15 @@
10
11 scr_struct = UNSTUFF_BITS(resp, 60, 4);
12 if (scr_struct != 0) {
13- printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
14+ printk(KERN_WARNING "%s: unrecognised SCR structure version %d\n",
15 mmc_hostname(card->host), scr_struct);
16- return -EINVAL;
17+ scr->sda_vsn = 0;
18+ scr->bus_widths = 0;
19+ } else {
20+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
21+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
22 }
23
24- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
25- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
26-
27 return 0;
28 }
29
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 @@
1---
2 arch/arm/Kconfig | 2
3 drivers/Kconfig | 2
4 drivers/Makefile | 1
5 drivers/power/Kconfig | 70 +++++
6 drivers/power/Makefile | 28 ++
7 drivers/power/adc_battery.c | 278 +++++++++++++++++++++
8 drivers/power/apm_power.c | 247 +++++++++++++++++++
9 drivers/power/ds2760_battery.c | 475 +++++++++++++++++++++++++++++++++++++
10 drivers/power/micro_battery.c | 257 ++++++++++++++++++++
11 drivers/power/olpc_battery.c | 302 +++++++++++++++++++++++
12 drivers/power/pda_power.c | 263 ++++++++++++++++++++
13 drivers/power/pmu_battery.c | 215 ++++++++++++++++
14 drivers/power/power_supply.h | 42 +++
15 drivers/power/power_supply_core.c | 168 +++++++++++++
16 drivers/power/power_supply_leds.c | 188 ++++++++++++++
17 drivers/power/power_supply_sysfs.c | 289 ++++++++++++++++++++++
18 drivers/power/simpad-battery.c | 242 ++++++++++++++++++
19 include/linux/power_supply.h | 175 +++++++++++++
20 18 files changed, 3244 insertions(+)
21
22Index: linux-2.6.22/drivers/power/adc_battery.c
23===================================================================
24--- /dev/null 1970-01-01 00:00:00.000000000 +0000
25+++ linux-2.6.22/drivers/power/adc_battery.c 2007-08-23 12:26:28.000000000 +0200
26@@ -0,0 +1,278 @@
27+/*
28+ * Copyright (c) 2007 Paul Sokolovsky
29+ *
30+ * This program is free software; you can redistribute it and/or modify
31+ * it under the terms of the GNU General Public License as published by
32+ * the Free Software Foundation; either version 2 of the License, or
33+ * (at your option) any later version.
34+ *
35+ */
36+
37+//#define DEBUG
38+
39+#include <linux/module.h>
40+#include <linux/interrupt.h>
41+#include <linux/pm.h>
42+#include <linux/delay.h>
43+#include <linux/workqueue.h>
44+#include <linux/platform_device.h>
45+#include <linux/power_supply.h>
46+#include <linux/adc.h>
47+#include <linux/adc_battery.h>
48+
49+#include <asm/irq.h>
50+
51+#define PIN_NO_VOLT 0
52+#define PIN_NO_CURR 1
53+#define PIN_NO_TEMP 2
54+
55+struct battery_adc_priv {
56+ struct power_supply batt_cdev;
57+
58+ struct battery_adc_platform_data *pdata;
59+
60+ struct adc_request req;
61+ struct adc_sense pins[3];
62+ struct adc_sense last_good_pins[3];
63+
64+ struct workqueue_struct *wq;
65+ struct delayed_work work;
66+};
67+
68+/*
69+ * Battery properties
70+ */
71+
72+static int adc_battery_get_property(struct power_supply *psy,
73+ enum power_supply_property psp,
74+ union power_supply_propval *val)
75+{
76+ struct battery_adc_priv* drvdata = (struct battery_adc_priv*)psy;
77+ int voltage;
78+
79+ switch (psp) {
80+ case POWER_SUPPLY_PROP_STATUS:
81+ val->intval = drvdata->pdata->charge_status;
82+ break;
83+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
84+ val->intval = drvdata->pdata->battery_info.voltage_max_design;
85+ break;
86+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
87+ val->intval = drvdata->pdata->battery_info.voltage_min_design;
88+ break;
89+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
90+ val->intval = drvdata->pdata->battery_info.charge_full_design;
91+ break;
92+ case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
93+ val->intval = drvdata->pdata->battery_info.charge_empty_design;
94+ break;
95+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
96+ val->intval = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
97+ break;
98+ case POWER_SUPPLY_PROP_CURRENT_NOW:
99+ val->intval = drvdata->last_good_pins[PIN_NO_CURR].value * drvdata->pdata->current_mult;
100+ break;
101+ case POWER_SUPPLY_PROP_CHARGE_NOW:
102+ /* We do calculations in mX, not uX, because todo it in uX we should use "long long"s,
103+ * which is a mess (need to use do_div) when you need divide operation). */
104+ voltage = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
105+ val->intval = ((voltage/1000 - drvdata->pdata->battery_info.voltage_min_design/1000) *
106+ (drvdata->pdata->battery_info.charge_full_design/1000 -
107+ drvdata->pdata->battery_info.charge_empty_design/1000)) /
108+ (drvdata->pdata->battery_info.voltage_max_design/1000 -
109+ drvdata->pdata->battery_info.voltage_min_design/1000);
110+ val->intval *= 1000; /* convert final result to uX */
111+ break;
112+ case POWER_SUPPLY_PROP_TEMP:
113+ val->intval = drvdata->last_good_pins[PIN_NO_TEMP].value * drvdata->pdata->temperature_mult / 1000;
114+ break;
115+ default:
116+ return -EINVAL;
117+ };
118+ return 0;
119+}
120+
121+/*
122+ * Driver body
123+ */
124+
125+static void adc_battery_query(struct battery_adc_priv *drvdata)
126+{
127+ struct battery_adc_platform_data *pdata = drvdata->pdata;
128+ int powered, charging;
129+
130+ adc_request_sample(&drvdata->req);
131+
132+ powered = power_supply_am_i_supplied(&drvdata->batt_cdev);
133+ charging = pdata->is_charging ? pdata->is_charging() : -1;
134+
135+ if (powered && charging)
136+ pdata->charge_status = POWER_SUPPLY_STATUS_CHARGING;
137+ else if (powered && !charging && charging != -1)
138+ pdata->charge_status = POWER_SUPPLY_STATUS_FULL;
139+ else
140+ pdata->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
141+
142+ /* Throw away invalid samples, this may happen soon after resume for example. */
143+ if (drvdata->pins[PIN_NO_VOLT].value > 0) {
144+ memcpy(drvdata->last_good_pins, drvdata->pins, sizeof(drvdata->pins));
145+#ifdef DEBUG
146+ printk("%d %d %d\n", drvdata->pins[PIN_NO_VOLT].value,
147+ drvdata->pins[PIN_NO_CURR].value,
148+ drvdata->pins[PIN_NO_TEMP].value);
149+#endif
150+ }
151+}
152+
153+static void adc_battery_charge_power_changed(struct power_supply *bat)
154+{
155+ struct battery_adc_priv *drvdata = (struct battery_adc_priv*)bat;
156+ cancel_delayed_work(&drvdata->work);
157+ queue_delayed_work(drvdata->wq, &drvdata->work, 0);
158+}
159+
160+static void adc_battery_work_func(struct work_struct *work)
161+{
162+ struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);
163+ struct battery_adc_priv *drvdata = container_of(delayed_work, struct battery_adc_priv, work);
164+
165+ adc_battery_query(drvdata);
166+ power_supply_changed(&drvdata->batt_cdev);
167+
168+ queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
169+}
170+
171+static int adc_battery_probe(struct platform_device *pdev)
172+{
173+ int retval;
174+ struct battery_adc_platform_data *pdata = pdev->dev.platform_data;
175+ struct battery_adc_priv *drvdata;
176+ int i, j;
177+ enum power_supply_property props[] = {
178+ POWER_SUPPLY_PROP_STATUS,
179+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
180+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
181+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
182+ POWER_SUPPLY_PROP_CURRENT_NOW,
183+ POWER_SUPPLY_PROP_CHARGE_NOW,
184+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
185+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
186+ POWER_SUPPLY_PROP_TEMP,
187+ };
188+
189+ // Initialize ts data structure.
190+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
191+ if (!drvdata)
192+ return -ENOMEM;
193+
194+ drvdata->batt_cdev.name = pdata->battery_info.name;
195+ drvdata->batt_cdev.use_for_apm = pdata->battery_info.use_for_apm;
196+ drvdata->batt_cdev.num_properties = ARRAY_SIZE(props);
197+ drvdata->batt_cdev.get_property = adc_battery_get_property;
198+ drvdata->batt_cdev.external_power_changed =
199+ adc_battery_charge_power_changed;
200+
201+ if (!pdata->voltage_pin) {
202+ drvdata->batt_cdev.num_properties--;
203+ props[3] = -1;
204+ }
205+ if (!pdata->current_pin) {
206+ drvdata->batt_cdev.num_properties--;
207+ props[4] = -1;
208+ }
209+ if (!pdata->temperature_pin) {
210+ drvdata->batt_cdev.num_properties--;
211+ props[8] = -1;
212+ }
213+
214+ drvdata->batt_cdev.properties = kmalloc(
215+ sizeof(*drvdata->batt_cdev.properties) *
216+ drvdata->batt_cdev.num_properties, GFP_KERNEL);
217+ if (!drvdata->batt_cdev.properties)
218+ return -ENOMEM;
219+
220+ j = 0;
221+ for (i = 0; i < ARRAY_SIZE(props); i++) {
222+ if (props[i] == -1)
223+ continue;
224+ drvdata->batt_cdev.properties[j++] = props[i];
225+ }
226+
227+ retval = power_supply_register(&pdev->dev, &drvdata->batt_cdev);
228+ if (retval) {
229+ printk("adc-battery: Error registering battery classdev");
230+ return retval;
231+ }
232+
233+ drvdata->req.senses = drvdata->pins;
234+ drvdata->req.num_senses = ARRAY_SIZE(drvdata->pins);
235+ drvdata->pins[PIN_NO_VOLT].name = pdata->voltage_pin;
236+ drvdata->pins[PIN_NO_CURR].name = pdata->current_pin;
237+ drvdata->pins[PIN_NO_TEMP].name = pdata->temperature_pin;
238+
239+ adc_request_register(&drvdata->req);
240+
241+ /* Here we assume raw values in mV */
242+ if (!pdata->voltage_mult)
243+ pdata->voltage_mult = 1000;
244+ /* Here we assume raw values in mA */
245+ if (!pdata->current_mult)
246+ pdata->current_mult = 1000;
247+ /* Here we assume raw values in 1/10 C */
248+ if (!pdata->temperature_mult)
249+ pdata->temperature_mult = 1000;
250+
251+ drvdata->pdata = pdata;
252+ pdata->drvdata = drvdata; /* Seems ugly, we need better solution */
253+
254+ platform_set_drvdata(pdev, drvdata);
255+
256+ // Load initial values ASAP
257+ adc_battery_query(drvdata);
258+
259+ // Still schedule next sampling soon
260+ INIT_DELAYED_WORK(&drvdata->work, adc_battery_work_func);
261+ drvdata->wq = create_workqueue(pdev->dev.bus_id);
262+ if (!drvdata->wq)
263+ return -ESRCH;
264+
265+ queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
266+
267+ return retval;
268+}
269+
270+static int adc_battery_remove(struct platform_device *pdev)
271+{
272+ struct battery_adc_priv *drvdata = platform_get_drvdata(pdev);
273+ cancel_delayed_work(&drvdata->work);
274+ destroy_workqueue(drvdata->wq);
275+ power_supply_unregister(&drvdata->batt_cdev);
276+ adc_request_unregister(&drvdata->req);
277+ kfree(drvdata->batt_cdev.properties);
278+ return 0;
279+}
280+
281+static struct platform_driver adc_battery_driver = {
282+ .driver = {
283+ .name = "adc-battery",
284+ },
285+ .probe = adc_battery_probe,
286+ .remove = adc_battery_remove,
287+};
288+
289+static int __init adc_battery_init(void)
290+{
291+ return platform_driver_register(&adc_battery_driver);
292+}
293+
294+static void __exit adc_battery_exit(void)
295+{
296+ platform_driver_unregister(&adc_battery_driver);
297+}
298+
299+module_init(adc_battery_init)
300+module_exit(adc_battery_exit)
301+
302+MODULE_AUTHOR("Paul Sokolovsky");
303+MODULE_DESCRIPTION("Battery driver for ADC device");
304+MODULE_LICENSE("GPL");
305Index: linux-2.6.22/drivers/power/apm_power.c
306===================================================================
307--- /dev/null 1970-01-01 00:00:00.000000000 +0000
308+++ linux-2.6.22/drivers/power/apm_power.c 2007-08-23 12:13:52.000000000 +0200
309@@ -0,0 +1,247 @@
310+/*
311+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
312+ * Copyright (c) 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
313+ *
314+ * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
315+ *
316+ * Use consistent with the GNU GPL is permitted,
317+ * provided that this copyright notice is
318+ * preserved in its entirety in all copies and derived works.
319+ */
320+
321+#include <linux/module.h>
322+#include <linux/power_supply.h>
323+#include <linux/apm-emulation.h>
324+
325+#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
326+ POWER_SUPPLY_PROP_##prop, val)
327+
328+#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
329+ prop, val)
330+
331+#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
332+
333+static struct power_supply *main_battery;
334+
335+static void find_main_battery(void)
336+{
337+ struct device *dev;
338+ struct power_supply *bat, *batm;
339+ union power_supply_propval full;
340+ int max_charge = 0;
341+
342+ main_battery = NULL;
343+ batm = NULL;
344+ list_for_each_entry(dev, &power_supply_class->devices, node) {
345+ bat = dev_get_drvdata(dev);
346+ /* If none of battery devices cantains 'use_for_apm' flag,
347+ choice one with maximum design charge */
348+ if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
349+ if (full.intval > max_charge) {
350+ batm = bat;
351+ max_charge = full.intval;
352+ }
353+ }
354+
355+ if (bat->use_for_apm)
356+ main_battery = bat;
357+ }
358+ if (!main_battery)
359+ main_battery = batm;
360+
361+ return;
362+}
363+
364+static int calculate_time(int status)
365+{
366+ union power_supply_propval charge_full, charge_empty;
367+ union power_supply_propval charge, I;
368+
369+ if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
370+ /* if battery can't report this property, use design value */
371+ if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
372+ return -1;
373+ }
374+
375+ if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
376+ /* if battery can't report this property, use design value */
377+ if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
378+ charge_empty.intval = 0;
379+ }
380+
381+ if (MPSY_PROP(CHARGE_AVG, &charge)) {
382+ /* if battery can't report average value, use momentary */
383+ if (MPSY_PROP(CHARGE_NOW, &charge))
384+ return -1;
385+ }
386+
387+ if (MPSY_PROP(CURRENT_AVG, &I)) {
388+ /* if battery can't report average value, use momentary */
389+ if (MPSY_PROP(CURRENT_NOW, &I))
390+ return -1;
391+ }
392+
393+ if (I.intval == 0)
394+ return 0;
395+ else if (status == POWER_SUPPLY_STATUS_CHARGING)
396+ return ((charge.intval - charge_full.intval) * 60L) /
397+ I.intval;
398+ else
399+ return -((charge.intval - charge_empty.intval) * 60L) /
400+ I.intval;
401+}
402+
403+static int calculate_capacity(int using_charge)
404+{
405+ enum power_supply_property full_prop, empty_prop;
406+ enum power_supply_property full_design_prop, empty_design_prop;
407+ enum power_supply_property now_prop, avg_prop;
408+ union power_supply_propval empty, full, cur;
409+ int ret;
410+
411+ if (using_charge) {
412+ full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
413+ empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
414+ full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
415+ empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
416+ now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
417+ avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
418+ }
419+ else {
420+ full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
421+ empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
422+ full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
423+ empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
424+ now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
425+ avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
426+ }
427+
428+ if (_MPSY_PROP(full_prop, &full)) {
429+ /* if battery can't report this property, use design value */
430+ if (_MPSY_PROP(full_design_prop, &full))
431+ return -1;
432+ }
433+
434+ if (_MPSY_PROP(avg_prop, &cur)) {
435+ /* if battery can't report average value, use momentary */
436+ if (_MPSY_PROP(now_prop, &cur))
437+ return -1;
438+ }
439+
440+ if (_MPSY_PROP(empty_prop, &empty)) {
441+ /* if battery can't report this property, use design value */
442+ if (_MPSY_PROP(empty_design_prop, &empty))
443+ empty.intval = 0;
444+ }
445+
446+ if (full.intval - empty.intval)
447+ ret = ((cur.intval - empty.intval) * 100L) /
448+ (full.intval - empty.intval);
449+ else
450+ return -1;
451+
452+ if (ret > 100)
453+ return 100;
454+ else if (ret < 0)
455+ return 0;
456+
457+ return ret;
458+}
459+
460+static void apm_battery_apm_get_power_status(struct apm_power_info *info)
461+{
462+ union power_supply_propval status;
463+ union power_supply_propval capacity, time_to_full, time_to_empty;
464+
465+ down(&power_supply_class->sem);
466+ find_main_battery();
467+ if (!main_battery) {
468+ up(&power_supply_class->sem);
469+ return;
470+ }
471+
472+ /* status */
473+
474+ if (MPSY_PROP(STATUS, &status))
475+ status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
476+
477+ /* ac line status */
478+
479+ if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
480+ (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
481+ (status.intval == POWER_SUPPLY_STATUS_FULL))
482+ info->ac_line_status = APM_AC_ONLINE;
483+ else
484+ info->ac_line_status = APM_AC_OFFLINE;
485+
486+ /* battery life (i.e. capacity, in percents) */
487+
488+ if (MPSY_PROP(CAPACITY, &capacity) == 0)
489+ info->battery_life = capacity.intval;
490+ else {
491+ /* try calculate using energy */
492+ info->battery_life = calculate_capacity(0);
493+ /* if failed try calculate using charge instead */
494+ if (info->battery_life == -1)
495+ info->battery_life = calculate_capacity(1);
496+ }
497+
498+ /* charging status */
499+
500+ if (status.intval == POWER_SUPPLY_STATUS_CHARGING)
501+ info->battery_status = APM_BATTERY_STATUS_CHARGING;
502+ else {
503+ if (info->battery_life > 50)
504+ info->battery_status = APM_BATTERY_STATUS_HIGH;
505+ else if (info->battery_life > 5)
506+ info->battery_status = APM_BATTERY_STATUS_LOW;
507+ else
508+ info->battery_status = APM_BATTERY_STATUS_CRITICAL;
509+ }
510+ info->battery_flag = info->battery_status;
511+
512+ /* time */
513+
514+ info->units = APM_UNITS_MINS;
515+
516+ if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
517+ if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
518+ if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
519+ info->time = calculate_time(status.intval);
520+ else
521+ info->time = time_to_full.intval / 60;
522+ }
523+ }
524+ else {
525+ if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
526+ if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
527+ info->time = calculate_time(status.intval);
528+ else
529+ info->time = time_to_empty.intval / 60;
530+ }
531+ }
532+
533+ up(&power_supply_class->sem);
534+ return;
535+}
536+
537+static int __init apm_battery_init(void)
538+{
539+ printk(KERN_INFO "APM Battery Driver\n");
540+
541+ apm_get_power_status = apm_battery_apm_get_power_status;
542+ return 0;
543+}
544+
545+static void __exit apm_battery_exit(void)
546+{
547+ apm_get_power_status = NULL;
548+ return;
549+}
550+
551+module_init(apm_battery_init);
552+module_exit(apm_battery_exit);
553+
554+MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
555+MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
556+MODULE_LICENSE("GPL");
557Index: linux-2.6.22/drivers/power/ds2760_battery.c
558===================================================================
559--- /dev/null 1970-01-01 00:00:00.000000000 +0000
560+++ linux-2.6.22/drivers/power/ds2760_battery.c 2007-08-23 12:13:52.000000000 +0200
561@@ -0,0 +1,475 @@
562+/*
563+ * Driver for batteries with DS2760 chips inside.
564+ *
565+ * Copyright (c) 2007 Anton Vorontsov
566+ * 2004-2007 Matt Reimer
567+ * 2004 Szabolcs Gyurko
568+ *
569+ * Use consistent with the GNU GPL is permitted,
570+ * provided that this copyright notice is
571+ * preserved in its entirety in all copies and derived works.
572+ *
573+ * Author: Anton Vorontsov <cbou@mail.ru>
574+ * February 2007
575+ *
576+ * Matt Reimer <mreimer@vpop.net>
577+ * April 2004, 2005, 2007
578+ *
579+ * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
580+ * September 2004
581+ */
582+
583+#include <linux/module.h>
584+#include <linux/param.h>
585+#include <linux/jiffies.h>
586+#include <linux/workqueue.h>
587+#include <linux/pm.h>
588+#include <linux/platform_device.h>
589+#include <linux/power_supply.h>
590+
591+#include "../w1/w1.h"
592+#include "../w1/slaves/w1_ds2760.h"
593+
594+struct ds2760_device_info {
595+ struct device *dev;
596+
597+ /* DS2760 data, valid after calling ds2760_battery_read_status() */
598+ unsigned long update_time; /* jiffies when data read */
599+ char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */
600+ int voltage_raw; /* units of 4.88 mV */
601+ int voltage_uV; /* units of uV */
602+ int current_raw; /* units of 0.625 mA */
603+ int current_uA; /* units of uA */
604+ int accum_current_raw; /* units of 0.25 mAh */
605+ int accum_current_uAh; /* units of uAh */
606+ int temp_raw; /* units of 0.125 C */
607+ int temp_C; /* units of 0.1 C */
608+ int rated_capacity; /* units of uAh */
609+ int rem_capacity; /* percentage */
610+ int full_active_uAh; /* units of uAh */
611+ int empty_uAh; /* units of uAh */
612+ int life_sec; /* units of seconds */
613+ int charge_status; /* POWER_SUPPLY_STATUS_* */
614+
615+ int full_counter;
616+ struct power_supply bat;
617+ struct device *w1_dev;
618+ struct workqueue_struct *monitor_wqueue;
619+ struct delayed_work monitor_work;
620+};
621+
622+static unsigned int cache_time = 1000;
623+module_param(cache_time, uint, 0644);
624+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
625+
626+/* Some batteries have their rated capacity stored a N * 10 mAh, while
627+ * others use an index into this table. */
628+static int rated_capacities[] = {
629+ 0,
630+ 920, /* Samsung */
631+ 920, /* BYD */
632+ 920, /* Lishen */
633+ 920, /* NEC */
634+ 1440, /* Samsung */
635+ 1440, /* BYD */
636+ 1440, /* Lishen */
637+ 1440, /* NEC */
638+ 2880, /* Samsung */
639+ 2880, /* BYD */
640+ 2880, /* Lishen */
641+ 2880 /* NEC */
642+};
643+
644+/* array is level at temps 0C, 10C, 20C, 30C, 40C
645+ * temp is in Celsius */
646+static int battery_interpolate(int array[], int temp)
647+{
648+ int index, dt;
649+
650+ if (temp <= 0)
651+ return array[0];
652+ if (temp >= 40)
653+ return array[4];
654+
655+ index = temp / 10;
656+ dt = temp % 10;
657+
658+ return array[index] + (((array[index + 1] - array[index]) * dt) / 10);
659+}
660+
661+static int ds2760_battery_read_status(struct ds2760_device_info *di)
662+{
663+ int ret, i, start, count, scale[5];
664+
665+ if (di->update_time && time_before(jiffies, di->update_time +
666+ msecs_to_jiffies(cache_time)))
667+ return 0;
668+
669+ /* The first time we read the entire contents of SRAM/EEPROM,
670+ * but after that we just read the interesting bits that change. */
671+ if (di->update_time == 0) {
672+ start = 0;
673+ count = DS2760_DATA_SIZE;
674+ }
675+ else {
676+ start = DS2760_VOLTAGE_MSB;
677+ count = DS2760_TEMP_LSB - start + 1;
678+ }
679+
680+ ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count);
681+ if (ret != count) {
682+ dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n",
683+ di->w1_dev);
684+ return 1;
685+ }
686+
687+ di->update_time = jiffies;
688+
689+ /* DS2760 reports voltage in units of 4.88mV, but the battery class
690+ * reports in units of uV, so convert by multiplying by 4880. */
691+ di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) |
692+ (di->raw[DS2760_VOLTAGE_LSB] >> 5);
693+ di->voltage_uV = di->voltage_raw * 4880;
694+
695+ /* DS2760 reports current in signed units of 0.625mA, but the battery
696+ * class reports in units of uA, so convert by multiplying by 625. */
697+ di->current_raw =
698+ (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) |
699+ (di->raw[DS2760_CURRENT_LSB] >> 3);
700+ di->current_uA = di->current_raw * 625;
701+
702+ /* DS2760 reports accumulated current in signed units of 0.25mAh. */
703+ di->accum_current_raw =
704+ (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) |
705+ di->raw[DS2760_CURRENT_ACCUM_LSB];
706+ di->accum_current_uAh = di->accum_current_raw * 250;
707+
708+ /* DS2760 reports temperature in signed units of 0.125C, but the
709+ * battery class reports in units of 1/10 C, so we convert by
710+ * multiplying by .125 * 10 = 1.25. */
711+ di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) |
712+ (di->raw[DS2760_TEMP_LSB] >> 5);
713+ di->temp_C = di->temp_raw + (di->temp_raw / 4);
714+
715+ /* At least some battery monitors (e.g. HP iPAQ) store the battery's
716+ * maximum rated capacity. */
717+ if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities))
718+ di->rated_capacity = rated_capacities[
719+ (unsigned int)di->raw[DS2760_RATED_CAPACITY]];
720+ else
721+ di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10;
722+
723+ di->rated_capacity *= 1000; /* convert to uAh */
724+
725+ /* Calculate the full level at the present temperature. */
726+ di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
727+ di->raw[DS2760_ACTIVE_FULL + 1];
728+
729+ scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 |
730+ di->raw[DS2760_ACTIVE_FULL + 1];
731+ for (i = 1; i < 5; i++)
732+ scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
733+
734+ di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
735+ di->full_active_uAh *= 1000; /* convert to uAh */
736+
737+ /* Calculate the empty level at the present temperature. */
738+ scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4];
739+ for (i = 3; i >= 0; i--)
740+ scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i];
741+
742+ di->empty_uAh = battery_interpolate(scale, di->temp_C / 10);
743+ di->empty_uAh *= 1000; /* convert to uAh */
744+
745+ /* From Maxim Application Note 131: remaining capacity =
746+ * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */
747+ di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) /
748+ (di->full_active_uAh - di->empty_uAh);
749+
750+ if (di->rem_capacity < 0)
751+ di->rem_capacity = 0;
752+ if (di->rem_capacity > 100)
753+ di->rem_capacity = 100;
754+
755+ if (di->current_uA)
756+ di->life_sec = -((di->accum_current_uAh - di->empty_uAh) *
757+ 3600L) / di->current_uA;
758+ else
759+ di->life_sec = 0;
760+
761+ return 0;
762+}
763+
764+static void ds2760_battery_update_status(struct ds2760_device_info *di)
765+{
766+ int old_charge_status = di->charge_status;
767+
768+ ds2760_battery_read_status(di);
769+
770+ if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN)
771+ di->full_counter = 0;
772+
773+ if (power_supply_am_i_supplied(&di->bat)) {
774+ if (di->current_uA > 10000) {
775+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
776+ di->full_counter = 0;
777+ }
778+ else if (di->current_uA < -5000) {
779+ if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING)
780+ dev_notice(di->dev, "not enough power to "
781+ "charge\n");
782+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
783+ di->full_counter = 0;
784+ }
785+ else if (di->current_uA < 10000 &&
786+ di->charge_status != POWER_SUPPLY_STATUS_FULL) {
787+
788+ /* Don't consider the battery to be full unless
789+ * we've seen the current < 10 mA at least two
790+ * consecutive times. */
791+
792+ di->full_counter++;
793+
794+ if (di->full_counter < 2)
795+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
796+ else {
797+ unsigned char acr[2];
798+ int acr_val;
799+
800+ /* acr is in units of 0.25 mAh */
801+ acr_val = di->full_active_uAh * 4L / 1000;
802+
803+ acr[0] = acr_val >> 8;
804+ acr[1] = acr_val & 0xff;
805+
806+ if (w1_ds2760_write(di->w1_dev, acr,
807+ DS2760_CURRENT_ACCUM_MSB, 2) < 2)
808+ dev_warn(di->dev,
809+ "ACR reset failed\n");
810+
811+ di->charge_status = POWER_SUPPLY_STATUS_FULL;
812+ }
813+ }
814+ }
815+ else {
816+ di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
817+ di->full_counter = 0;
818+ }
819+
820+ if (di->charge_status != old_charge_status)
821+ power_supply_changed(&di->bat);
822+
823+ return;
824+}
825+
826+static void ds2760_battery_work(struct work_struct *work)
827+{
828+ struct ds2760_device_info *di = container_of(work,
829+ struct ds2760_device_info, monitor_work.work);
830+ const int interval = HZ * 60;
831+
832+ dev_dbg(di->dev, "%s\n", __FUNCTION__);
833+
834+ ds2760_battery_update_status(di);
835+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
836+
837+ return;
838+}
839+
840+#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \
841+ bat);
842+
843+static void ds2760_battery_external_power_changed(struct power_supply *psy)
844+{
845+ struct ds2760_device_info *di = to_ds2760_device_info(psy);
846+
847+ dev_dbg(di->dev, "%s\n", __FUNCTION__);
848+
849+ cancel_delayed_work(&di->monitor_work);
850+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
851+
852+ return;
853+}
854+
855+static int ds2760_battery_get_property(struct power_supply *psy,
856+ enum power_supply_property psp,
857+ union power_supply_propval *val)
858+{
859+ struct ds2760_device_info *di = to_ds2760_device_info(psy);
860+
861+ switch (psp) {
862+ case POWER_SUPPLY_PROP_STATUS:
863+ val->intval = di->charge_status;
864+ return 0;
865+ default:
866+ break;
867+ }
868+
869+ ds2760_battery_read_status(di);
870+
871+ switch (psp) {
872+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
873+ val->intval = di->voltage_uV;
874+ break;
875+ case POWER_SUPPLY_PROP_CURRENT_NOW:
876+ val->intval = di->current_uA;
877+ break;
878+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
879+ val->intval = di->rated_capacity;
880+ break;
881+ case POWER_SUPPLY_PROP_CHARGE_FULL:
882+ val->intval = di->full_active_uAh;
883+ break;
884+ case POWER_SUPPLY_PROP_CHARGE_EMPTY:
885+ val->intval = di->empty_uAh;
886+ break;
887+ case POWER_SUPPLY_PROP_CHARGE_NOW:
888+ val->intval = di->accum_current_uAh;
889+ break;
890+ case POWER_SUPPLY_PROP_TEMP:
891+ val->intval = di->temp_C;
892+ break;
893+ default:
894+ return -EINVAL;
895+ }
896+
897+ return 0;
898+}
899+
900+static enum power_supply_property ds2760_battery_props[] = {
901+ POWER_SUPPLY_PROP_STATUS,
902+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
903+ POWER_SUPPLY_PROP_CURRENT_NOW,
904+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
905+ POWER_SUPPLY_PROP_CHARGE_FULL,
906+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
907+ POWER_SUPPLY_PROP_CHARGE_NOW,
908+ POWER_SUPPLY_PROP_TEMP,
909+};
910+
911+static int ds2760_battery_probe(struct platform_device *pdev)
912+{
913+ int retval = 0;
914+ struct ds2760_device_info *di;
915+ struct ds2760_platform_data *pdata;
916+
917+ di = kzalloc(sizeof(*di), GFP_KERNEL);
918+ if (!di) {
919+ retval = -ENOMEM;
920+ goto di_alloc_failed;
921+ }
922+
923+ platform_set_drvdata(pdev, di);
924+
925+ pdata = pdev->dev.platform_data;
926+ di->dev = &pdev->dev;
927+ di->w1_dev = pdev->dev.parent;
928+ di->bat.name = pdev->dev.bus_id;
929+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
930+ di->bat.properties = ds2760_battery_props;
931+ di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
932+ di->bat.get_property = ds2760_battery_get_property;
933+ di->bat.external_power_changed =
934+ ds2760_battery_external_power_changed;
935+ di->bat.use_for_apm = 1;
936+
937+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
938+
939+ retval = power_supply_register(&pdev->dev, &di->bat);
940+ if (retval) {
941+ dev_err(di->dev, "failed to register battery");
942+ goto batt_failed;
943+ }
944+
945+ INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
946+ di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id);
947+ if (!di->monitor_wqueue) {
948+ retval = -ESRCH;
949+ goto workqueue_failed;
950+ }
951+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1);
952+
953+ goto success;
954+
955+workqueue_failed:
956+ power_supply_unregister(&di->bat);
957+batt_failed:
958+ kfree(di);
959+di_alloc_failed:
960+success:
961+ return retval;
962+}
963+
964+static int ds2760_battery_remove(struct platform_device *pdev)
965+{
966+ struct ds2760_device_info *di = platform_get_drvdata(pdev);
967+
968+ cancel_rearming_delayed_workqueue(di->monitor_wqueue,
969+ &di->monitor_work);
970+ destroy_workqueue(di->monitor_wqueue);
971+ power_supply_unregister(&di->bat);
972+
973+ return 0;
974+}
975+
976+#ifdef CONFIG_PM
977+
978+static int ds2760_battery_suspend(struct platform_device *pdev,
979+ pm_message_t state)
980+{
981+ struct ds2760_device_info *di = platform_get_drvdata(pdev);
982+
983+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
984+
985+ return 0;
986+}
987+
988+static int ds2760_battery_resume(struct platform_device *pdev)
989+{
990+ struct ds2760_device_info *di = platform_get_drvdata(pdev);
991+
992+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
993+ power_supply_changed(&di->bat);
994+
995+ cancel_delayed_work(&di->monitor_work);
996+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
997+
998+ return 0;
999+}
1000+
1001+#else
1002+
1003+#define ds2760_battery_suspend NULL
1004+#define ds2760_battery_resume NULL
1005+
1006+#endif /* CONFIG_PM */
1007+
1008+static struct platform_driver ds2760_battery_driver = {
1009+ .driver = {
1010+ .name = "ds2760-battery",
1011+ },
1012+ .probe = ds2760_battery_probe,
1013+ .remove = ds2760_battery_remove,
1014+ .suspend = ds2760_battery_suspend,
1015+ .resume = ds2760_battery_resume,
1016+};
1017+
1018+static int __init ds2760_battery_init(void)
1019+{
1020+ return platform_driver_register(&ds2760_battery_driver);
1021+}
1022+
1023+static void __exit ds2760_battery_exit(void)
1024+{
1025+ platform_driver_unregister(&ds2760_battery_driver);
1026+ return;
1027+}
1028+
1029+module_init(ds2760_battery_init);
1030+module_exit(ds2760_battery_exit);
1031+
1032+MODULE_LICENSE("GPL");
1033+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
1034+ "Matt Reimer <mreimer@vpop.net>, "
1035+ "Anton Vorontsov <cbou@mail.ru>");
1036+MODULE_DESCRIPTION("ds2760 battery driver");
1037Index: linux-2.6.22/drivers/power/Kconfig
1038===================================================================
1039--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1040+++ linux-2.6.22/drivers/power/Kconfig 2007-08-23 12:13:52.000000000 +0200
1041@@ -0,0 +1,70 @@
1042+menuconfig POWER_SUPPLY
1043+ tristate "Power supply class support"
1044+ help
1045+ Say Y here to enable power supply class support. This allows
1046+ power supply (batteries, AC, USB) monitoring by userspace
1047+ via sysfs and uevent (if available) and/or APM kernel interface
1048+ (if selected below).
1049+
1050+if POWER_SUPPLY
1051+
1052+config POWER_SUPPLY_DEBUG
1053+ bool "Power supply debug"
1054+ help
1055+ Say Y here to enable debugging messages for power supply class
1056+ and drivers.
1057+
1058+config PDA_POWER
1059+ tristate "Generic PDA/phone power driver"
1060+ help
1061+ Say Y here to enable generic power driver for PDAs and phones with
1062+ one or two external power supplies (AC/USB) connected to main and
1063+ backup batteries, and optional builtin charger.
1064+
1065+config APM_POWER
1066+ tristate "APM emulation for class batteries"
1067+ depends on APM_EMULATION
1068+ help
1069+ Say Y here to enable support APM status emulation using
1070+ battery class devices.
1071+
1072+config BATTERY_DS2760
1073+ tristate "DS2760 battery driver (HP iPAQ & others)"
1074+ select W1
1075+ select W1_SLAVE_DS2760
1076+ help
1077+ Say Y here to enable support for batteries with ds2760 chip.
1078+
1079+config BATTERY_PMU
1080+ tristate "Apple PMU battery"
1081+ depends on ADB_PMU
1082+ help
1083+ Say Y here to expose battery information on Apple machines
1084+ through the generic battery class.
1085+
1086+config BATTERY_OLPC
1087+ tristate "One Laptop Per Child battery"
1088+ depends on X86_32
1089+ help
1090+ Say Y to enable support for the battery on the OLPC laptop.
1091+
1092+# drivers below are not in battery2-2.6 tree
1093+
1094+config ADC_BATTERY
1095+ tristate "Generic ADC battery driver"
1096+ depends on ADC && POWER_SUPPLY
1097+ help
1098+ Say Y here to enable support for battery monitoring using generic ADC device.
1099+
1100+config IPAQ_MICRO_BATTERY
1101+ tristate "HP iPAQ Micro ASIC battery driver"
1102+ depends on IPAQ_MICRO && POWER_SUPPLY
1103+ help
1104+ Choose this option if you want to monitor battery status on
1105+ Compaq/HP iPAQ h3100 h3600
1106+
1107+config MCP_UCB1x00_SIMPAD_BATTERY
1108+ tristate "SIMpad Battery Reading Support"
1109+ depends on MCP_UCB1x00 && POWER_SUPPLY
1110+
1111+endif # POWER_SUPPLY
1112Index: linux-2.6.22/drivers/power/Makefile
1113===================================================================
1114--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1115+++ linux-2.6.22/drivers/power/Makefile 2007-08-23 12:13:52.000000000 +0200
1116@@ -0,0 +1,28 @@
1117+power_supply-objs := power_supply_core.o
1118+
1119+ifeq ($(CONFIG_SYSFS),y)
1120+power_supply-objs += power_supply_sysfs.o
1121+endif
1122+
1123+ifeq ($(CONFIG_LEDS_TRIGGERS),y)
1124+power_supply-objs += power_supply_leds.o
1125+endif
1126+
1127+ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y)
1128+EXTRA_CFLAGS += -DDEBUG
1129+endif
1130+
1131+obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
1132+
1133+obj-$(CONFIG_PDA_POWER) += pda_power.o
1134+obj-$(CONFIG_APM_POWER) += apm_power.o
1135+
1136+obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
1137+obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
1138+obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
1139+
1140+# drivers below are not in battery2-2.6 tree
1141+
1142+obj-$(CONFIG_ADC_BATTERY) += adc_battery.o
1143+obj-$(CONFIG_IPAQ_MICRO_BATTERY) += micro_battery.o
1144+obj-$(CONFIG_MCP_UCB1x00_SIMPAD_BATTERY) += simpad-battery.o
1145Index: linux-2.6.22/drivers/power/micro_battery.c
1146===================================================================
1147--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1148+++ linux-2.6.22/drivers/power/micro_battery.c 2007-08-23 12:25:20.000000000 +0200
1149@@ -0,0 +1,257 @@
1150+/*
1151+ * This program is free software; you can redistribute it and/or modify
1152+ * it under the terms of the GNU General Public License version 2 as
1153+ * published by the Free Software Foundation.
1154+ *
1155+ * h3600 atmel micro companion support, battery subdevice
1156+ * based on previous kernel 2.4 version
1157+ * Author : Alessandro Gardich <gremlin@gremlin.it>
1158+ *
1159+ */
1160+
1161+
1162+#include <linux/module.h>
1163+#include <linux/version.h>
1164+
1165+#include <linux/init.h>
1166+#include <linux/fs.h>
1167+#include <linux/interrupt.h>
1168+#include <linux/sched.h>
1169+#include <linux/pm.h>
1170+#include <linux/sysctl.h>
1171+#include <linux/proc_fs.h>
1172+#include <linux/delay.h>
1173+#include <linux/device.h>
1174+#include <linux/power_supply.h>
1175+#include <linux/platform_device.h>
1176+#include <linux/timer.h>
1177+
1178+#include <asm/arch/hardware.h>
1179+
1180+#include <asm/arch/h3600.h>
1181+#include <asm/arch/SA-1100.h>
1182+
1183+#include <asm/hardware/micro.h>
1184+
1185+#define BATT_PERIOD 10*HZ
1186+
1187+#define H3600_BATT_STATUS_HIGH 0x01
1188+#define H3600_BATT_STATUS_LOW 0x02
1189+#define H3600_BATT_STATUS_CRITICAL 0x04
1190+#define H3600_BATT_STATUS_CHARGING 0x08
1191+#define H3600_BATT_STATUS_CHARGEMAIN 0x10
1192+#define H3600_BATT_STATUS_DEAD 0x20 /* Battery will not charge */
1193+#define H3600_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */
1194+#define H3600_BATT_STATUS_FULL 0x40 /* Battery fully charged (and connected to AC) */
1195+#define H3600_BATT_STATUS_NOBATTERY 0x80
1196+#define H3600_BATT_STATUS_UNKNOWN 0xff
1197+
1198+
1199+//static struct power_supply_dev *micro_battery;
1200+
1201+static micro_private_t *p_micro;
1202+
1203+struct timer_list batt_timer;
1204+
1205+struct {
1206+ int ac;
1207+ int update_time;
1208+ int chemistry;
1209+ int voltage;
1210+ int temperature;
1211+ int flag;
1212+} micro_battery;
1213+
1214+static void micro_battery_receive (int len, unsigned char *data) {
1215+ if (0) {
1216+ printk(KERN_ERR "h3600_battery - AC = %02x\n", data[0]);
1217+ printk(KERN_ERR "h3600_battery - BAT1 chemistry = %02x\n", data[1]);
1218+ printk(KERN_ERR "h3600_battery - BAT1 voltage = %d %02x%02x\n", (data[3]<<8)+data[2], data[2], data[3]);
1219+ printk(KERN_ERR "h3600_battery - BAT1 status = %02x\n", data[4]);
1220+ }
1221+
1222+ micro_battery.ac = data[0];
1223+ micro_battery.chemistry = data[1];
1224+ micro_battery.voltage = ((((unsigned short)data[3]<<8)+data[2]) * 5000L ) * 1000 / 1024;
1225+ micro_battery.flag = data[4];
1226+
1227+ if (len == 9) {
1228+ if (0) {
1229+ printk(KERN_ERR "h3600_battery - BAT2 chemistry = %02x\n", data[5]);
1230+ printk(KERN_ERR "h3600_battery - BAT2 voltage = %d %02x%02x\n", (data[7]<<8)+data[6], data[6], data[7]);
1231+ printk(KERN_ERR "h3600_battery - BAT2 status = %02x\n", data[8]);
1232+ }
1233+ }
1234+}
1235+
1236+static void micro_temperature_receive (int len, unsigned char *data) {
1237+ micro_battery.temperature = ((unsigned short)data[1]<<8)+data[0];
1238+}
1239+
1240+void h3600_battery_read_status(unsigned long data) {
1241+
1242+ if (++data % 2)
1243+ h3600_micro_tx_msg(0x09,0,NULL);
1244+ else
1245+ h3600_micro_tx_msg(0x06,0,NULL);
1246+
1247+ batt_timer.expires += BATT_PERIOD;
1248+ batt_timer.data = data;
1249+
1250+ add_timer(&batt_timer);
1251+}
1252+
1253+int get_capacity(struct power_supply *b) {
1254+ switch (micro_battery.flag) {
1255+ case H3600_BATT_STATUS_HIGH : return 100; break;
1256+ case H3600_BATT_STATUS_LOW : return 50; break;
1257+ case H3600_BATT_STATUS_CRITICAL : return 5; break;
1258+ default: break;
1259+ }
1260+ return 0;
1261+}
1262+
1263+int get_status(struct power_supply *b) {
1264+
1265+ if (micro_battery.flag == H3600_BATT_STATUS_UNKNOWN)
1266+ return POWER_SUPPLY_STATUS_UNKNOWN;
1267+
1268+ if (micro_battery.flag & H3600_BATT_STATUS_FULL)
1269+ return POWER_SUPPLY_STATUS_FULL;
1270+
1271+ if ((micro_battery.flag & H3600_BATT_STATUS_CHARGING) ||
1272+ (micro_battery.flag & H3600_BATT_STATUS_CHARGEMAIN))
1273+ return POWER_SUPPLY_STATUS_CHARGING;
1274+
1275+ return POWER_SUPPLY_STATUS_DISCHARGING;
1276+}
1277+
1278+static int micro_batt_get_property(struct power_supply *b,
1279+ enum power_supply_property psp,
1280+ union power_supply_propval *val)
1281+{
1282+ switch (psp) {
1283+ case POWER_SUPPLY_PROP_STATUS:
1284+ val->intval = get_status(b);
1285+ break;
1286+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
1287+ val->intval = 4700000;
1288+ break;
1289+ case POWER_SUPPLY_PROP_CAPACITY:
1290+ val->intval = get_capacity(b);
1291+ break;
1292+ case POWER_SUPPLY_PROP_TEMP:
1293+ val->intval = micro_battery.temperature;
1294+ break;
1295+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1296+ val->intval = micro_battery.voltage;
1297+ break;
1298+ default:
1299+ return -EINVAL;
1300+ };
1301+
1302+ return 0;
1303+}
1304+
1305+static enum power_supply_property micro_batt_props[] = {
1306+ POWER_SUPPLY_PROP_STATUS,
1307+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1308+ POWER_SUPPLY_PROP_CAPACITY,
1309+ POWER_SUPPLY_PROP_TEMP,
1310+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
1311+};
1312+
1313+static struct power_supply h3600_battery = {
1314+ .name = "main-battery",
1315+ .properties = micro_batt_props,
1316+ .num_properties = ARRAY_SIZE(micro_batt_props),
1317+ .get_property = micro_batt_get_property,
1318+ .use_for_apm = 1,
1319+};
1320+
1321+static int micro_batt_probe (struct platform_device *pdev)
1322+{
1323+ if (1) printk(KERN_ERR "micro battery probe : begin\n");
1324+
1325+ power_supply_register(&pdev->dev, &h3600_battery);
1326+
1327+ { /*--- callback ---*/
1328+ p_micro = platform_get_drvdata(pdev);
1329+ spin_lock(p_micro->lock);
1330+ p_micro->h_batt = micro_battery_receive;
1331+ p_micro->h_temp = micro_temperature_receive;
1332+ spin_unlock(p_micro->lock);
1333+ }
1334+
1335+ { /*--- timer ---*/
1336+ init_timer(&batt_timer);
1337+ batt_timer.expires = jiffies + BATT_PERIOD;
1338+ batt_timer.data = 0;
1339+ batt_timer.function = h3600_battery_read_status;
1340+
1341+ add_timer(&batt_timer);
1342+ }
1343+
1344+ if (1) printk(KERN_ERR "micro battery probe : end\n");
1345+ return 0;
1346+}
1347+
1348+static int micro_batt_remove (struct platform_device *pdev)
1349+{
1350+ power_supply_unregister(&h3600_battery);
1351+ { /*--- callback ---*/
1352+ init_timer(&batt_timer);
1353+ p_micro->h_batt = NULL;
1354+ p_micro->h_temp = NULL;
1355+ spin_unlock(p_micro->lock);
1356+ }
1357+ { /*--- timer ---*/
1358+ del_timer_sync(&batt_timer);
1359+ }
1360+ return 0;
1361+}
1362+
1363+static int micro_batt_suspend ( struct platform_device *pdev, pm_message_t state)
1364+{
1365+ { /*--- timer ---*/
1366+ del_timer(&batt_timer);
1367+ }
1368+ return 0;
1369+}
1370+
1371+static int micro_batt_resume ( struct platform_device *pdev)
1372+{
1373+ { /*--- timer ---*/
1374+ add_timer(&batt_timer);
1375+ }
1376+ return 0;
1377+}
1378+
1379+struct platform_driver micro_batt_device_driver = {
1380+ .driver = {
1381+ .name = "h3600-micro-battery",
1382+ },
1383+ .probe = micro_batt_probe,
1384+ .remove = micro_batt_remove,
1385+ .suspend = micro_batt_suspend,
1386+ .resume = micro_batt_resume,
1387+};
1388+
1389+static int micro_batt_init (void)
1390+{
1391+ return platform_driver_register(&micro_batt_device_driver);
1392+}
1393+
1394+static void micro_batt_cleanup (void)
1395+{
1396+ platform_driver_unregister (&micro_batt_device_driver);
1397+}
1398+
1399+module_init (micro_batt_init);
1400+module_exit (micro_batt_cleanup);
1401+
1402+MODULE_LICENSE("GPL");
1403+MODULE_AUTHOR("gremlin.it");
1404+MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery");
1405+
1406+
1407Index: linux-2.6.22/drivers/power/olpc_battery.c
1408===================================================================
1409--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1410+++ linux-2.6.22/drivers/power/olpc_battery.c 2007-08-23 12:13:52.000000000 +0200
1411@@ -0,0 +1,302 @@
1412+/*
1413+ * Battery driver for One Laptop Per Child board.
1414+ *
1415+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
1416+ *
1417+ * This program is free software; you can redistribute it and/or modify
1418+ * it under the terms of the GNU General Public License version 2 as
1419+ * published by the Free Software Foundation.
1420+ */
1421+
1422+#include <linux/module.h>
1423+#include <linux/err.h>
1424+#include <linux/platform_device.h>
1425+#include <linux/power_supply.h>
1426+#include <linux/jiffies.h>
1427+#include <linux/sched.h>
1428+#include <asm/io.h>
1429+
1430+#define wBAT_VOLTAGE 0xf900 /* *9.76/32, mV */
1431+#define wBAT_CURRENT 0xf902 /* *15.625/120, mA */
1432+#define wBAT_TEMP 0xf906 /* *256/1000, °C */
1433+#define wAMB_TEMP 0xf908 /* *256/1000, °C */
1434+#define SOC 0xf910 /* percentage */
1435+#define sMBAT_STATUS 0xfaa4
1436+#define sBAT_PRESENT 1
1437+#define sBAT_FULL 2
1438+#define sBAT_DESTROY 4 /* what is this exactly? */
1439+#define sBAT_LOW 32
1440+#define sBAT_DISCHG 64
1441+#define sMCHARGE_STATUS 0xfaa5
1442+#define sBAT_CHARGE 1
1443+#define sBAT_OVERTEMP 4
1444+#define sBAT_NiMH 8
1445+#define sPOWER_FLAG 0xfa40
1446+#define ADAPTER_IN 1
1447+
1448+/*********************************************************************
1449+ * EC locking and access
1450+ *********************************************************************/
1451+
1452+static int lock_ec(void)
1453+{
1454+ unsigned long timeo = jiffies + HZ / 20;
1455+
1456+ while (1) {
1457+ unsigned char lock = inb(0x6c) & 0x80;
1458+ if (!lock)
1459+ return 0;
1460+ if (time_after(jiffies, timeo)) {
1461+ printk(KERN_ERR "olpc_battery: failed to lock EC for "
1462+ "battery access\n");
1463+ return 1;
1464+ }
1465+ yield();
1466+ }
1467+}
1468+
1469+static void unlock_ec(void)
1470+{
1471+ outb(0xff, 0x6c);
1472+ return;
1473+}
1474+
1475+static unsigned char read_ec_byte(unsigned short adr)
1476+{
1477+ outb(adr >> 8, 0x381);
1478+ outb(adr, 0x382);
1479+ return inb(0x383);
1480+}
1481+
1482+static unsigned short read_ec_word(unsigned short adr)
1483+{
1484+ return (read_ec_byte(adr) << 8) | read_ec_byte(adr + 1);
1485+}
1486+
1487+/*********************************************************************
1488+ * Power
1489+ *********************************************************************/
1490+
1491+static int olpc_ac_get_prop(struct power_supply *psy,
1492+ enum power_supply_property psp,
1493+ union power_supply_propval *val)
1494+{
1495+ int ret = 0;
1496+
1497+ if (lock_ec())
1498+ return -EIO;
1499+
1500+ switch (psp) {
1501+ case POWER_SUPPLY_PROP_ONLINE:
1502+ if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
1503+ ret = -ENODEV;
1504+ goto out;
1505+ }
1506+ val->intval = !!(read_ec_byte(sPOWER_FLAG) & ADAPTER_IN);
1507+ break;
1508+ default:
1509+ ret = -EINVAL;
1510+ break;
1511+ }
1512+out:
1513+ unlock_ec();
1514+ return ret;
1515+}
1516+
1517+static enum power_supply_property olpc_ac_props[] = {
1518+ POWER_SUPPLY_PROP_ONLINE,
1519+};
1520+
1521+static struct power_supply olpc_ac = {
1522+ .name = "olpc-ac",
1523+ .type = POWER_SUPPLY_TYPE_MAINS,
1524+ .properties = olpc_ac_props,
1525+ .num_properties = ARRAY_SIZE(olpc_ac_props),
1526+ .get_property = olpc_ac_get_prop,
1527+};
1528+
1529+/*********************************************************************
1530+ * Battery properties
1531+ *********************************************************************/
1532+
1533+static int olpc_bat_get_property(struct power_supply *psy,
1534+ enum power_supply_property psp,
1535+ union power_supply_propval *val)
1536+{
1537+ int ret = 0;
1538+
1539+ if (lock_ec())
1540+ return -EIO;
1541+
1542+ switch (psp) {
1543+ case POWER_SUPPLY_PROP_STATUS:
1544+ {
1545+ int status = POWER_SUPPLY_STATUS_UNKNOWN;
1546+
1547+ val->intval = read_ec_byte(sMBAT_STATUS);
1548+
1549+ if (!(val->intval & sBAT_PRESENT)) {
1550+ ret = -ENODEV;
1551+ goto out;
1552+ }
1553+
1554+ if (val->intval & sBAT_DISCHG)
1555+ status = POWER_SUPPLY_STATUS_DISCHARGING;
1556+ else if (val->intval & sBAT_FULL)
1557+ status = POWER_SUPPLY_STATUS_FULL;
1558+
1559+ val->intval = read_ec_byte(sMCHARGE_STATUS);
1560+ if (val->intval & sBAT_CHARGE)
1561+ status = POWER_SUPPLY_STATUS_CHARGING;
1562+
1563+ val->intval = status;
1564+ break;
1565+ }
1566+ case POWER_SUPPLY_PROP_PRESENT:
1567+ val->intval = !!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT);
1568+ break;
1569+ case POWER_SUPPLY_PROP_HEALTH:
1570+ val->intval = read_ec_byte(sMCHARGE_STATUS);
1571+ if (val->intval & sBAT_OVERTEMP)
1572+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
1573+ else
1574+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
1575+ break;
1576+ case POWER_SUPPLY_PROP_TECHNOLOGY:
1577+ val->intval = read_ec_byte(sMCHARGE_STATUS);
1578+ if (val->intval & sBAT_NiMH)
1579+ val->intval = POWER_SUPPLY_TECHNOLOGY_NIMH;
1580+ else
1581+ val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
1582+ break;
1583+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
1584+ val->intval = read_ec_byte(wBAT_VOLTAGE) * 9760L / 32;
1585+ break;
1586+ case POWER_SUPPLY_PROP_CURRENT_AVG:
1587+ val->intval = read_ec_byte(wBAT_CURRENT) * 15625L / 120;
1588+ break;
1589+ case POWER_SUPPLY_PROP_CAPACITY:
1590+ val->intval = read_ec_byte(SOC);
1591+ break;
1592+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
1593+ val->intval = read_ec_byte(sMBAT_STATUS);
1594+ if (val->intval & sBAT_FULL)
1595+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
1596+ else if (val->intval & sBAT_LOW)
1597+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
1598+ else
1599+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
1600+ break;
1601+ case POWER_SUPPLY_PROP_TEMP:
1602+ val->intval = read_ec_byte(wBAT_TEMP) * 256 / 100;
1603+ break;
1604+ case POWER_SUPPLY_PROP_TEMP_AMBIENT:
1605+ val->intval = read_ec_byte(wAMB_TEMP) * 256 / 100;
1606+ break;
1607+ default:
1608+ ret = -EINVAL;
1609+ break;
1610+ }
1611+
1612+out:
1613+ unlock_ec();
1614+ return ret;
1615+}
1616+
1617+static enum power_supply_property olpc_bat_props[] = {
1618+ POWER_SUPPLY_PROP_STATUS,
1619+ POWER_SUPPLY_PROP_PRESENT,
1620+ POWER_SUPPLY_PROP_HEALTH,
1621+ POWER_SUPPLY_PROP_TECHNOLOGY,
1622+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
1623+ POWER_SUPPLY_PROP_CURRENT_AVG,
1624+ POWER_SUPPLY_PROP_CAPACITY,
1625+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
1626+ POWER_SUPPLY_PROP_TEMP,
1627+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
1628+};
1629+
1630+/*********************************************************************
1631+ * Initialisation
1632+ *********************************************************************/
1633+
1634+static struct platform_device *bat_pdev;
1635+
1636+static struct power_supply olpc_bat = {
1637+ .properties = olpc_bat_props,
1638+ .num_properties = ARRAY_SIZE(olpc_bat_props),
1639+ .get_property = olpc_bat_get_property,
1640+ .use_for_apm = 1,
1641+};
1642+
1643+static int __init olpc_bat_init(void)
1644+{
1645+ int ret = 0;
1646+ unsigned short tmp;
1647+
1648+ if (!request_region(0x380, 4, "olpc-battery")) {
1649+ ret = -EIO;
1650+ goto region_failed;
1651+ }
1652+
1653+ if (lock_ec()) {
1654+ ret = -EIO;
1655+ goto lock_failed;
1656+ }
1657+
1658+ tmp = read_ec_word(0xfe92);
1659+ unlock_ec();
1660+
1661+ if (tmp != 0x380) {
1662+ /* Doesn't look like OLPC EC */
1663+ ret = -ENODEV;
1664+ goto not_olpc_ec;
1665+ }
1666+
1667+ bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
1668+ if (IS_ERR(bat_pdev)) {
1669+ ret = PTR_ERR(bat_pdev);
1670+ goto pdev_failed;
1671+ }
1672+
1673+ ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
1674+ if (ret)
1675+ goto ac_failed;
1676+
1677+ olpc_bat.name = bat_pdev->name;
1678+
1679+ ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
1680+ if (ret)
1681+ goto battery_failed;
1682+
1683+ goto success;
1684+
1685+battery_failed:
1686+ power_supply_unregister(&olpc_ac);
1687+ac_failed:
1688+ platform_device_unregister(bat_pdev);
1689+pdev_failed:
1690+not_olpc_ec:
1691+lock_failed:
1692+ release_region(0x380, 4);
1693+region_failed:
1694+success:
1695+ return ret;
1696+}
1697+
1698+static void __exit olpc_bat_exit(void)
1699+{
1700+ power_supply_unregister(&olpc_bat);
1701+ power_supply_unregister(&olpc_ac);
1702+ platform_device_unregister(bat_pdev);
1703+ release_region(0x380, 4);
1704+ return;
1705+}
1706+
1707+module_init(olpc_bat_init);
1708+module_exit(olpc_bat_exit);
1709+
1710+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1711+MODULE_LICENSE("GPL");
1712+MODULE_DESCRIPTION("Battery driver for One Laptop Per Child "
1713+ "($100 laptop) board.");
1714Index: linux-2.6.22/drivers/power/pda_power.c
1715===================================================================
1716--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1717+++ linux-2.6.22/drivers/power/pda_power.c 2007-08-23 12:13:52.000000000 +0200
1718@@ -0,0 +1,263 @@
1719+/*
1720+ * Common power driver for PDAs and phones with one or two external
1721+ * power supplies (AC/USB) connected to main and backup batteries,
1722+ * and optional builtin charger.
1723+ *
1724+ * Copyright 2007 Anton Vorontsov <cbou@mail.ru>
1725+ *
1726+ * This program is free software; you can redistribute it and/or modify
1727+ * it under the terms of the GNU General Public License version 2 as
1728+ * published by the Free Software Foundation.
1729+ */
1730+
1731+#include <linux/module.h>
1732+#include <linux/platform_device.h>
1733+#include <linux/interrupt.h>
1734+#include <linux/power_supply.h>
1735+#include <linux/pda_power.h>
1736+#include <linux/timer.h>
1737+#include <linux/jiffies.h>
1738+
1739+static inline unsigned int get_irq_flags(struct resource *res)
1740+{
1741+ unsigned int flags = IRQF_DISABLED | IRQF_SHARED;
1742+
1743+ flags |= res->flags & IRQF_TRIGGER_MASK;
1744+
1745+ return flags;
1746+}
1747+
1748+static struct device *dev;
1749+static struct pda_power_pdata *pdata;
1750+static struct resource *ac_irq, *usb_irq;
1751+static struct timer_list charger_timer;
1752+static struct timer_list supply_timer;
1753+
1754+static int pda_power_get_property(struct power_supply *psy,
1755+ enum power_supply_property psp,
1756+ union power_supply_propval *val)
1757+{
1758+ switch (psp) {
1759+ case POWER_SUPPLY_PROP_ONLINE:
1760+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
1761+ val->intval = pdata->is_ac_online ?
1762+ pdata->is_ac_online() : 0;
1763+ else
1764+ val->intval = pdata->is_usb_online ?
1765+ pdata->is_usb_online() : 0;
1766+ break;
1767+ default:
1768+ return -EINVAL;
1769+ }
1770+ return 0;
1771+}
1772+
1773+static enum power_supply_property pda_power_props[] = {
1774+ POWER_SUPPLY_PROP_ONLINE,
1775+};
1776+
1777+static char *pda_power_supplied_to[] = {
1778+ "main-battery",
1779+ "backup-battery",
1780+};
1781+
1782+static struct power_supply pda_power_supplies[] = {
1783+ {
1784+ .name = "ac",
1785+ .type = POWER_SUPPLY_TYPE_MAINS,
1786+ .supplied_to = pda_power_supplied_to,
1787+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
1788+ .properties = pda_power_props,
1789+ .num_properties = ARRAY_SIZE(pda_power_props),
1790+ .get_property = pda_power_get_property,
1791+ },
1792+ {
1793+ .name = "usb",
1794+ .type = POWER_SUPPLY_TYPE_USB,
1795+ .supplied_to = pda_power_supplied_to,
1796+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
1797+ .properties = pda_power_props,
1798+ .num_properties = ARRAY_SIZE(pda_power_props),
1799+ .get_property = pda_power_get_property,
1800+ },
1801+};
1802+
1803+static void update_charger(void)
1804+{
1805+ if (!pdata->set_charge)
1806+ return;
1807+
1808+ if (pdata->is_ac_online && pdata->is_ac_online()) {
1809+ dev_dbg(dev, "charger on (AC)\n");
1810+ pdata->set_charge(PDA_POWER_CHARGE_AC);
1811+ }
1812+ else if (pdata->is_usb_online && pdata->is_usb_online()) {
1813+ dev_dbg(dev, "charger on (USB)\n");
1814+ pdata->set_charge(PDA_POWER_CHARGE_USB);
1815+ }
1816+ else {
1817+ dev_dbg(dev, "charger off\n");
1818+ pdata->set_charge(0);
1819+ }
1820+
1821+ return;
1822+}
1823+
1824+static void supply_timer_func(unsigned long irq)
1825+{
1826+ if (ac_irq && irq == ac_irq->start)
1827+ power_supply_changed(&pda_power_supplies[0]);
1828+ else if (usb_irq && irq == usb_irq->start)
1829+ power_supply_changed(&pda_power_supplies[1]);
1830+ return;
1831+}
1832+
1833+static void charger_timer_func(unsigned long irq)
1834+{
1835+ update_charger();
1836+
1837+ /* Okay, charger set. Now wait a bit before notifying supplicants,
1838+ * charge power should stabilize. */
1839+ supply_timer.data = irq;
1840+ mod_timer(&supply_timer,
1841+ jiffies + msecs_to_jiffies(pdata->wait_for_charger));
1842+ return;
1843+}
1844+
1845+static irqreturn_t power_changed_isr(int irq, void *unused)
1846+{
1847+ /* Wait a bit before reading ac/usb line status and setting charger,
1848+ * because ac/usb status readings may lag from irq. */
1849+ charger_timer.data = irq;
1850+ mod_timer(&charger_timer,
1851+ jiffies + msecs_to_jiffies(pdata->wait_for_status));
1852+ return IRQ_HANDLED;
1853+}
1854+
1855+static int pda_power_probe(struct platform_device *pdev)
1856+{
1857+ int ret = 0;
1858+
1859+ dev = &pdev->dev;
1860+
1861+ if (pdev->id != -1) {
1862+ dev_err(dev, "it's meaningless to register several "
1863+ "pda_powers, use id = -1\n");
1864+ ret = -EINVAL;
1865+ goto wrongid;
1866+ }
1867+
1868+ pdata = pdev->dev.platform_data;
1869+
1870+ update_charger();
1871+
1872+ if (!pdata->wait_for_status)
1873+ pdata->wait_for_status = 500;
1874+
1875+ if (!pdata->wait_for_charger)
1876+ pdata->wait_for_charger = 500;
1877+
1878+ setup_timer(&charger_timer, charger_timer_func, 0);
1879+ setup_timer(&supply_timer, supply_timer_func, 0);
1880+
1881+ ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
1882+ usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
1883+ if (!ac_irq && !usb_irq) {
1884+ dev_err(dev, "no ac/usb irq specified\n");
1885+ ret = -ENODEV;
1886+ goto noirqs;
1887+ }
1888+
1889+ if (pdata->supplied_to) {
1890+ pda_power_supplies[0].supplied_to = pdata->supplied_to;
1891+ pda_power_supplies[1].supplied_to = pdata->supplied_to;
1892+ pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
1893+ pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
1894+ }
1895+
1896+ ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
1897+ if (ret) {
1898+ dev_err(dev, "failed to register %s power supply\n",
1899+ pda_power_supplies[0].name);
1900+ goto supply0_failed;
1901+ }
1902+
1903+ ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
1904+ if (ret) {
1905+ dev_err(dev, "failed to register %s power supply\n",
1906+ pda_power_supplies[1].name);
1907+ goto supply1_failed;
1908+ }
1909+
1910+ if (ac_irq) {
1911+ ret = request_irq(ac_irq->start, power_changed_isr,
1912+ get_irq_flags(ac_irq), ac_irq->name,
1913+ &pda_power_supplies[0]);
1914+ if (ret) {
1915+ dev_err(dev, "request ac irq failed\n");
1916+ goto ac_irq_failed;
1917+ }
1918+ }
1919+
1920+ if (usb_irq) {
1921+ ret = request_irq(usb_irq->start, power_changed_isr,
1922+ get_irq_flags(usb_irq), usb_irq->name,
1923+ &pda_power_supplies[1]);
1924+ if (ret) {
1925+ dev_err(dev, "request usb irq failed\n");
1926+ goto usb_irq_failed;
1927+ }
1928+ }
1929+
1930+ goto success;
1931+
1932+usb_irq_failed:
1933+ if (ac_irq)
1934+ free_irq(ac_irq->start, &pda_power_supplies[0]);
1935+ac_irq_failed:
1936+ power_supply_unregister(&pda_power_supplies[1]);
1937+supply1_failed:
1938+ power_supply_unregister(&pda_power_supplies[0]);
1939+supply0_failed:
1940+noirqs:
1941+wrongid:
1942+success:
1943+ return ret;
1944+}
1945+
1946+static int pda_power_remove(struct platform_device *pdev)
1947+{
1948+ if (usb_irq)
1949+ free_irq(usb_irq->start, &pda_power_supplies[1]);
1950+ if (ac_irq)
1951+ free_irq(ac_irq->start, &pda_power_supplies[0]);
1952+ del_timer_sync(&charger_timer);
1953+ del_timer_sync(&supply_timer);
1954+ power_supply_unregister(&pda_power_supplies[1]);
1955+ power_supply_unregister(&pda_power_supplies[0]);
1956+ return 0;
1957+}
1958+
1959+static struct platform_driver pda_power_pdrv = {
1960+ .driver = {
1961+ .name = "pda-power",
1962+ },
1963+ .probe = pda_power_probe,
1964+ .remove = pda_power_remove,
1965+};
1966+
1967+static int __init pda_power_init(void)
1968+{
1969+ return platform_driver_register(&pda_power_pdrv);
1970+}
1971+
1972+static void __exit pda_power_exit(void)
1973+{
1974+ platform_driver_unregister(&pda_power_pdrv);
1975+ return;
1976+}
1977+
1978+module_init(pda_power_init);
1979+module_exit(pda_power_exit);
1980+MODULE_LICENSE("GPL");
1981+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
1982Index: linux-2.6.22/drivers/power/pmu_battery.c
1983===================================================================
1984--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1985+++ linux-2.6.22/drivers/power/pmu_battery.c 2007-08-23 12:13:52.000000000 +0200
1986@@ -0,0 +1,215 @@
1987+/*
1988+ * Battery class driver for Apple PMU
1989+ *
1990+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
1991+ *
1992+ * This program is free software; you can redistribute it and/or modify
1993+ * it under the terms of the GNU General Public License version 2 as
1994+ * published by the Free Software Foundation.
1995+ */
1996+
1997+#include <linux/module.h>
1998+#include <linux/platform_device.h>
1999+#include <linux/err.h>
2000+#include <linux/power_supply.h>
2001+#include <linux/adb.h>
2002+#include <linux/pmu.h>
2003+
2004+static struct pmu_battery_dev {
2005+ struct power_supply bat;
2006+ struct pmu_battery_info *pbi;
2007+ char name[16];
2008+ int propval;
2009+} *pbats[PMU_MAX_BATTERIES];
2010+
2011+#define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
2012+
2013+/*********************************************************************
2014+ * Power
2015+ *********************************************************************/
2016+
2017+static int pmu_get_ac_prop(struct power_supply *psy,
2018+ enum power_supply_property psp,
2019+ union power_supply_propval *val)
2020+{
2021+ switch (psp) {
2022+ case POWER_SUPPLY_PROP_ONLINE:
2023+ val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
2024+ (pmu_battery_count == 0);
2025+ break;
2026+ default:
2027+ return -EINVAL;
2028+ }
2029+
2030+ return 0;
2031+}
2032+
2033+static enum power_supply_property pmu_ac_props[] = {
2034+ POWER_SUPPLY_PROP_ONLINE,
2035+};
2036+
2037+static struct power_supply pmu_ac = {
2038+ .name = "pmu-ac",
2039+ .type = POWER_SUPPLY_TYPE_MAINS,
2040+ .properties = pmu_ac_props,
2041+ .num_properties = ARRAY_SIZE(pmu_ac_props),
2042+ .get_property = pmu_get_ac_prop,
2043+};
2044+
2045+/*********************************************************************
2046+ * Battery properties
2047+ *********************************************************************/
2048+
2049+static char *pmu_batt_types[] = {
2050+ "Smart", "Comet", "Hooper", "Unknown"
2051+};
2052+
2053+static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
2054+{
2055+ switch (pbi->flags & PMU_BATT_TYPE_MASK) {
2056+ case PMU_BATT_TYPE_SMART:
2057+ return pmu_batt_types[0];
2058+ case PMU_BATT_TYPE_COMET:
2059+ return pmu_batt_types[1];
2060+ case PMU_BATT_TYPE_HOOPER:
2061+ return pmu_batt_types[2];
2062+ default: break;
2063+ }
2064+ return pmu_batt_types[3];
2065+}
2066+
2067+static int pmu_bat_get_property(struct power_supply *psy,
2068+ enum power_supply_property psp,
2069+ union power_supply_propval *val)
2070+{
2071+ struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
2072+ struct pmu_battery_info *pbi = pbat->pbi;
2073+
2074+ switch (psp) {
2075+ case POWER_SUPPLY_PROP_STATUS:
2076+ if (pbi->flags & PMU_BATT_CHARGING)
2077+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
2078+ else
2079+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
2080+ break;
2081+ case POWER_SUPPLY_PROP_PRESENT:
2082+ val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
2083+ break;
2084+ case POWER_SUPPLY_PROP_MODEL_NAME:
2085+ val->strval = pmu_bat_get_model_name(pbi);
2086+ break;
2087+ case POWER_SUPPLY_PROP_ENERGY_AVG:
2088+ val->intval = pbi->charge * 1000; /* mWh -> µWh */
2089+ break;
2090+ case POWER_SUPPLY_PROP_ENERGY_FULL:
2091+ val->intval = pbi->max_charge * 1000; /* mWh -> µWh */
2092+ break;
2093+ case POWER_SUPPLY_PROP_CURRENT_AVG:
2094+ val->intval = pbi->amperage * 1000; /* mA -> µA */
2095+ break;
2096+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
2097+ val->intval = pbi->voltage * 1000; /* mV -> µV */
2098+ break;
2099+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
2100+ val->intval = pbi->time_remaining;
2101+ break;
2102+ default:
2103+ return -EINVAL;
2104+ }
2105+
2106+ return 0;
2107+}
2108+
2109+static enum power_supply_property pmu_bat_props[] = {
2110+ POWER_SUPPLY_PROP_STATUS,
2111+ POWER_SUPPLY_PROP_PRESENT,
2112+ POWER_SUPPLY_PROP_MODEL_NAME,
2113+ POWER_SUPPLY_PROP_ENERGY_AVG,
2114+ POWER_SUPPLY_PROP_ENERGY_FULL,
2115+ POWER_SUPPLY_PROP_CURRENT_AVG,
2116+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
2117+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
2118+};
2119+
2120+/*********************************************************************
2121+ * Initialisation
2122+ *********************************************************************/
2123+
2124+static struct platform_device *bat_pdev;
2125+
2126+static int __init pmu_bat_init(void)
2127+{
2128+ int ret;
2129+ int i;
2130+
2131+ bat_pdev = platform_device_register_simple("pmu-battery",
2132+ 0, NULL, 0);
2133+ if (IS_ERR(bat_pdev)) {
2134+ ret = PTR_ERR(bat_pdev);
2135+ goto pdev_register_failed;
2136+ }
2137+
2138+ ret = power_supply_register(&bat_pdev->dev, &pmu_ac);
2139+ if (ret)
2140+ goto ac_register_failed;
2141+
2142+ for (i = 0; i < pmu_battery_count; i++) {
2143+ struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
2144+ GFP_KERNEL);
2145+ if (!pbat)
2146+ break;
2147+
2148+ sprintf(pbat->name, "PMU battery %d", i);
2149+ pbat->bat.name = pbat->name;
2150+ pbat->bat.properties = pmu_bat_props;
2151+ pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
2152+ pbat->bat.get_property = pmu_bat_get_property;
2153+ pbat->pbi = &pmu_batteries[i];
2154+
2155+ ret = power_supply_register(&bat_pdev->dev, &pbat->bat);
2156+ if (ret) {
2157+ kfree(pbat);
2158+ goto battery_register_failed;
2159+ }
2160+ pbats[i] = pbat;
2161+ }
2162+
2163+ goto success;
2164+
2165+battery_register_failed:
2166+ while (i--) {
2167+ if (!pbats[i])
2168+ continue;
2169+ power_supply_unregister(&pbats[i]->bat);
2170+ kfree(pbats[i]);
2171+ }
2172+ power_supply_unregister(&pmu_ac);
2173+ac_register_failed:
2174+ platform_device_unregister(bat_pdev);
2175+pdev_register_failed:
2176+success:
2177+ return ret;
2178+}
2179+
2180+static void __exit pmu_bat_exit(void)
2181+{
2182+ int i;
2183+
2184+ for (i = 0; i < PMU_MAX_BATTERIES; i++) {
2185+ if (!pbats[i])
2186+ continue;
2187+ power_supply_unregister(&pbats[i]->bat);
2188+ kfree(pbats[i]);
2189+ }
2190+ power_supply_unregister(&pmu_ac);
2191+ platform_device_unregister(bat_pdev);
2192+
2193+ return;
2194+}
2195+
2196+module_init(pmu_bat_init);
2197+module_exit(pmu_bat_exit);
2198+
2199+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
2200+MODULE_LICENSE("GPL");
2201+MODULE_DESCRIPTION("PMU battery driver");
2202Index: linux-2.6.22/drivers/power/power_supply_core.c
2203===================================================================
2204--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2205+++ linux-2.6.22/drivers/power/power_supply_core.c 2007-08-23 12:13:52.000000000 +0200
2206@@ -0,0 +1,168 @@
2207+/*
2208+ * Universal power supply monitor class
2209+ *
2210+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2211+ * Copyright (c) 2004 Szabolcs Gyurko
2212+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2213+ *
2214+ * Modified: 2004, Oct Szabolcs Gyurko
2215+ *
2216+ * You may use this code as per GPL version 2
2217+ */
2218+
2219+#include <linux/module.h>
2220+#include <linux/types.h>
2221+#include <linux/init.h>
2222+#include <linux/device.h>
2223+#include <linux/err.h>
2224+#include <linux/power_supply.h>
2225+#include "power_supply.h"
2226+
2227+struct class *power_supply_class;
2228+
2229+static void power_supply_changed_work(struct work_struct *work)
2230+{
2231+ struct power_supply *psy = container_of(work, struct power_supply,
2232+ changed_work);
2233+ int i;
2234+
2235+ dev_dbg(psy->dev, "%s\n", __FUNCTION__);
2236+
2237+ for (i = 0; i < psy->num_supplicants; i++) {
2238+ struct device *dev;
2239+
2240+ down(&power_supply_class->sem);
2241+ list_for_each_entry(dev, &power_supply_class->devices, node) {
2242+ struct power_supply *pst = dev_get_drvdata(dev);
2243+
2244+ if (!strcmp(psy->supplied_to[i], pst->name)) {
2245+ if (pst->external_power_changed)
2246+ pst->external_power_changed(pst);
2247+ }
2248+ }
2249+ up(&power_supply_class->sem);
2250+ }
2251+
2252+ power_supply_update_leds(psy);
2253+
2254+ kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
2255+
2256+ return;
2257+}
2258+
2259+void power_supply_changed(struct power_supply *psy)
2260+{
2261+ dev_dbg(psy->dev, "%s\n", __FUNCTION__);
2262+
2263+ schedule_work(&psy->changed_work);
2264+
2265+ return;
2266+}
2267+
2268+int power_supply_am_i_supplied(struct power_supply *psy)
2269+{
2270+ union power_supply_propval ret = {0,};
2271+ struct device *dev;
2272+
2273+ down(&power_supply_class->sem);
2274+ list_for_each_entry(dev, &power_supply_class->devices, node) {
2275+ struct power_supply *epsy = dev_get_drvdata(dev);
2276+ int i;
2277+
2278+ for (i = 0; i < epsy->num_supplicants; i++) {
2279+ if (!strcmp(epsy->supplied_to[i], psy->name)) {
2280+ if (epsy->get_property(epsy,
2281+ POWER_SUPPLY_PROP_ONLINE, &ret))
2282+ continue;
2283+ if (ret.intval)
2284+ goto out;
2285+ }
2286+ }
2287+ }
2288+out:
2289+ up(&power_supply_class->sem);
2290+
2291+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
2292+
2293+ return ret.intval;
2294+}
2295+
2296+int power_supply_register(struct device *parent, struct power_supply *psy)
2297+{
2298+ int rc = 0;
2299+
2300+ psy->dev = device_create(power_supply_class, parent, 0,
2301+ "%s", psy->name);
2302+ if (IS_ERR(psy->dev)) {
2303+ rc = PTR_ERR(psy->dev);
2304+ goto dev_create_failed;
2305+ }
2306+
2307+ dev_set_drvdata(psy->dev, psy);
2308+
2309+ INIT_WORK(&psy->changed_work, power_supply_changed_work);
2310+
2311+ rc = power_supply_create_attrs(psy);
2312+ if (rc)
2313+ goto create_attrs_failed;
2314+
2315+ rc = power_supply_create_triggers(psy);
2316+ if (rc)
2317+ goto create_triggers_failed;
2318+
2319+ power_supply_changed(psy);
2320+
2321+ goto success;
2322+
2323+create_triggers_failed:
2324+ power_supply_remove_attrs(psy);
2325+create_attrs_failed:
2326+ device_unregister(psy->dev);
2327+dev_create_failed:
2328+success:
2329+ return rc;
2330+}
2331+
2332+void power_supply_unregister(struct power_supply *psy)
2333+{
2334+ flush_scheduled_work();
2335+ power_supply_remove_triggers(psy);
2336+ power_supply_remove_attrs(psy);
2337+ device_unregister(psy->dev);
2338+ return;
2339+}
2340+
2341+static int __init power_supply_class_init(void)
2342+{
2343+ power_supply_class = class_create(THIS_MODULE, "power_supply");
2344+
2345+ if (IS_ERR(power_supply_class))
2346+ return PTR_ERR(power_supply_class);
2347+
2348+ power_supply_class->dev_uevent = power_supply_uevent;
2349+
2350+ return 0;
2351+}
2352+
2353+static void __exit power_supply_class_exit(void)
2354+{
2355+ class_destroy(power_supply_class);
2356+ return;
2357+}
2358+
2359+EXPORT_SYMBOL_GPL(power_supply_changed);
2360+EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
2361+EXPORT_SYMBOL_GPL(power_supply_register);
2362+EXPORT_SYMBOL_GPL(power_supply_unregister);
2363+
2364+/* exported for the APM Power driver, APM emulation */
2365+EXPORT_SYMBOL_GPL(power_supply_class);
2366+
2367+subsys_initcall(power_supply_class_init);
2368+module_exit(power_supply_class_exit);
2369+
2370+MODULE_DESCRIPTION("Universal power supply monitor class");
2371+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
2372+ "Szabolcs Gyurko, "
2373+ "Anton Vorontsov <cbou@mail.ru>");
2374+MODULE_LICENSE("GPL");
2375Index: linux-2.6.22/drivers/power/power_supply.h
2376===================================================================
2377--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2378+++ linux-2.6.22/drivers/power/power_supply.h 2007-08-23 12:13:52.000000000 +0200
2379@@ -0,0 +1,42 @@
2380+/*
2381+ * Functions private to power supply class
2382+ *
2383+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2384+ * Copyright (c) 2004 Szabolcs Gyurko
2385+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2386+ *
2387+ * Modified: 2004, Oct Szabolcs Gyurko
2388+ *
2389+ * You may use this code as per GPL version 2
2390+ */
2391+
2392+#ifdef CONFIG_SYSFS
2393+
2394+extern int power_supply_create_attrs(struct power_supply *psy);
2395+extern void power_supply_remove_attrs(struct power_supply *psy);
2396+extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
2397+ char *buffer, int buffer_size);
2398+
2399+#else
2400+
2401+static inline int power_supply_create_attrs(struct power_supply *psy)
2402+{ return 0; }
2403+static inline void power_supply_remove_attrs(struct power_supply *psy) {}
2404+#define power_supply_uevent NULL
2405+
2406+#endif /* CONFIG_SYSFS */
2407+
2408+#ifdef CONFIG_LEDS_TRIGGERS
2409+
2410+extern void power_supply_update_leds(struct power_supply *psy);
2411+extern int power_supply_create_triggers(struct power_supply *psy);
2412+extern void power_supply_remove_triggers(struct power_supply *psy);
2413+
2414+#else
2415+
2416+static inline void power_supply_update_leds(struct power_supply *psy) {}
2417+static inline int power_supply_create_triggers(struct power_supply *psy)
2418+{ return 0; }
2419+static inline void power_supply_remove_triggers(struct power_supply *psy) {}
2420+
2421+#endif /* CONFIG_LEDS_TRIGGERS */
2422Index: linux-2.6.22/drivers/power/power_supply_leds.c
2423===================================================================
2424--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2425+++ linux-2.6.22/drivers/power/power_supply_leds.c 2007-08-23 12:13:52.000000000 +0200
2426@@ -0,0 +1,188 @@
2427+/*
2428+ * LEDs triggers for power supply class
2429+ *
2430+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2431+ * Copyright (c) 2004 Szabolcs Gyurko
2432+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2433+ *
2434+ * Modified: 2004, Oct Szabolcs Gyurko
2435+ *
2436+ * You may use this code as per GPL version 2
2437+ */
2438+
2439+#include <linux/power_supply.h>
2440+
2441+/* If we have hwtimer trigger, then use it to blink charging LED */
2442+
2443+#if defined(CONFIG_LEDS_TRIGGER_HWTIMER) || \
2444+ (defined(CONFIG_BATTERY_MODULE) && \
2445+ defined(CONFIG_LEDS_TRIGGER_HWTIMER_MODULE))
2446+ #define led_trigger_register_charging led_trigger_register_hwtimer
2447+ #define led_trigger_unregister_charging led_trigger_unregister_hwtimer
2448+#else
2449+ #define led_trigger_register_charging led_trigger_register_simple
2450+ #define led_trigger_unregister_charging led_trigger_unregister_simple
2451+#endif
2452+
2453+/* Battery specific LEDs triggers. */
2454+
2455+static void power_supply_update_bat_leds(struct power_supply *psy)
2456+{
2457+ union power_supply_propval status;
2458+
2459+ if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
2460+ return;
2461+
2462+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
2463+
2464+ switch(status.intval) {
2465+ case POWER_SUPPLY_STATUS_FULL:
2466+ led_trigger_event(psy->charging_full_trig, LED_FULL);
2467+ led_trigger_event(psy->charging_trig, LED_OFF);
2468+ led_trigger_event(psy->full_trig, LED_FULL);
2469+ break;
2470+ case POWER_SUPPLY_STATUS_CHARGING:
2471+ led_trigger_event(psy->charging_full_trig, LED_FULL);
2472+ led_trigger_event(psy->charging_trig, LED_FULL);
2473+ led_trigger_event(psy->full_trig, LED_OFF);
2474+ break;
2475+ default:
2476+ led_trigger_event(psy->charging_full_trig, LED_OFF);
2477+ led_trigger_event(psy->charging_trig, LED_OFF);
2478+ led_trigger_event(psy->full_trig, LED_OFF);
2479+ break;
2480+ }
2481+
2482+ return;
2483+}
2484+
2485+static int power_supply_create_bat_triggers(struct power_supply *psy)
2486+{
2487+ int rc = 0;
2488+
2489+ psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
2490+ sizeof("-charging-or-full"), GFP_KERNEL);
2491+ if (!psy->charging_full_trig_name)
2492+ goto charging_full_failed;
2493+
2494+ psy->charging_trig_name = kmalloc(strlen(psy->name) +
2495+ sizeof("-charging"), GFP_KERNEL);
2496+ if (!psy->charging_trig_name)
2497+ goto charging_failed;
2498+
2499+ psy->full_trig_name = kmalloc(strlen(psy->name) +
2500+ sizeof("-full"), GFP_KERNEL);
2501+ if (!psy->full_trig_name)
2502+ goto full_failed;
2503+
2504+ strcpy(psy->charging_full_trig_name, psy->name);
2505+ strcat(psy->charging_full_trig_name, "-charging-or-full");
2506+ strcpy(psy->charging_trig_name, psy->name);
2507+ strcat(psy->charging_trig_name, "-charging");
2508+ strcpy(psy->full_trig_name, psy->name);
2509+ strcat(psy->full_trig_name, "-full");
2510+
2511+ led_trigger_register_simple(psy->charging_full_trig_name,
2512+ &psy->charging_full_trig);
2513+ led_trigger_register_charging(psy->charging_trig_name,
2514+ &psy->charging_trig);
2515+ led_trigger_register_simple(psy->full_trig_name,
2516+ &psy->full_trig);
2517+
2518+ goto success;
2519+
2520+full_failed:
2521+ kfree(psy->charging_trig_name);
2522+charging_failed:
2523+ kfree(psy->charging_full_trig_name);
2524+charging_full_failed:
2525+ rc = -ENOMEM;
2526+success:
2527+ return rc;
2528+}
2529+
2530+static void power_supply_remove_bat_triggers(struct power_supply *psy)
2531+{
2532+ led_trigger_unregister_simple(psy->charging_full_trig);
2533+ led_trigger_unregister_charging(psy->charging_trig);
2534+ led_trigger_unregister_simple(psy->full_trig);
2535+ kfree(psy->full_trig_name);
2536+ kfree(psy->charging_trig_name);
2537+ kfree(psy->charging_full_trig_name);
2538+ return;
2539+}
2540+
2541+/* Generated power specific LEDs triggers. */
2542+
2543+static void power_supply_update_gen_leds(struct power_supply *psy)
2544+{
2545+ union power_supply_propval online;
2546+
2547+ if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
2548+ return;
2549+
2550+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
2551+
2552+ if (online.intval)
2553+ led_trigger_event(psy->online_trig, LED_FULL);
2554+ else
2555+ led_trigger_event(psy->online_trig, LED_OFF);
2556+
2557+ return;
2558+}
2559+
2560+static int power_supply_create_gen_triggers(struct power_supply *psy)
2561+{
2562+ int rc = 0;
2563+
2564+ psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
2565+ GFP_KERNEL);
2566+ if (!psy->online_trig_name)
2567+ goto online_failed;
2568+
2569+ strcpy(psy->online_trig_name, psy->name);
2570+ strcat(psy->online_trig_name, "-online");
2571+
2572+ led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
2573+
2574+ goto success;
2575+
2576+online_failed:
2577+ rc = -ENOMEM;
2578+success:
2579+ return rc;
2580+}
2581+
2582+static void power_supply_remove_gen_triggers(struct power_supply *psy)
2583+{
2584+ led_trigger_unregister_simple(psy->online_trig);
2585+ kfree(psy->online_trig_name);
2586+ return;
2587+}
2588+
2589+/* Choice what triggers to create&update. */
2590+
2591+void power_supply_update_leds(struct power_supply *psy)
2592+{
2593+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
2594+ power_supply_update_bat_leds(psy);
2595+ else
2596+ power_supply_update_gen_leds(psy);
2597+ return;
2598+}
2599+
2600+int power_supply_create_triggers(struct power_supply *psy)
2601+{
2602+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
2603+ return power_supply_create_bat_triggers(psy);
2604+ return power_supply_create_gen_triggers(psy);
2605+}
2606+
2607+void power_supply_remove_triggers(struct power_supply *psy)
2608+{
2609+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
2610+ power_supply_remove_bat_triggers(psy);
2611+ else
2612+ power_supply_remove_gen_triggers(psy);
2613+ return;
2614+}
2615Index: linux-2.6.22/drivers/power/power_supply_sysfs.c
2616===================================================================
2617--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2618+++ linux-2.6.22/drivers/power/power_supply_sysfs.c 2007-08-23 12:13:52.000000000 +0200
2619@@ -0,0 +1,289 @@
2620+/*
2621+ * Sysfs interface for the universal power supply monitor class
2622+ *
2623+ * Copyright © 2007 David Woodhouse <dwmw2@infradead.org>
2624+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2625+ * Copyright (c) 2004 Szabolcs Gyurko
2626+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2627+ *
2628+ * Modified: 2004, Oct Szabolcs Gyurko
2629+ *
2630+ * You may use this code as per GPL version 2
2631+ */
2632+
2633+#include <linux/ctype.h>
2634+#include <linux/power_supply.h>
2635+
2636+/*
2637+ * This is because the name "current" breaks the device attr macro.
2638+ * The "current" word resolvs to "(get_current())" so instead of
2639+ * "current" "(get_current())" appears in the sysfs.
2640+ *
2641+ * The source of this definition is the device.h which calls __ATTR
2642+ * macro in sysfs.h which calls the __stringify macro.
2643+ *
2644+ * Only modification that the name is not tried to be resolved
2645+ * (as a macro let's say).
2646+ */
2647+
2648+#define POWER_SUPPLY_ATTR(_name) \
2649+{ \
2650+ .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \
2651+ .show = power_supply_show_property, \
2652+ .store = NULL, \
2653+}
2654+
2655+static struct device_attribute power_supply_attrs[];
2656+
2657+static ssize_t power_supply_show_property(struct device *dev,
2658+ struct device_attribute *attr,
2659+ char *buf) {
2660+ static char *status_text[] = {
2661+ "Unknown", "Charging", "Discharging", "Not charging", "Full"
2662+ };
2663+ static char *health_text[] = {
2664+ "Unknown", "Good", "Overheat", "Dead"
2665+ };
2666+ static char *technology_text[] = {
2667+ "Unknown", "NiMH", "Li-ion", "Li-poly"
2668+ };
2669+ static char *capacity_level_text[] = {
2670+ "Unknown", "Critical", "Low", "Normal", "High", "Full"
2671+ };
2672+ ssize_t ret;
2673+ struct power_supply *psy = dev_get_drvdata(dev);
2674+ const ptrdiff_t off = attr - power_supply_attrs;
2675+ union power_supply_propval value;
2676+
2677+ ret = psy->get_property(psy, off, &value);
2678+
2679+ if (ret < 0) {
2680+ dev_err(dev, "driver failed to report `%s' property\n",
2681+ attr->attr.name);
2682+ return ret;
2683+ }
2684+
2685+ if (off == POWER_SUPPLY_PROP_STATUS)
2686+ return sprintf(buf, "%s\n", status_text[value.intval]);
2687+ else if (off == POWER_SUPPLY_PROP_HEALTH)
2688+ return sprintf(buf, "%s\n", health_text[value.intval]);
2689+ else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
2690+ return sprintf(buf, "%s\n", technology_text[value.intval]);
2691+ else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
2692+ return sprintf(buf, "%s\n",
2693+ capacity_level_text[value.intval]);
2694+ else if (off == POWER_SUPPLY_PROP_MODEL_NAME)
2695+ return sprintf(buf, "%s\n", value.strval);
2696+
2697+ return sprintf(buf, "%d\n", value.intval);
2698+}
2699+
2700+/* Must be in the same order as POWER_SUPPLY_PROP_* */
2701+static struct device_attribute power_supply_attrs[] = {
2702+ /* Properties of type `int' */
2703+ POWER_SUPPLY_ATTR(status),
2704+ POWER_SUPPLY_ATTR(health),
2705+ POWER_SUPPLY_ATTR(present),
2706+ POWER_SUPPLY_ATTR(online),
2707+ POWER_SUPPLY_ATTR(technology),
2708+ POWER_SUPPLY_ATTR(voltage_max_design),
2709+ POWER_SUPPLY_ATTR(voltage_min_design),
2710+ POWER_SUPPLY_ATTR(voltage_now),
2711+ POWER_SUPPLY_ATTR(voltage_avg),
2712+ POWER_SUPPLY_ATTR(current_now),
2713+ POWER_SUPPLY_ATTR(current_avg),
2714+ POWER_SUPPLY_ATTR(charge_full_design),
2715+ POWER_SUPPLY_ATTR(charge_empty_design),
2716+ POWER_SUPPLY_ATTR(charge_full),
2717+ POWER_SUPPLY_ATTR(charge_empty),
2718+ POWER_SUPPLY_ATTR(charge_now),
2719+ POWER_SUPPLY_ATTR(charge_avg),
2720+ POWER_SUPPLY_ATTR(energy_full_design),
2721+ POWER_SUPPLY_ATTR(energy_empty_design),
2722+ POWER_SUPPLY_ATTR(energy_full),
2723+ POWER_SUPPLY_ATTR(energy_empty),
2724+ POWER_SUPPLY_ATTR(energy_now),
2725+ POWER_SUPPLY_ATTR(energy_avg),
2726+ POWER_SUPPLY_ATTR(capacity),
2727+ POWER_SUPPLY_ATTR(capacity_level),
2728+ POWER_SUPPLY_ATTR(temp),
2729+ POWER_SUPPLY_ATTR(temp_ambient),
2730+ POWER_SUPPLY_ATTR(time_to_empty_now),
2731+ POWER_SUPPLY_ATTR(time_to_empty_avg),
2732+ POWER_SUPPLY_ATTR(time_to_full_now),
2733+ POWER_SUPPLY_ATTR(time_to_full_avg),
2734+ /* Properties of type `const char *' */
2735+ POWER_SUPPLY_ATTR(model_name),
2736+};
2737+
2738+static ssize_t power_supply_show_static_attrs(struct device *dev,
2739+ struct device_attribute *attr,
2740+ char *buf) {
2741+ static char *type_text[] = { "Battery", "UPS", "Mains", "USB" };
2742+ struct power_supply *psy = dev_get_drvdata(dev);
2743+
2744+ return sprintf(buf, "%s\n", type_text[psy->type]);
2745+}
2746+
2747+static struct device_attribute power_supply_static_attrs[] = {
2748+ __ATTR(type, 0444, power_supply_show_static_attrs, NULL),
2749+};
2750+
2751+int power_supply_create_attrs(struct power_supply *psy)
2752+{
2753+ int rc = 0;
2754+ int i, j;
2755+
2756+ for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
2757+ rc = device_create_file(psy->dev,
2758+ &power_supply_static_attrs[i]);
2759+ if (rc)
2760+ goto statics_failed;
2761+ }
2762+
2763+ for (j = 0; j < psy->num_properties; j++) {
2764+ rc = device_create_file(psy->dev,
2765+ &power_supply_attrs[psy->properties[j]]);
2766+ if (rc)
2767+ goto dynamics_failed;
2768+ }
2769+
2770+ goto succeed;
2771+
2772+dynamics_failed:
2773+ while (j--)
2774+ device_remove_file(psy->dev,
2775+ &power_supply_attrs[psy->properties[j]]);
2776+statics_failed:
2777+ while (i--)
2778+ device_remove_file(psy->dev,
2779+ &power_supply_static_attrs[psy->properties[i]]);
2780+succeed:
2781+ return rc;
2782+}
2783+
2784+void power_supply_remove_attrs(struct power_supply *psy)
2785+{
2786+ int i;
2787+
2788+ for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
2789+ device_remove_file(psy->dev,
2790+ &power_supply_static_attrs[i]);
2791+
2792+ for (i = 0; i < psy->num_properties; i++)
2793+ device_remove_file(psy->dev,
2794+ &power_supply_attrs[psy->properties[i]]);
2795+
2796+ return;
2797+}
2798+
2799+static char *kstruprdup(const char *str, gfp_t gfp)
2800+{
2801+ char *ret, *ustr;
2802+
2803+ ustr = ret = kmalloc(strlen(str) + 1, gfp);
2804+
2805+ if (!ret)
2806+ return NULL;
2807+
2808+ while (*str)
2809+ *ustr++ = toupper(*str++);
2810+
2811+ *ustr = 0;
2812+
2813+ return ret;
2814+}
2815+
2816+int power_supply_uevent(struct device *dev, char **envp, int num_envp,
2817+ char *buffer, int buffer_size)
2818+{
2819+ struct power_supply *psy = dev_get_drvdata(dev);
2820+ int i = 0, length = 0, ret = 0, j;
2821+ char *prop_buf;
2822+ char *attrname;
2823+
2824+ dev_dbg(dev, "uevent\n");
2825+
2826+ if (!psy) {
2827+ dev_dbg(dev, "No power supply yet\n");
2828+ return ret;
2829+ }
2830+
2831+ dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
2832+
2833+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
2834+ &length, "POWER_SUPPLY_NAME=%s", psy->name);
2835+ if (ret)
2836+ return ret;
2837+
2838+ prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
2839+ if (!prop_buf)
2840+ return -ENOMEM;
2841+
2842+ for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
2843+ struct device_attribute *attr;
2844+ char *line;
2845+
2846+ attr = &power_supply_static_attrs[j];
2847+
2848+ ret = power_supply_show_static_attrs(dev, attr, prop_buf);
2849+ if (ret < 0)
2850+ goto out;
2851+
2852+ line = strchr(prop_buf, '\n');
2853+ if (line)
2854+ *line = 0;
2855+
2856+ attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
2857+ if (!attrname) {
2858+ ret = -ENOMEM;
2859+ goto out;
2860+ }
2861+
2862+ dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
2863+
2864+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
2865+ &length, "POWER_SUPPLY_%s=%s",
2866+ attrname, prop_buf);
2867+ kfree(attrname);
2868+ if (ret)
2869+ goto out;
2870+ }
2871+
2872+ dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
2873+
2874+ for (j = 0; j < psy->num_properties; j++) {
2875+ struct device_attribute *attr;
2876+ char *line;
2877+
2878+ attr = &power_supply_attrs[psy->properties[j]];
2879+
2880+ ret = power_supply_show_property(dev, attr, prop_buf);
2881+ if (ret < 0)
2882+ goto out;
2883+
2884+ line = strchr(prop_buf, '\n');
2885+ if (line)
2886+ *line = 0;
2887+
2888+ attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
2889+ if (!attrname) {
2890+ ret = -ENOMEM;
2891+ goto out;
2892+ }
2893+
2894+ dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
2895+
2896+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
2897+ &length, "POWER_SUPPLY_%s=%s",
2898+ attrname, prop_buf);
2899+ kfree(attrname);
2900+ if (ret)
2901+ goto out;
2902+ }
2903+
2904+out:
2905+ free_page((unsigned long)prop_buf);
2906+
2907+ return ret;
2908+}
2909Index: linux-2.6.22/drivers/power/simpad-battery.c
2910===================================================================
2911--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2912+++ linux-2.6.22/drivers/power/simpad-battery.c 2007-08-23 12:13:52.000000000 +0200
2913@@ -0,0 +1,242 @@
2914+/*
2915+ * linux/drivers/misc/simpad-battery.c
2916+ *
2917+ * Copyright (C) 2005 Holger Hans Peter Freyther
2918+ * Copyright (C) 2001 Juergen Messerer
2919+ *
2920+ * This program is free software; you can redistribute it and/or modify
2921+ * it under the terms of the GNU General Public License as published by
2922+ * the Free Software Foundation; either version 2 of the License.
2923+ *
2924+ * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is
2925+ * unsupported for now.
2926+ *
2927+ */
2928+
2929+#include <linux/battery.h>
2930+#include <asm/dma.h>
2931+#include "ucb1x00.h"
2932+
2933+
2934+/*
2935+ * Conversion from AD -> mV
2936+ * 7.5V = 1023 7.3313mV/Digit
2937+ *
2938+ * 400 Units == 9.7V
2939+ * a = ADC value
2940+ * 21 = ADC error
2941+ * 12600 = Divident to get 2*7.3242
2942+ * 860 = Divider to get 2*7.3242
2943+ * 170 = Voltagedrop over
2944+ */
2945+#define CALIBRATE_BATTERY(a) ((((a + 21)*12600)/860) + 170)
2946+
2947+/*
2948+ * We have two types of batteries a small and a large one
2949+ * To get the right value we to distinguish between those two
2950+ * 450 Units == 15 V
2951+ */
2952+#define CALIBRATE_SUPPLY(a) (((a) * 1500) / 45)
2953+#define MIN_SUPPLY 12000 /* Less then 12V means no powersupply */
2954+
2955+/*
2956+ * Charging Current
2957+ * if value is >= 50 then charging is on
2958+ */
2959+#define CALIBRATE_CHARGING(a) (((a)* 1000)/(152/4)))
2960+
2961+struct simpad_battery_t {
2962+ struct battery battery;
2963+ struct ucb1x00* ucb;
2964+
2965+ /*
2966+ * Variables for the values to one time support
2967+ * T-Sinuspad as well
2968+ */
2969+ int min_voltage;
2970+ int min_current;
2971+ int min_charge;
2972+
2973+ int max_voltage;
2974+ int max_current;
2975+ int max_charge;
2976+
2977+ int min_supply;
2978+ int charging_led_label;
2979+ int charging_max_label;
2980+ int batt_full;
2981+ int batt_low;
2982+ int batt_critical;
2983+ int batt_empty;
2984+};
2985+
2986+static int simpad_get_min_voltage(struct battery* _battery )
2987+{
2988+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
2989+ return battery->min_voltage;
2990+}
2991+
2992+static int simpad_get_min_current(struct battery* _battery)
2993+{
2994+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
2995+ return battery->min_current;
2996+}
2997+
2998+static int simpad_get_min_charge(struct battery* _battery)
2999+{
3000+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3001+ return battery->min_charge;
3002+}
3003+
3004+static int simpad_get_max_voltage(struct battery* _battery)
3005+{
3006+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3007+ return battery->max_voltage;
3008+}
3009+
3010+static int simpad_get_max_current(struct battery* _battery)
3011+{
3012+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3013+ return battery->max_current;
3014+}
3015+
3016+static int simpad_get_max_charge(struct battery* _battery)
3017+{
3018+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3019+ return battery->max_charge;
3020+}
3021+
3022+static int simpad_get_temp(struct battery* _battery)
3023+{
3024+ return 0;
3025+}
3026+
3027+static int simpad_get_voltage(struct battery* _battery)
3028+{
3029+ int val;
3030+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3031+
3032+
3033+ ucb1x00_adc_enable(battery->ucb);
3034+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD1, UCB_NOSYNC);
3035+ ucb1x00_adc_disable(battery->ucb);
3036+
3037+ return CALIBRATE_BATTERY(val);
3038+}
3039+
3040+static int simpad_get_current(struct battery* _battery)
3041+{
3042+ int val;
3043+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3044+
3045+ ucb1x00_adc_enable(battery->ucb);
3046+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD3, UCB_NOSYNC);
3047+ ucb1x00_adc_disable(battery->ucb);
3048+
3049+ return val;
3050+}
3051+
3052+static int simpad_get_charge(struct battery* _battery)
3053+{
3054+ int val;
3055+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3056+
3057+ ucb1x00_adc_enable(battery->ucb);
3058+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD2, UCB_NOSYNC);
3059+ ucb1x00_adc_disable(battery->ucb);
3060+
3061+ return CALIBRATE_SUPPLY(val);
3062+
3063+}
3064+
3065+static int simpad_get_status(struct battery* _battery)
3066+{
3067+ struct simpad_battery_t* battery = (struct simpad_battery_t*)(_battery);
3068+ int vcharger = simpad_get_voltage(_battery);
3069+ int icharger = simpad_get_current(_battery);
3070+
3071+ int status = BATTERY_STATUS_UNKNOWN;
3072+ if(icharger > battery->charging_led_label)
3073+ status = BATTERY_STATUS_CHARGING;
3074+ else if(vcharger > battery->min_supply)
3075+ status = BATTERY_STATUS_NOT_CHARGING;
3076+ else
3077+ status = BATTERY_STATUS_DISCHARGING;
3078+
3079+ return status;
3080+}
3081+
3082+static struct simpad_battery_t simpad_battery = {
3083+ .battery = {
3084+ .get_min_voltage = simpad_get_min_voltage,
3085+ .get_min_current = simpad_get_min_current,
3086+ .get_min_charge = simpad_get_min_charge,
3087+ .get_max_voltage = simpad_get_max_voltage,
3088+ .get_max_current = simpad_get_max_current,
3089+ .get_max_charge = simpad_get_max_charge,
3090+ .get_temp = simpad_get_temp,
3091+ .get_voltage = simpad_get_voltage,
3092+ .get_current = simpad_get_current,
3093+ .get_charge = simpad_get_charge,
3094+ .get_status = simpad_get_status,
3095+ },
3096+ .min_voltage = 0,
3097+ .min_current = 0,
3098+ .min_charge = 0,
3099+ .max_voltage = 0,
3100+ .max_current = 0,
3101+ .max_charge = 0,
3102+
3103+ .min_supply = 1200,
3104+ .charging_led_label = 18,
3105+ .charging_max_label = 265,
3106+ .batt_full = 8300,
3107+ .batt_low = 7300,
3108+ .batt_critical = 6800,
3109+ .batt_empty = 6500,
3110+};
3111+
3112+
3113+
3114+/*
3115+ * UCB glue code
3116+ */
3117+static int ucb1x00_battery_add(struct class_device *dev)
3118+{
3119+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
3120+ simpad_battery.ucb = ucb;
3121+
3122+ battery_class_register(&simpad_battery.battery);
3123+
3124+ return 0;
3125+}
3126+
3127+static void ucb1x00_battery_remove(struct class_device *dev)
3128+{
3129+ return battery_class_unregister(&simpad_battery.battery);
3130+}
3131+
3132+
3133+static struct ucb1x00_class_interface ucb1x00_battery_interface = {
3134+ .interface = {
3135+ .add = ucb1x00_battery_add,
3136+ .remove = ucb1x00_battery_remove,
3137+ },
3138+};
3139+
3140+
3141+static int __init battery_register(void)
3142+{
3143+ return ucb1x00_register_interface(&ucb1x00_battery_interface);
3144+}
3145+
3146+static void __exit battery_unregister(void)
3147+{
3148+ ucb1x00_unregister_interface(&ucb1x00_battery_interface);
3149+}
3150+
3151+module_init(battery_register);
3152+module_exit(battery_unregister);
3153+
3154+MODULE_AUTHOR("Holger Hans Peter Freyther");
3155+MODULE_LICENSE("GPL");
3156Index: linux-2.6.22/arch/arm/Kconfig
3157===================================================================
3158--- linux-2.6.22.orig/arch/arm/Kconfig 2007-08-23 12:17:42.000000000 +0200
3159+++ linux-2.6.22/arch/arm/Kconfig 2007-08-23 12:22:28.000000000 +0200
3160@@ -1016,6 +1016,8 @@
3161
3162 source "drivers/w1/Kconfig"
3163
3164+source "drivers/power/Kconfig"
3165+
3166 source "drivers/hwmon/Kconfig"
3167
3168 #source "drivers/l3/Kconfig"
3169Index: linux-2.6.22/drivers/Kconfig
3170===================================================================
3171--- linux-2.6.22.orig/drivers/Kconfig 2007-08-23 12:21:27.000000000 +0200
3172+++ linux-2.6.22/drivers/Kconfig 2007-08-23 12:22:03.000000000 +0200
3173@@ -54,6 +54,8 @@
3174
3175 source "drivers/w1/Kconfig"
3176
3177+source "drivers/power/Kconfig"
3178+
3179 source "drivers/hwmon/Kconfig"
3180
3181 source "drivers/mfd/Kconfig"
3182Index: linux-2.6.22/drivers/Makefile
3183===================================================================
3184--- linux-2.6.22.orig/drivers/Makefile 2007-08-23 12:33:58.000000000 +0200
3185+++ linux-2.6.22/drivers/Makefile 2007-08-23 12:34:34.000000000 +0200
3186@@ -61,6 +61,7 @@
3187 obj-$(CONFIG_RTC_LIB) += rtc/
3188 obj-y += i2c/
3189 obj-$(CONFIG_W1) += w1/
3190+obj-$(CONFIG_POWER_SUPPLY) += power/
3191 obj-$(CONFIG_HWMON) += hwmon/
3192 obj-$(CONFIG_PHONE) += telephony/
3193 obj-$(CONFIG_MD) += md/
3194Index: linux-2.6.22/include/linux/power_supply.h
3195===================================================================
3196--- /dev/null 1970-01-01 00:00:00.000000000 +0000
3197+++ linux-2.6.22/include/linux/power_supply.h 2007-08-23 12:37:10.000000000 +0200
3198@@ -0,0 +1,175 @@
3199+/*
3200+ * Universal power supply monitor class
3201+ *
3202+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
3203+ * Copyright (c) 2004 Szabolcs Gyurko
3204+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
3205+ *
3206+ * Modified: 2004, Oct Szabolcs Gyurko
3207+ *
3208+ * You may use this code as per GPL version 2
3209+ */
3210+
3211+#ifndef __LINUX_POWER_SUPPLY_H__
3212+#define __LINUX_POWER_SUPPLY_H__
3213+
3214+#include <linux/device.h>
3215+#include <linux/workqueue.h>
3216+#include <linux/leds.h>
3217+
3218+/*
3219+ * All voltages, currents, charges, energies, time and temperatures in uV,
3220+ * uA, uAh, uWh, seconds and tenths of degree Celsius unless otherwise
3221+ * stated. It's driver's job to convert its raw values to units in which
3222+ * this class operates.
3223+ */
3224+
3225+/*
3226+ * For systems where the charger determines the maximum battery capacity
3227+ * the min and max fields should be used to present these values to user
3228+ * space. Unused/unknown fields will not appear in sysfs.
3229+ */
3230+
3231+enum {
3232+ POWER_SUPPLY_STATUS_UNKNOWN = 0,
3233+ POWER_SUPPLY_STATUS_CHARGING,
3234+ POWER_SUPPLY_STATUS_DISCHARGING,
3235+ POWER_SUPPLY_STATUS_NOT_CHARGING,
3236+ POWER_SUPPLY_STATUS_FULL,
3237+};
3238+
3239+enum {
3240+ POWER_SUPPLY_HEALTH_UNKNOWN = 0,
3241+ POWER_SUPPLY_HEALTH_GOOD,
3242+ POWER_SUPPLY_HEALTH_OVERHEAT,
3243+ POWER_SUPPLY_HEALTH_DEAD,
3244+};
3245+
3246+enum {
3247+ POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,
3248+ POWER_SUPPLY_TECHNOLOGY_NIMH,
3249+ POWER_SUPPLY_TECHNOLOGY_LION,
3250+ POWER_SUPPLY_TECHNOLOGY_LIPO,
3251+};
3252+
3253+enum {
3254+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
3255+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
3256+ POWER_SUPPLY_CAPACITY_LEVEL_LOW,
3257+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
3258+ POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
3259+ POWER_SUPPLY_CAPACITY_LEVEL_FULL,
3260+};
3261+
3262+enum power_supply_property {
3263+ /* Properties of type `int' */
3264+ POWER_SUPPLY_PROP_STATUS = 0,
3265+ POWER_SUPPLY_PROP_HEALTH,
3266+ POWER_SUPPLY_PROP_PRESENT,
3267+ POWER_SUPPLY_PROP_ONLINE,
3268+ POWER_SUPPLY_PROP_TECHNOLOGY,
3269+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
3270+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
3271+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
3272+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
3273+ POWER_SUPPLY_PROP_CURRENT_NOW,
3274+ POWER_SUPPLY_PROP_CURRENT_AVG,
3275+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
3276+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
3277+ POWER_SUPPLY_PROP_CHARGE_FULL,
3278+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
3279+ POWER_SUPPLY_PROP_CHARGE_NOW,
3280+ POWER_SUPPLY_PROP_CHARGE_AVG,
3281+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
3282+ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
3283+ POWER_SUPPLY_PROP_ENERGY_FULL,
3284+ POWER_SUPPLY_PROP_ENERGY_EMPTY,
3285+ POWER_SUPPLY_PROP_ENERGY_NOW,
3286+ POWER_SUPPLY_PROP_ENERGY_AVG,
3287+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
3288+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
3289+ POWER_SUPPLY_PROP_TEMP,
3290+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
3291+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
3292+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
3293+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
3294+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3295+ /* Properties of type `const char *' */
3296+ POWER_SUPPLY_PROP_MODEL_NAME,
3297+};
3298+
3299+enum power_supply_type {
3300+ POWER_SUPPLY_TYPE_BATTERY = 0,
3301+ POWER_SUPPLY_TYPE_UPS,
3302+ POWER_SUPPLY_TYPE_MAINS,
3303+ POWER_SUPPLY_TYPE_USB,
3304+};
3305+
3306+union power_supply_propval {
3307+ int intval;
3308+ const char *strval;
3309+};
3310+
3311+struct power_supply {
3312+ const char *name;
3313+ enum power_supply_type type;
3314+ enum power_supply_property *properties;
3315+ size_t num_properties;
3316+
3317+ char **supplied_to;
3318+ size_t num_supplicants;
3319+
3320+ int (*get_property)(struct power_supply *psy,
3321+ enum power_supply_property psp,
3322+ union power_supply_propval *val);
3323+ void (*external_power_changed)(struct power_supply *psy);
3324+
3325+ /* For APM emulation, think legacy userspace. */
3326+ int use_for_apm;
3327+
3328+ /* private */
3329+ struct device *dev;
3330+ struct work_struct changed_work;
3331+
3332+#ifdef CONFIG_LEDS_TRIGGERS
3333+ struct led_trigger *charging_full_trig;
3334+ char *charging_full_trig_name;
3335+ struct led_trigger *charging_trig;
3336+ char *charging_trig_name;
3337+ struct led_trigger *full_trig;
3338+ char *full_trig_name;
3339+ struct led_trigger *online_trig;
3340+ char *online_trig_name;
3341+#endif
3342+};
3343+
3344+/*
3345+ * This is recommended structure to specify static power supply parameters.
3346+ * Generic one, parametrizable for different power supplies. Power supply
3347+ * class itself does not use it, but that's what implementing most platform
3348+ * drivers, should try reuse for consistency.
3349+ */
3350+
3351+struct power_supply_info {
3352+ const char *name;
3353+ int technology;
3354+ int voltage_max_design;
3355+ int voltage_min_design;
3356+ int charge_full_design;
3357+ int charge_empty_design;
3358+ int energy_full_design;
3359+ int energy_empty_design;
3360+ int use_for_apm;
3361+};
3362+
3363+extern void power_supply_changed(struct power_supply *psy);
3364+extern int power_supply_am_i_supplied(struct power_supply *psy);
3365+
3366+extern int power_supply_register(struct device *parent,
3367+ struct power_supply *psy);
3368+extern void power_supply_unregister(struct power_supply *psy);
3369+
3370+/* For APM emulation, think legacy userspace. */
3371+extern struct class *power_supply_class;
3372+
3373+#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 @@
1 drivers/video/Kconfig | 18
2 drivers/video/Makefile | 1
3 drivers/video/pxafb.c | 305 +++++--
4 drivers/video/pxafb.h | 65 +
5 drivers/video/pxafb_overlay.c | 1525 ++++++++++++++++++++++++++++++++++++
6 include/asm-arm/arch-pxa/pxa-regs.h | 111 ++
7 6 files changed, 1969 insertions(+), 56 deletions(-)
8
9--- linux-2.6.24-rc1.orig/drivers/video/Kconfig
10+++ linux-2.6.24-rc1/drivers/video/Kconfig
11@@ -1718,6 +1718,24 @@
12
13 If unsure, say N.
14
15+choice
16+ prompt "PXA LCD type"
17+ depends on FB_PXA
18+
19+config FB_PXA_LCD_QVGA
20+ bool "QVGA(320x240)"
21+
22+config FB_PXA_LCD_VGA
23+ bool "VGA (640x480)"
24+
25+endchoice
26+
27+config FB_PXA_OVERLAY
28+ tristate "PXA LCD overlay support"
29+ depends on FB_PXA
30+ ---help---
31+ Frame buffer overlay driver for PXA27x
32+
33 config FB_PXA_PARAMETERS
34 bool "PXA LCD command line parameters"
35 default n
36--- linux-2.6.24-rc1.orig/drivers/video/Makefile
37+++ linux-2.6.24-rc1/drivers/video/Makefile
38@@ -96,6 +96,7 @@
39 obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
40 obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o
41 obj-$(CONFIG_FB_PXA) += pxafb.o
42+obj-$(CONFIG_FB_PXA_OVERLAY) += pxafb_overlay.o
43 obj-$(CONFIG_FB_W100) += w100fb.o
44 obj-$(CONFIG_FB_AU1100) += au1100fb.o
45 obj-$(CONFIG_FB_AU1200) += au1200fb.o
46--- linux-2.6.24-rc1.orig/drivers/video/pxafb.c
47+++ linux-2.6.24-rc1/drivers/video/pxafb.c
48@@ -59,17 +59,49 @@
49 #define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
50 #define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
51
52+wait_queue_head_t fcs_wait_eof;
53+int fcs_in_eof;
54+static DECLARE_MUTEX(fcs_lcd_sem);
55+
56 static void (*pxafb_backlight_power)(int);
57 static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
58
59 static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
60-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
61+void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state);
62
63 #ifdef CONFIG_FB_PXA_PARAMETERS
64 #define PXAFB_OPTIONS_SIZE 256
65 static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
66 #endif
67
68+static struct pxafb_rgb def_rgb_8 = {
69+ red: { offset: 0, length: 8, },
70+ green: { offset: 0, length: 8, },
71+ blue: { offset: 0, length: 8, },
72+ transp: { offset: 0, length: 0, },
73+};
74+
75+static struct pxafb_rgb def_rgb_16 = {
76+ red: { offset: 11, length: 5, },
77+ green: { offset: 5, length: 6, },
78+ blue: { offset: 0, length: 5, },
79+ transp: { offset: 0, length: 0, },
80+};
81+
82+static struct pxafb_rgb def_rgb_18 = {
83+ red: { offset: 12, length: 6, },
84+ green: { offset: 6, length: 6, },
85+ blue: { offset: 0, length: 6, },
86+ transp: { offset: 0, length: 0, },
87+};
88+
89+static struct pxafb_rgb def_rgb_24 = {
90+ red: { offset: 16, length: 8, },
91+ green: { offset: 8, length: 8, },
92+ blue: { offset: 0, length: 8, },
93+ transp: { offset: 0, length: 0, },
94+};
95+
96 static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
97 {
98 unsigned long flags;
99@@ -209,6 +241,10 @@
100 case 4: ret = LCCR3_4BPP; break;
101 case 8: ret = LCCR3_8BPP; break;
102 case 16: ret = LCCR3_16BPP; break;
103+ case 18: ret = LCCR3_18BPP; break;
104+ case 19: ret = LCCR3_19BPP; break;
105+ case 24: ret = LCCR3_24BPP; break;
106+ case 25: ret = LCCR3_25BPP; break;
107 }
108 return ret;
109 }
110@@ -320,18 +356,34 @@
111 * The pixel packing format is described on page 7-11 of the
112 * PXA2XX Developer's Manual.
113 */
114- if (var->bits_per_pixel == 16) {
115- var->red.offset = 11; var->red.length = 5;
116- var->green.offset = 5; var->green.length = 6;
117- var->blue.offset = 0; var->blue.length = 5;
118- var->transp.offset = var->transp.length = 0;
119- } else {
120- var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
121- var->red.length = 8;
122- var->green.length = 8;
123- var->blue.length = 8;
124- var->transp.length = 0;
125- }
126+ switch (var->bits_per_pixel) {
127+ case 16:
128+ /* 2 pixels per line */
129+ var->red = def_rgb_16.red;
130+ var->green = def_rgb_16.green;
131+ var->blue = def_rgb_16.blue;
132+ var->transp = def_rgb_16.transp;
133+ break;
134+ case 18:
135+ case 19:
136+ var->red = def_rgb_18.red;
137+ var->green = def_rgb_18.green;
138+ var->blue = def_rgb_18.blue;
139+ var->transp = def_rgb_18.transp;
140+ break;
141+ case 24:
142+ case 25:
143+ var->red = def_rgb_24.red;
144+ var->green = def_rgb_24.green;
145+ var->blue = def_rgb_24.blue;
146+ var->transp = def_rgb_24.transp;
147+ break;
148+ default:
149+ var->red = def_rgb_8.red;
150+ var->green = def_rgb_8.green;
151+ var->blue = def_rgb_8.blue;
152+ var->transp = def_rgb_8.transp;
153+ }
154
155 #ifdef CONFIG_CPU_FREQ
156 pr_debug("pxafb: dma period = %d ps, clock = %d kHz\n",
157@@ -345,7 +397,7 @@
158 static inline void pxafb_set_truecolor(u_int is_true_color)
159 {
160 pr_debug("pxafb: true_color = %d\n", is_true_color);
161- // do your machine-specific setup if needed
162+ /* do your machine-specific setup if needed */
163 }
164
165 /*
166@@ -360,7 +412,8 @@
167
168 pr_debug("pxafb: set_par\n");
169
170- if (var->bits_per_pixel == 16)
171+ if (var->bits_per_pixel == 16 || var->bits_per_pixel == 18 ||var->bits_per_pixel == 19
172+ || var->bits_per_pixel == 24 || var->bits_per_pixel == 25)
173 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
174 else if (!fbi->cmap_static)
175 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
176@@ -373,12 +426,25 @@
177 fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
178 }
179
180- fbi->fb.fix.line_length = var->xres_virtual *
181- var->bits_per_pixel / 8;
182- if (var->bits_per_pixel == 16)
183- fbi->palette_size = 0;
184- else
185- fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
186+ switch (var->bits_per_pixel) {
187+ case 16:
188+ fbi->fb.fix.line_length = var->xres_virtual * 2;
189+ fbi->palette_size = 0;
190+ break;
191+ case 18:
192+ case 19:
193+ fbi->fb.fix.line_length = var->xres_virtual * 3;
194+ fbi->palette_size = 0;
195+ break;
196+ case 24:
197+ case 25:
198+ fbi->fb.fix.line_length = var->xres_virtual * 4;
199+ fbi->palette_size = 0;
200+ break;
201+ default:
202+ fbi->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
203+ fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
204+ }
205
206 if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
207 palette_mem_size = fbi->palette_size * sizeof(u16);
208@@ -395,7 +461,8 @@
209 */
210 pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
211
212- if (fbi->fb.var.bits_per_pixel == 16)
213+ if (fbi->fb.var.bits_per_pixel == 16 || fbi->fb.var.bits_per_pixel == 18 ||fbi->fb.var.bits_per_pixel == 19
214+ || fbi->fb.var.bits_per_pixel == 24 || fbi->fb.var.bits_per_pixel == 25)
215 fb_dealloc_cmap(&fbi->fb.cmap);
216 else
217 fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
218@@ -441,7 +508,7 @@
219 * 16 bpp mode does not really use the palette, so this will not
220 * blank the display in all modes.
221 */
222-static int pxafb_blank(int blank, struct fb_info *info)
223+int pxafb_blank(int blank, struct fb_info *info)
224 {
225 struct pxafb_info *fbi = (struct pxafb_info *)info;
226 int i;
227@@ -458,19 +525,20 @@
228 for (i = 0; i < fbi->palette_size; i++)
229 pxafb_setpalettereg(i, 0, 0, 0, 0, info);
230
231- pxafb_schedule_work(fbi, C_DISABLE);
232- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
233+ pxafb_schedule_work(fbi, C_BLANK);
234+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
235 break;
236
237 case FB_BLANK_UNBLANK:
238- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
239+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
240 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
241 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
242 fb_set_cmap(&fbi->fb.cmap, info);
243- pxafb_schedule_work(fbi, C_ENABLE);
244+ pxafb_schedule_work(fbi, C_UNBLANK);
245 }
246 return 0;
247 }
248+EXPORT_SYMBOL(pxafb_blank);
249
250 static int pxafb_mmap(struct fb_info *info,
251 struct vm_area_struct *vma)
252@@ -606,6 +674,10 @@
253 case 4:
254 case 8:
255 case 16:
256+ case 18:
257+ case 19:
258+ case 24:
259+ case 25:
260 break;
261 default:
262 printk(KERN_ERR "%s: invalid bit depth %d\n",
263@@ -637,7 +709,10 @@
264
265 new_regs.lccr0 = fbi->lccr0 |
266 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
267- LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
268+#ifdef CONFIG_PXA27x /* Enable overlay for PXA27x */
269+ LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM |
270+#endif
271+ LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
272
273 new_regs.lccr1 =
274 LCCR1_DisWdth(var->xres) +
275@@ -696,7 +771,7 @@
276
277 fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
278 fbi->dmadesc_fbhigh_cpu->fidr = 0;
279- fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
280+ fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL | LDCMD_EOFINT;
281
282 fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
283 fbi->dmadesc_palette_cpu->fidr = 0;
284@@ -708,7 +783,8 @@
285 sizeof(u32);
286 fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
287
288- if (var->bits_per_pixel == 16) {
289+ if (var->bits_per_pixel == 16 || var->bits_per_pixel == 18 ||var->bits_per_pixel == 19
290+ || var->bits_per_pixel == 24 || var->bits_per_pixel == 25) {
291 /* palette shouldn't be loaded in true-color mode */
292 fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
293 fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
294@@ -763,8 +839,8 @@
295 }
296
297 /*
298- * NOTE! The following functions are purely helpers for set_ctrlr_state.
299- * Do not call them directly; set_ctrlr_state does the correct serialisation
300+ * NOTE! The following functions are purely helpers for pxafb_set_ctrlr_state.
301+ * Do not call them directly; pxafb_set_ctrlr_state does the correct serialisation
302 * to ensure that things happen in the right way 100% of time time.
303 * -- rmk
304 */
305@@ -786,7 +862,8 @@
306
307 static void pxafb_setup_gpio(struct pxafb_info *fbi)
308 {
309- int gpio, ldd_bits;
310+ int gpio;
311+ int ldd_bits = 0;
312 unsigned int lccr0 = fbi->lccr0;
313
314 /*
315@@ -796,28 +873,56 @@
316 /* 4 bit interface */
317 if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
318 (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
319- (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
320+ (lccr0 & LCCR0_DPD) == LCCR0_4PixMono) {
321 ldd_bits = 4;
322-
323+ }
324 /* 8 bit interface */
325 else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
326 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
327 ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
328- (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
329+ (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl)) {
330 ldd_bits = 8;
331-
332+ }
333 /* 16 bit interface */
334- else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
335- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
336- ldd_bits = 16;
337+ else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
338+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act)) {
339+ switch (fbi->fb.var.bits_per_pixel) {
340+ case 16:
341+#ifdef CONFIG_PXA27x
342+ /* bits 58-77 */
343+ GPDR1 |= (0x3f << 26);
344+ GPDR2 |= 0x00003fff;
345
346+ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
347+ GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
348+#endif
349+ ldd_bits = 16;
350+ break;
351+ case 18:
352+ case 19:
353+ case 24:
354+ case 25:
355+#ifdef CONFIG_PXA27x
356+ /* bits 58-77 and 86, 87 */
357+ GPDR1 |= (0x3f << 26);
358+ GPDR2 |= 0x00c03fff;
359+
360+ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
361+ GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
362+ GAFR2_U = (GAFR2_U & 0xffff0fff) | 0xa000;
363+#endif
364+ ldd_bits = 25;
365+ break;
366+ }
367+ }
368 else {
369 printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
370 return;
371 }
372
373- for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
374+ for (gpio = 58; ldd_bits > 0; gpio++, ldd_bits--) {
375 pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
376+ }
377 pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
378 pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
379 pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
380@@ -837,6 +942,7 @@
381 /* enable LCD controller clock */
382 clk_enable(fbi->clk);
383
384+ down(&fcs_lcd_sem);
385 /* Sequence from 11.7.10 */
386 LCCR3 = fbi->reg_lccr3;
387 LCCR2 = fbi->reg_lccr2;
388@@ -847,6 +953,8 @@
389 FDADR1 = fbi->fdadr1;
390 LCCR0 |= LCCR0_ENB;
391
392+ up(&fcs_lcd_sem);
393+
394 pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
395 pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
396 pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
397@@ -862,6 +970,7 @@
398
399 pr_debug("pxafb: disabling LCD controller\n");
400
401+ down(&fcs_lcd_sem);
402 set_current_state(TASK_UNINTERRUPTIBLE);
403 add_wait_queue(&fbi->ctrlr_wait, &wait);
404
405@@ -871,6 +980,7 @@
406
407 schedule_timeout(200 * HZ / 1000);
408 remove_wait_queue(&fbi->ctrlr_wait, &wait);
409+ up(&fcs_lcd_sem);
410
411 /* disable LCD controller clock */
412 clk_disable(fbi->clk);
413@@ -888,6 +998,11 @@
414 LCCR0 |= LCCR0_LDM;
415 wake_up(&fbi->ctrlr_wait);
416 }
417+ if (lcsr & LCSR_EOF && fcs_in_eof) {
418+ LCCR0 |= LCCR0_EFM;
419+ fcs_in_eof = 0;
420+ wake_up(&fcs_wait_eof);
421+ }
422
423 LCSR = lcsr;
424 return IRQ_HANDLED;
425@@ -898,7 +1013,7 @@
426 * sleep when disabling the LCD controller, or if we get two contending
427 * processes trying to alter state.
428 */
429-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
430+void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state)
431 {
432 u_int old_state;
433
434@@ -920,7 +1035,9 @@
435 */
436 if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
437 fbi->state = state;
438- //TODO __pxafb_lcd_power(fbi, 0);
439+ /* TODO __pxafb_lcd_power(fbi, 0); */
440+ if(fbi->set_overlay_ctrlr_state)
441+ fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
442 pxafb_disable_controller(fbi);
443 }
444 break;
445@@ -934,6 +1051,8 @@
446 fbi->state = state;
447 __pxafb_backlight_power(fbi, 0);
448 __pxafb_lcd_power(fbi, 0);
449+ if(fbi->set_overlay_ctrlr_state)
450+ fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
451 if (old_state != C_DISABLE_CLKCHANGE)
452 pxafb_disable_controller(fbi);
453 }
454@@ -947,7 +1066,9 @@
455 if (old_state == C_DISABLE_CLKCHANGE) {
456 fbi->state = C_ENABLE;
457 pxafb_enable_controller(fbi);
458- //TODO __pxafb_lcd_power(fbi, 1);
459+ /* TODO __pxafb_lcd_power(fbi, 1); */
460+ if(fbi->set_overlay_ctrlr_state)
461+ fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
462 }
463 break;
464
465@@ -959,9 +1080,13 @@
466 */
467 if (old_state == C_ENABLE) {
468 __pxafb_lcd_power(fbi, 0);
469+ if(fbi->set_overlay_ctrlr_state)
470+ fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
471 pxafb_disable_controller(fbi);
472 pxafb_setup_gpio(fbi);
473 pxafb_enable_controller(fbi);
474+ if(fbi->set_overlay_ctrlr_state)
475+ fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
476 __pxafb_lcd_power(fbi, 1);
477 }
478 break;
479@@ -987,11 +1112,46 @@
480 pxafb_enable_controller(fbi);
481 __pxafb_lcd_power(fbi, 1);
482 __pxafb_backlight_power(fbi, 1);
483+ if(fbi->set_overlay_ctrlr_state)
484+ fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
485 }
486 break;
487+
488+ case C_BLANK:
489+ /*
490+ * Disable controller, blank overlays if exist.
491+ */
492+ if ((old_state != C_DISABLE) && (old_state != C_BLANK)) {
493+ fbi->state = state;
494+ __pxafb_backlight_power(fbi, 0);
495+ __pxafb_lcd_power(fbi, 0);
496+ if(fbi->set_overlay_ctrlr_state)
497+ fbi->set_overlay_ctrlr_state(fbi, C_BLANK);
498+ if (old_state != C_DISABLE_CLKCHANGE)
499+ pxafb_disable_controller(fbi);
500+ }
501+ break;
502+
503+ case C_UNBLANK:
504+ /*
505+ * Power up the LCD screen, enable controller, and
506+ * turn on the backlight, unblank overlays if exist.
507+ */
508+ if ((old_state != C_ENABLE) && (old_state != C_UNBLANK)) {
509+ fbi->state = C_UNBLANK;
510+ pxafb_setup_gpio(fbi);
511+ pxafb_enable_controller(fbi);
512+ __pxafb_lcd_power(fbi, 1);
513+ __pxafb_backlight_power(fbi, 1);
514+ if(fbi->set_overlay_ctrlr_state)
515+ fbi->set_overlay_ctrlr_state(fbi, C_UNBLANK);
516+ }
517+ break;
518+
519 }
520 up(&fbi->ctrlr_sem);
521 }
522+EXPORT_SYMBOL(pxafb_set_ctrlr_state);
523
524 /*
525 * Our LCD controller task (which is called when we blank or unblank)
526@@ -1003,7 +1163,7 @@
527 container_of(work, struct pxafb_info, task);
528 u_int state = xchg(&fbi->task_state, -1);
529
530- set_ctrlr_state(fbi, state);
531+ pxafb_set_ctrlr_state(fbi, state);
532 }
533
534 #ifdef CONFIG_CPU_FREQ
535@@ -1018,19 +1178,29 @@
536 pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
537 {
538 struct pxafb_info *fbi = TO_INF(nb, freq_transition);
539- //TODO struct cpufreq_freqs *f = data;
540+ /* TODO struct cpufreq_freqs *f = data; */
541+ struct cpufreq_freqs *clkinfo;
542 u_int pcd;
543+ u_int lccr3;
544
545 switch (val) {
546 case CPUFREQ_PRECHANGE:
547- set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
548+ pxafb_set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
549 break;
550
551 case CPUFREQ_POSTCHANGE:
552- pcd = get_pcd(fbi, fbi->fb.var.pixclock);
553+ clkinfo = (struct cpufreq_freqs *)data;
554+ /* If leaving a 13kHz state with the LCD sustained */
555+ if ((clkinfo->old == 13000))
556+ break;
557+
558+ pcd = get_pcd(fbi->fb.var.pixclock);
559+ lccr3 = fbi->reg_lccr3;
560 set_hsync_time(fbi, pcd);
561 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
562- set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
563+ pxafb_set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
564+ if (lccr3 != fbi->reg_lccr3 && !((LCCR0 & LCCR0_DIS) || !(LCCR0 & LCCR0_ENB)))
565+ LCCR3 = fbi->reg_lccr3;
566 break;
567 }
568 return 0;
569@@ -1049,7 +1219,7 @@
570 printk(KERN_DEBUG "min dma period: %d ps, "
571 "new clock %d kHz\n", pxafb_display_dma_period(var),
572 policy->max);
573- // TODO: fill in min/max values
574+ /* TODO: fill in min/max values */
575 break;
576 #if 0
577 case CPUFREQ_NOTIFY:
578@@ -1075,7 +1245,7 @@
579 {
580 struct pxafb_info *fbi = platform_get_drvdata(dev);
581
582- set_ctrlr_state(fbi, C_DISABLE_PM);
583+ pxafb_set_ctrlr_state(fbi, C_DISABLE_PM);
584 return 0;
585 }
586
587@@ -1083,7 +1253,11 @@
588 {
589 struct pxafb_info *fbi = platform_get_drvdata(dev);
590
591- set_ctrlr_state(fbi, C_ENABLE_PM);
592+ pxafb_set_ctrlr_state(fbi, C_ENABLE_PM);
593+//RP#ifdef CONFIG_PXA27x
594+//RP LCCR4 |= (1 << 31); /* Disable the PCD Divisor, PCDDIV */
595+//RP LCCR4 |= (5 << 17); /* Undocumented feature */
596+//RP#endif
597 return 0;
598 }
599 #else
600@@ -1197,11 +1371,21 @@
601 fbi->task_state = (u_char)-1;
602
603 for (i = 0; i < inf->num_modes; i++) {
604- smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
605+ if (mode[i].bpp <= 16) { /* 8, 16 bpp */
606+ smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
607+ } else if ( mode[i].bpp > 19 ) { /* 24, 25 bpp */
608+ smemlen = mode[i].xres * mode[i].yres * 4;
609+ } else { /* 18, 19 bpp */
610+ /* packed format */
611+ smemlen = mode[i].xres * mode[i].yres * 3;
612+ }
613+
614 if (smemlen > fbi->fb.fix.smem_len)
615 fbi->fb.fix.smem_len = smemlen;
616 }
617
618+ fbi->set_overlay_ctrlr_state = NULL;
619+
620 init_waitqueue_head(&fbi->ctrlr_wait);
621 INIT_WORK(&fbi->task, pxafb_task);
622 init_MUTEX(&fbi->ctrlr_sem);
623@@ -1268,6 +1452,10 @@
624 case 4:
625 case 8:
626 case 16:
627+ case 18:
628+ case 19:
629+ case 24:
630+ case 25:
631 inf->modes[0].bpp = bpp;
632 dev_info(dev, "overriding bit depth: %d\n", bpp);
633 break;
634@@ -1416,7 +1604,7 @@
635 fbi = pxafb_init_fbinfo(&dev->dev);
636 if (!fbi) {
637 dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
638- ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
639+ ret = -ENOMEM; /* only reason for pxafb_init_fbinfo to fail is kmalloc */
640 goto failed;
641 }
642
643@@ -1451,7 +1639,7 @@
644 }
645
646 #ifdef CONFIG_PM
647- // TODO
648+ /* TODO */
649 #endif
650
651 #ifdef CONFIG_CPU_FREQ
652@@ -1464,7 +1652,12 @@
653 /*
654 * Ok, now enable the LCD controller
655 */
656- set_ctrlr_state(fbi, C_ENABLE);
657+ pxafb_set_ctrlr_state(fbi, C_ENABLE);
658+//#ifdef CONFIG_PXA27x
659+// LCCR4 |= (1 << 31); /* Disabel the PCD Divisor, PCDDIV */
660+// LCCR4 |= (5 << 17); /* Undocumented feature */
661+//#endif
662+ init_waitqueue_head(&fcs_wait_eof);
663
664 return 0;
665
666--- linux-2.6.24-rc1.orig/drivers/video/pxafb.h
667+++ linux-2.6.24-rc1/drivers/video/pxafb.h
668@@ -29,6 +29,60 @@
669 unsigned int lccr3;
670 };
671
672+struct pxafb_rgb {
673+ struct fb_bitfield red;
674+ struct fb_bitfield green;
675+ struct fb_bitfield blue;
676+ struct fb_bitfield transp;
677+};
678+
679+#ifdef CONFIG_PXA27x
680+/* PXA Overlay Framebuffer Support */
681+struct overlayfb_info
682+{
683+ struct fb_info fb;
684+
685+ struct fb_var_screeninfo old_var;
686+
687+ struct semaphore mutex;
688+ unsigned long refcount;
689+
690+ struct pxafb_info *basefb;
691+
692+ unsigned long map_cpu;
693+ unsigned long screen_cpu;
694+ unsigned long palette_cpu;
695+ unsigned long map_size;
696+ unsigned long palette_size;
697+
698+ dma_addr_t screen_dma;
699+ dma_addr_t map_dma;
700+ dma_addr_t palette_dma;
701+
702+ volatile u_char state;
703+
704+ /* overlay specific info */
705+ unsigned long xpos; /* screen position (x, y)*/
706+ unsigned long ypos;
707+ unsigned long format;
708+
709+ /* additional */
710+ union {
711+ struct pxafb_dma_descriptor *dma0;
712+ struct pxafb_dma_descriptor *dma1;
713+ struct {
714+ struct pxafb_dma_descriptor *dma2;
715+ struct pxafb_dma_descriptor *dma3;
716+ struct pxafb_dma_descriptor *dma4;
717+ };
718+ struct {
719+ struct pxafb_dma_descriptor *dma5_pal;
720+ struct pxafb_dma_descriptor *dma5_frame;
721+ };
722+ };
723+};
724+#endif
725+
726 /* PXA LCD DMA descriptor */
727 struct pxafb_dma_descriptor {
728 unsigned int fdadr;
729@@ -90,6 +144,14 @@
730 wait_queue_head_t ctrlr_wait;
731 struct work_struct task;
732
733+#ifdef CONFIG_PXA27x
734+ /* PXA Overlay Framebuffer Support */
735+ struct overlayfb_info *overlay1fb;
736+ struct overlayfb_info *overlay2fb;
737+ struct overlayfb_info *cursorfb;
738+#endif
739+ void (*set_overlay_ctrlr_state)(struct pxafb_info *, u_int);
740+
741 #ifdef CONFIG_CPU_FREQ
742 struct notifier_block freq_transition;
743 struct notifier_block freq_policy;
744@@ -109,6 +171,9 @@
745 #define C_DISABLE_PM (5)
746 #define C_ENABLE_PM (6)
747 #define C_STARTUP (7)
748+#define C_BLANK (8)
749+#define C_UNBLANK (9)
750+
751
752 #define PXA_NAME "PXA"
753
754--- /dev/null
755+++ linux-2.6.24-rc1/drivers/video/pxafb_overlay.c
756@@ -0,0 +1,1525 @@
757+/*
758+ * linux/drivers/video/pxafb_overlay.c
759+ *
760+ * Copyright (c) 2004, Intel Corporation
761+ *
762+ * Code Status:
763+ * 2004/10/28: <yan.yin@intel.com>
764+ * - Ported to 2.6 kernel
765+ * - Made overlay driver a loadable module
766+ * - Merged overlay optimized patch
767+ * 2004/03/10: <stanley.cai@intel.com>
768+ * - Fixed Bugs
769+ * - Added workaround for overlay1&2
770+ * 2003/08/27: <yu.tang@intel.com>
771+ * - Added Overlay 1 & Overlay2 & Hardware Cursor support
772+ *
773+ *
774+ * This software program is licensed subject to the GNU Lesser General
775+ * Public License (LGPL). Version 2.1, February 1999, available at
776+ * http://www.gnu.org/copyleft/lesser.html
777+ *
778+ * Intel PXA27x LCD Controller Frame Buffer Overlay Driver
779+ *
780+ *
781+ */
782+
783+#include <linux/module.h>
784+#include <linux/moduleparam.h>
785+#include <linux/kernel.h>
786+#include <linux/sched.h>
787+#include <linux/errno.h>
788+#include <linux/string.h>
789+#include <linux/interrupt.h>
790+#include <linux/slab.h>
791+#include <linux/fb.h>
792+#include <linux/delay.h>
793+#include <linux/init.h>
794+#include <linux/ioport.h>
795+#include <linux/cpufreq.h>
796+#include <linux/device.h>
797+#include <linux/platform_device.h>
798+#include <linux/dma-mapping.h>
799+
800+#include <asm/hardware.h>
801+#include <asm/io.h>
802+#include <asm/irq.h>
803+#include <asm/uaccess.h>
804+#include <asm/arch/bitfield.h>
805+#include <asm/arch/pxafb.h>
806+#include <asm/arch/pxa-regs.h>
807+
808+#include "pxafb.h"
809+
810+/* LCD enhancement : Overlay 1 & 2 & Hardware Cursor */
811+
812+/*
813+ * LCD enhancement : Overlay 1
814+ *
815+ * Features:
816+ * - support 16bpp (No palette)
817+ */
818+/*
819+ * debugging?
820+ */
821+#define DEBUG 0
822+
823+#ifdef DEBUG
824+#define dbg(fmt,arg...) printk(KERN_ALERT "%s(): " fmt "\n", __FUNCTION__, ##arg)
825+#else
826+#define dbg(fmt,arg...)
827+#endif
828+
829+static int overlay1fb_enable(struct fb_info *info);
830+static int overlay2fb_enable(struct fb_info *info);
831+static int cursorfb_enable(struct fb_info *info);
832+
833+static int overlay1fb_disable(struct fb_info *info);
834+static int overlay2fb_disable(struct fb_info *info);
835+static int cursorfb_disable(struct fb_info *info);
836+
837+static int overlay1fb_blank(int blank, struct fb_info *info);
838+static int overlay2fb_blank(int blank, struct fb_info *info);
839+static int cursorfb_blank(int blank, struct fb_info *info);
840+
841+extern void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state);
842+extern int pxafb_blank(int blank, struct fb_info *info);
843+
844+static struct pxafb_rgb def_rgb_18 = {
845+ red: { offset: 12, length: 6, },
846+ green: { offset: 6, length: 6, },
847+ blue: { offset: 0, length: 6, },
848+ transp: { offset: 0, length: 0, },
849+};
850+
851+static struct pxafb_rgb def_rgbt_16 = {
852+ red: { offset: 10, length: 5, },
853+ green: { offset: 5, length: 5, },
854+ blue: { offset: 0, length: 5, },
855+ transp: { offset: 15, length: 1, },
856+};
857+
858+static struct pxafb_rgb def_rgbt_19 = {
859+ red: { offset: 12, length: 6, },
860+ green: { offset: 6, length: 6, },
861+ blue: { offset: 0, length: 6, },
862+ transp: { offset: 18, length: 1, },
863+};
864+
865+static struct pxafb_rgb def_rgbt_24 = {
866+ red: { offset: 16, length: 7, },
867+ green: { offset: 8, length: 8, },
868+ blue: { offset: 0, length: 8, },
869+ transp: { offset: 0, length: 0, },
870+};
871+
872+static struct pxafb_rgb def_rgbt_25 = {
873+ red: { offset: 16, length: 8, },
874+ green: { offset: 8, length: 8, },
875+ blue: { offset: 0, length: 8, },
876+ transp: { offset: 24, length: 1, },
877+};
878+
879+#define CLEAR_LCD_INTR(reg, intr) do { \
880+ reg = (intr); \
881+}while(0)
882+
883+#define WAIT_FOR_LCD_INTR(reg,intr,timeout) ({ \
884+ int __done =0; \
885+ int __t = timeout; \
886+ while (__t) { \
887+ __done = (reg) & (intr); \
888+ if (__done) break; \
889+ mdelay(10); \
890+ __t--; \
891+ } \
892+ if (!__t) dbg("wait " #intr " timeount");\
893+ __done; \
894+})
895+
896+#define DISABLE_OVERLAYS(fbi) do { \
897+ if (fbi->overlay1fb && (fbi->overlay1fb->state == C_ENABLE)) { \
898+ overlay1fb_disable((struct fb_info*)fbi->overlay1fb); \
899+ } \
900+ if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)) { \
901+ overlay2fb_disable((struct fb_info*)fbi->overlay2fb); \
902+ } \
903+ if (fbi->cursorfb && (fbi->cursorfb->state == C_ENABLE)) { \
904+ cursorfb_disable((struct fb_info*)fbi->cursorfb); \
905+ } \
906+}while(0)
907+
908+#define ENABLE_OVERLAYS(fbi) do { \
909+ if (fbi->overlay1fb && (fbi->overlay1fb->state == C_DISABLE)) { \
910+ overlay1fb_enable((struct fb_info*)fbi->overlay1fb); \
911+ } \
912+ if (fbi->overlay2fb && (fbi->overlay2fb->state == C_DISABLE)) { \
913+ overlay2fb_enable((struct fb_info*)fbi->overlay2fb); \
914+ } \
915+ if (fbi->cursorfb && (fbi->cursorfb->state == C_DISABLE)) { \
916+ cursorfb_enable((struct fb_info*)fbi->cursorfb); \
917+ } \
918+}while(0)
919+
920+#define BLANK_OVERLAYS(fbi) do { \
921+ if (fbi->overlay1fb && (fbi->overlay1fb->state == C_ENABLE)) { \
922+ overlay1fb_disable((struct fb_info*)fbi->overlay1fb); \
923+ fbi->overlay1fb->state = C_BLANK; \
924+ } \
925+ if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)) { \
926+ overlay2fb_disable((struct fb_info*)fbi->overlay2fb); \
927+ fbi->overlay2fb->state = C_BLANK; \
928+ } \
929+ if (fbi->cursorfb && (fbi->cursorfb->state == C_ENABLE)) { \
930+ cursorfb_disable((struct fb_info*)fbi->cursorfb); \
931+ fbi->cursorfb->state = C_BLANK; \
932+ } \
933+}while(0)
934+
935+#define UNBLANK_OVERLAYS(fbi) do { \
936+ if (fbi->overlay1fb && (fbi->overlay1fb->state == C_BLANK)) { \
937+ overlay1fb_enable((struct fb_info*)fbi->overlay1fb); \
938+ fbi->overlay1fb->state = C_ENABLE; \
939+ } \
940+ if (fbi->overlay2fb && (fbi->overlay2fb->state == C_BLANK)) { \
941+ overlay2fb_enable((struct fb_info*)fbi->overlay2fb); \
942+ fbi->overlay2fb->state = C_ENABLE; \
943+ } \
944+ if (fbi->cursorfb && (fbi->cursorfb->state == C_BLANK)) { \
945+ cursorfb_enable((struct fb_info*)fbi->cursorfb); \
946+ fbi->cursorfb->state = C_ENABLE; \
947+ } \
948+}while(0)
949+
950+static int overlay1fb_open(struct fb_info *info, int user)
951+{
952+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
953+ int ret = 0;
954+
955+/* If basefb is disable, enable fb. */
956+ if (fbi->basefb && fbi->basefb->state != C_ENABLE)
957+ pxafb_blank(VESA_NO_BLANKING, (struct fb_info *)(fbi->basefb));
958+
959+ down(&fbi->mutex);
960+
961+ if (fbi->refcount)
962+ ret = -EACCES;
963+ else
964+ fbi->refcount ++;
965+
966+ up(&fbi->mutex);
967+
968+ /* Initialize the variables in overlay1 framebuffer. */
969+ fbi->fb.var.xres = fbi->fb.var.yres = 0;
970+ fbi->fb.var.bits_per_pixel = 0;
971+
972+ return ret;
973+}
974+
975+static int overlay1fb_release(struct fb_info *info, int user)
976+{
977+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
978+ down(&fbi->mutex);
979+
980+ if (fbi->refcount)
981+ fbi->refcount --;
982+
983+ up(&fbi->mutex);
984+ /* disable overlay when released */
985+ overlay1fb_blank(1, info);
986+
987+ return 0;
988+}
989+
990+static int overlay1fb_map_video_memory(struct fb_info *info)
991+{
992+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
993+
994+ if (fbi->map_cpu)
995+ dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu, fbi->map_dma);
996+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
997+
998+ fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
999+ &fbi->map_dma, GFP_KERNEL );
1000+
1001+ if (!fbi->map_cpu) return -ENOMEM;
1002+
1003+ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
1004+ fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1005+
1006+ fbi->fb.fix.smem_start = fbi->screen_dma;
1007+
1008+ /* setup dma descriptor */
1009+ fbi->dma1 = (struct pxafb_dma_descriptor*)
1010+ (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
1011+
1012+ fbi->dma1->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
1013+ fbi->dma1->fsadr = fbi->screen_dma;
1014+ fbi->dma1->fidr = 0;
1015+ fbi->dma1->ldcmd = fbi->fb.fix.smem_len;
1016+
1017+ return 0;
1018+}
1019+
1020+static int overlay1fb_enable(struct fb_info *info)
1021+{
1022+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1023+ unsigned long bpp1;
1024+
1025+ if (!fbi->map_cpu) return -EINVAL;
1026+
1027+ switch (fbi->fb.var.bits_per_pixel) {
1028+ case 16:
1029+ bpp1 = 0x4;
1030+ break;
1031+ case 18:
1032+ bpp1 = 0x6;
1033+ break;
1034+ case 19:
1035+ bpp1 = 0x8;
1036+ break;
1037+ case 24:
1038+ bpp1 = 0x9;
1039+ break;
1040+ case 25:
1041+ bpp1 = 0xa;
1042+ break;
1043+ default:
1044+ return -EINVAL;
1045+ }
1046+
1047+ /* disable branch/start/end of frame interrupt */
1048+ LCCR5 |= (LCCR5_IUM1 | LCCR5_BSM1 | LCCR5_EOFM1 | LCCR5_SOFM1);
1049+
1050+ if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
1051+ FDADR1 = (fbi->dma1->fdadr);
1052+ else
1053+ FBR1 = fbi->dma1->fdadr | 0x1;
1054+
1055+ /* enable overlay 1 window */
1056+ OVL1C2 = (fbi->ypos << 10) | fbi->xpos;
1057+ OVL1C1 = OVL1C1_O1EN | (bpp1 << 20) | ((fbi->fb.var.yres-1)<<10) | (fbi->fb.var.xres-1);
1058+
1059+ fbi->state = C_ENABLE;
1060+
1061+ return 0;
1062+}
1063+
1064+static int overlay1fb_disable(struct fb_info *info)
1065+{
1066+ struct overlayfb_info *fbi = (struct overlayfb_info*)info;
1067+ int done;
1068+
1069+ if ((fbi->state == C_DISABLE) || (fbi->state == C_BLANK))
1070+ return 0;
1071+
1072+ fbi->state = C_DISABLE;
1073+
1074+ /* clear O1EN */
1075+ OVL1C1 &= ~OVL1C1_O1EN;
1076+
1077+ CLEAR_LCD_INTR(LCSR1, LCSR1_BS1);
1078+ FBR1 = 0x3;
1079+ done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS1, 100);
1080+
1081+ if (!done) {
1082+ pr_debug(KERN_INFO "%s: timeout\n", __FUNCTION__);
1083+ return -1;
1084+ }
1085+ return 0;
1086+}
1087+
1088+static int overlay1fb_blank(int blank, struct fb_info *info)
1089+{
1090+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1091+ int err=0;
1092+
1093+ switch (blank) {
1094+ case 0:
1095+ err = overlay1fb_enable(info);
1096+ if (err) {
1097+ fbi->state = C_DISABLE;
1098+ pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
1099+ }
1100+ break;
1101+ case 1:
1102+ err = overlay1fb_disable(info);
1103+ if (err) {
1104+ fbi->state = C_DISABLE;
1105+ pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
1106+ }
1107+ break;
1108+ default:
1109+ break;
1110+ }
1111+
1112+ return err;
1113+}
1114+
1115+static int overlay1fb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
1116+{
1117+ int xpos, ypos;
1118+ struct overlayfb_info *fbi=(struct overlayfb_info*)info;
1119+
1120+ /* must in base frame */
1121+ xpos = (var->nonstd & 0x3ff);
1122+ ypos = ((var->nonstd>>10) & 0x3ff);
1123+
1124+ if ( (xpos + var->xres) > fbi->basefb->fb.var.xres )
1125+ return -EINVAL;
1126+
1127+ if ( (ypos + var->yres) > fbi->basefb->fb.var.yres )
1128+ return -EINVAL;
1129+
1130+ switch (var->bits_per_pixel) {
1131+ case 16:
1132+ if ( var->xres & 0x1 ) {
1133+ printk("xres should be a multiple of 2 pixels!\n");
1134+ return -EINVAL;
1135+ }
1136+ break;
1137+ case 18:
1138+ case 19:
1139+ if ( var->xres & 0x7 ) {
1140+ printk("xres should be a multiple of 8 pixels!\n");
1141+ return -EINVAL;
1142+ }
1143+ break;
1144+ default:
1145+ break;
1146+ }
1147+
1148+ fbi->old_var=*var;
1149+
1150+ var->activate=FB_ACTIVATE_NOW;
1151+
1152+ return 0;
1153+}
1154+
1155+
1156+static int overlay1fb_set_par(struct fb_info *info)
1157+{
1158+ int nbytes=0, err=0, pixels_per_line=0;
1159+
1160+ struct overlayfb_info *fbi=(struct overlayfb_info*)info;
1161+ struct fb_var_screeninfo *var = &fbi->fb.var;
1162+
1163+ info->flags &= ~FBINFO_MISC_USEREVENT;
1164+
1165+ if (fbi->state == C_BLANK)
1166+ return 0;
1167+
1168+ if (fbi->state == C_DISABLE)
1169+ goto out1;
1170+
1171+ /* only xpos & ypos change */
1172+ if ( (var->xres == fbi->old_var.xres) &&
1173+ (var->yres == fbi->old_var.yres) &&
1174+ (var->bits_per_pixel == fbi->old_var.bits_per_pixel) )
1175+ goto out2;
1176+
1177+out1:
1178+ switch(var->bits_per_pixel) {
1179+ case 16:
1180+ /* 2 pixels per line */
1181+ pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
1182+ nbytes = 2;
1183+
1184+ var->red = def_rgbt_16.red;
1185+ var->green = def_rgbt_16.green;
1186+ var->blue = def_rgbt_16.blue;
1187+ var->transp = def_rgbt_16.transp;
1188+
1189+ break;
1190+ case 18:
1191+ /* 8 pixels per line */
1192+ pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
1193+ nbytes = 3;
1194+
1195+ var->red = def_rgb_18.red;
1196+ var->green = def_rgb_18.green;
1197+ var->blue = def_rgb_18.blue;
1198+ var->transp = def_rgb_18.transp;
1199+
1200+ break;
1201+ case 19:
1202+ /* 8 pixels per line */
1203+ pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
1204+ nbytes = 3;
1205+
1206+ var->red = def_rgbt_19.red;
1207+ var->green = def_rgbt_19.green;
1208+ var->blue = def_rgbt_19.blue;
1209+ var->transp = def_rgbt_19.transp;
1210+
1211+ break;
1212+ case 24:
1213+ pixels_per_line = fbi->fb.var.xres;
1214+ nbytes = 4;
1215+
1216+ var->red = def_rgbt_24.red;
1217+ var->green = def_rgbt_24.green;
1218+ var->blue = def_rgbt_24.blue;
1219+ var->transp = def_rgbt_24.transp;
1220+
1221+ break;
1222+ case 25:
1223+ pixels_per_line = fbi->fb.var.xres;
1224+ nbytes = 4;
1225+
1226+ var->red = def_rgbt_25.red;
1227+ var->green = def_rgbt_25.green;
1228+ var->blue = def_rgbt_25.blue;
1229+ var->transp = def_rgbt_25.transp;
1230+
1231+ break;
1232+ }
1233+
1234+ fbi->fb.fix.line_length = nbytes * pixels_per_line;
1235+ fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
1236+
1237+ err= overlay1fb_map_video_memory((struct fb_info*)fbi);
1238+
1239+ if (err)
1240+ return err;
1241+
1242+out2:
1243+ fbi->xpos = var->nonstd & 0x3ff;
1244+ fbi->ypos = (var->nonstd>>10) & 0x3ff;
1245+
1246+ overlay1fb_enable(info);
1247+
1248+ return 0;
1249+
1250+}
1251+
1252+static struct fb_ops overlay1fb_ops = {
1253+ .owner = THIS_MODULE,
1254+ .fb_open = overlay1fb_open,
1255+ .fb_release = overlay1fb_release,
1256+ .fb_check_var = overlay1fb_check_var,
1257+ .fb_set_par = overlay1fb_set_par,
1258+ .fb_blank = overlay1fb_blank,
1259+ .fb_fillrect = cfb_fillrect,
1260+ .fb_copyarea = cfb_copyarea,
1261+ .fb_imageblit = cfb_imageblit,
1262+};
1263+
1264+ /*
1265+ * LCD enhancement : Overlay 2
1266+ *
1267+ * Features:
1268+ * - support planar YCbCr420/YCbCr422/YCbCr444;
1269+ */
1270+static int overlay2fb_open(struct fb_info *info, int user)
1271+{
1272+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1273+ int ret = 0;
1274+
1275+ /* if basefb is disable, enable fb. */
1276+ if (fbi->basefb && fbi->basefb->state != C_ENABLE)
1277+ pxafb_blank(VESA_NO_BLANKING, (struct fb_info *)(fbi->basefb));
1278+
1279+ down(&fbi->mutex);
1280+
1281+ if (fbi->refcount)
1282+ ret = -EACCES;
1283+ else
1284+ fbi->refcount ++;
1285+
1286+ up(&fbi->mutex);
1287+ fbi->fb.var.xres = fbi->fb.var.yres = 0;
1288+
1289+ return ret;
1290+}
1291+
1292+static int overlay2fb_release(struct fb_info *info, int user)
1293+{
1294+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1295+
1296+ down(&fbi->mutex);
1297+
1298+ if (fbi->refcount)
1299+ fbi->refcount --;
1300+
1301+ up(&fbi->mutex);
1302+
1303+ /* disable overlay when released */
1304+ overlay2fb_blank(1, info);
1305+
1306+ return 0;
1307+}
1308+
1309+static int overlay2fb_map_YUV_memory( struct fb_info *info)
1310+{
1311+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1312+ unsigned int ylen, cblen, crlen, aylen, acblen, acrlen;
1313+ unsigned int yoff, cboff, croff;
1314+ unsigned int xres,yres;
1315+ unsigned int nbytes;
1316+
1317+ ylen = cblen = crlen = aylen = acblen = acrlen = 0;
1318+ yoff = cboff = croff = 0;
1319+
1320+ if (fbi->map_cpu)
1321+ dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu, fbi->map_dma);
1322+
1323+ yres = fbi->fb.var.yres;
1324+
1325+ switch(fbi->format) {
1326+ case 0x4: /* YCbCr 4:2:0 planar */
1327+ pr_debug("420 planar\n");
1328+ /* 16 pixels per line */
1329+ xres = (fbi->fb.var.xres + 0xf) & (~0xf);
1330+ fbi->fb.fix.line_length = xres;
1331+
1332+ nbytes = xres * yres;
1333+ ylen = nbytes;
1334+ cblen = crlen = (nbytes/4);
1335+
1336+ break;
1337+ case 0x3: /* YCbCr 4:2:2 planar */
1338+ /* 8 pixles per line */
1339+ pr_debug("422 planar\n");
1340+ xres = (fbi->fb.var.xres + 0x7) & (~0x7);
1341+ fbi->fb.fix.line_length = xres;
1342+
1343+ nbytes = xres * yres;
1344+ ylen = nbytes;
1345+ cblen = crlen = (nbytes/2);
1346+
1347+ break;
1348+ case 0x2: /* YCbCr 4:4:4 planar */
1349+ /* 4 pixels per line */
1350+ pr_debug("444 planar\n");
1351+ xres = (fbi->fb.var.xres + 0x3) & (~0x3);
1352+ fbi->fb.fix.line_length = xres;
1353+
1354+ nbytes = xres * yres;
1355+ ylen = cblen = crlen = nbytes;
1356+ break;
1357+ }
1358+
1359+ /* 16-bytes alignment for DMA */
1360+ aylen = (ylen + 0xf) & (~0xf);
1361+ acblen = (cblen + 0xf) & (~0xf);
1362+ acrlen = (crlen + 0xf) & (~0xf);
1363+
1364+ fbi->fb.fix.smem_len = aylen + acblen + acrlen;
1365+
1366+ /* alloc memory */
1367+
1368+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
1369+ fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
1370+ &fbi->map_dma, GFP_KERNEL );
1371+
1372+ if (!fbi->map_cpu) return -ENOMEM;
1373+
1374+ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
1375+ fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1376+
1377+ fbi->fb.fix.smem_start = fbi->screen_dma;
1378+
1379+ /* setup dma for Planar format */
1380+ fbi->dma2 = (struct pxafb_dma_descriptor*)
1381+ (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
1382+ fbi->dma3 = fbi->dma2 - 1;
1383+ fbi->dma4 = fbi->dma3 - 1;
1384+
1385+ /* offset */
1386+ yoff = 0;
1387+ cboff = aylen;
1388+ croff = cboff + acblen;
1389+
1390+ /* Y vector */
1391+ fbi->dma2->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
1392+ fbi->dma2->fsadr = fbi->screen_dma + yoff;
1393+ fbi->dma2->fidr = 0;
1394+ fbi->dma2->ldcmd = ylen;
1395+
1396+ /* Cb vector */
1397+ fbi->dma3->fdadr = (fbi->dma2->fdadr - sizeof(struct pxafb_dma_descriptor));
1398+ fbi->dma3->fsadr = (fbi->screen_dma + cboff);
1399+ fbi->dma3->fidr = 0;
1400+ fbi->dma3->ldcmd = cblen;
1401+
1402+ /* Cr vector */
1403+
1404+ fbi->dma4->fdadr = (fbi->dma3->fdadr - sizeof(struct pxafb_dma_descriptor));
1405+ fbi->dma4->fsadr = (fbi->screen_dma + croff);
1406+ fbi->dma4->fidr = 0;
1407+ fbi->dma4->ldcmd = crlen;
1408+
1409+ /* adjust for user */
1410+ fbi->fb.var.red.length = ylen;
1411+ fbi->fb.var.red.offset = yoff;
1412+ fbi->fb.var.green.length = cblen;
1413+ fbi->fb.var.green.offset = cboff;
1414+ fbi->fb.var.blue.length = crlen;
1415+ fbi->fb.var.blue.offset = croff;
1416+
1417+ return 0;
1418+};
1419+
1420+static int overlay2fb_map_RGB_memory( struct fb_info *info)
1421+{
1422+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1423+ struct fb_var_screeninfo *var = &fbi->fb.var;
1424+ int pixels_per_line=0 , nbytes=0;
1425+
1426+ if (fbi->map_cpu)
1427+ dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu, fbi->map_dma);
1428+
1429+ switch(var->bits_per_pixel) {
1430+ case 16:
1431+ /* 2 pixels per line */
1432+ pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
1433+ nbytes = 2;
1434+
1435+ var->red = def_rgbt_16.red;
1436+ var->green = def_rgbt_16.green;
1437+ var->blue = def_rgbt_16.blue;
1438+ var->transp = def_rgbt_16.transp;
1439+ break;
1440+
1441+ case 18:
1442+ /* 8 pixels per line */
1443+ pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
1444+ nbytes = 3;
1445+
1446+ var->red = def_rgb_18.red;
1447+ var->green = def_rgb_18.green;
1448+ var->blue = def_rgb_18.blue;
1449+ var->transp = def_rgb_18.transp;
1450+
1451+ break;
1452+ case 19:
1453+ /* 8 pixels per line */
1454+ pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
1455+ nbytes = 3;
1456+
1457+ var->red = def_rgbt_19.red;
1458+ var->green = def_rgbt_19.green;
1459+ var->blue = def_rgbt_19.blue;
1460+ var->transp = def_rgbt_19.transp;
1461+
1462+ break;
1463+ case 24:
1464+ pixels_per_line = fbi->fb.var.xres;
1465+ nbytes = 4;
1466+
1467+ var->red = def_rgbt_24.red;
1468+ var->green = def_rgbt_24.green;
1469+ var->blue = def_rgbt_24.blue;
1470+ var->transp = def_rgbt_24.transp;
1471+
1472+ break;
1473+
1474+ case 25:
1475+ pixels_per_line = fbi->fb.var.xres;
1476+ nbytes = 4;
1477+
1478+ var->red = def_rgbt_25.red;
1479+ var->green = def_rgbt_25.green;
1480+ var->blue = def_rgbt_25.blue;
1481+ var->transp = def_rgbt_25.transp;
1482+
1483+ break;
1484+ }
1485+
1486+ fbi->fb.fix.line_length = nbytes * pixels_per_line;
1487+ fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
1488+
1489+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
1490+ fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
1491+ &fbi->map_dma, GFP_KERNEL );
1492+
1493+ if (!fbi->map_cpu) return -ENOMEM;
1494+
1495+ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
1496+ fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1497+
1498+ fbi->fb.fix.smem_start = fbi->screen_dma;
1499+
1500+ /* setup dma descriptor */
1501+ fbi->dma2 = (struct pxafb_dma_descriptor*)
1502+ (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
1503+
1504+ fbi->dma2->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
1505+ fbi->dma2->fsadr = fbi->screen_dma;
1506+ fbi->dma2->fidr = 0;
1507+ fbi->dma2->ldcmd = fbi->fb.fix.smem_len;
1508+
1509+ return 0;
1510+}
1511+
1512+static int overlay2fb_enable(struct fb_info *info)
1513+{
1514+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1515+ unsigned long bpp2;
1516+ unsigned int xres, yres;
1517+
1518+ if (!fbi->map_cpu) return -EINVAL;
1519+
1520+ switch(fbi->fb.var.bits_per_pixel) {
1521+ case 16:
1522+ bpp2 = 0x4;
1523+ break;
1524+ case 18:
1525+ bpp2 = 0x6;
1526+ break;
1527+ case 19:
1528+ bpp2 = 0x8;
1529+ break;
1530+ case 24:
1531+ bpp2 = 0x9;
1532+ break;
1533+ case 25:
1534+ bpp2 = 0xa;
1535+ break;
1536+ default:
1537+ return -EINVAL;
1538+ }
1539+
1540+ /* disable branch/start/end of frame interrupt */
1541+ LCCR5 |= (LCCR5_IUM4 | LCCR5_IUM3 | LCCR5_IUM2 |
1542+ LCCR5_BSM4 | LCCR5_BSM3 | LCCR5_BSM2 |
1543+ LCCR5_EOFM4 | LCCR5_EOFM3 | LCCR5_EOFM2 |
1544+ LCCR5_SOFM4 | LCCR5_SOFM3 | LCCR5_SOFM2);
1545+
1546+ if (fbi->format == 0) {
1547+ /* overlay2 RGB resolution, RGB and YUV have different xres value*/
1548+ xres = fbi->fb.var.xres;
1549+ yres = fbi->fb.var.yres;
1550+
1551+ OVL2C2 = (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos;
1552+ OVL2C1 = OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1);
1553+ /* setup RGB DMA */
1554+ if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
1555+ FDADR2 = fbi->dma2->fdadr;
1556+ else
1557+ FBR2 = fbi->dma2->fdadr | 0x1;
1558+ } else {
1559+ /* overlay2 YUV resolution */
1560+ xres = fbi->fb.fix.line_length;
1561+ yres = fbi->fb.var.yres;
1562+
1563+ OVL2C2 = (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos;
1564+ OVL2C1 = OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1);
1565+
1566+ if (fbi->state == C_DISABLE || fbi->state == C_BLANK) {
1567+ FDADR2 = fbi->dma2->fdadr;
1568+ FDADR3 = fbi->dma3->fdadr;
1569+ FDADR4 = fbi->dma4->fdadr;
1570+ } else {
1571+ FBR2 = fbi->dma2->fdadr | 0x01;
1572+ FBR3 = fbi->dma3->fdadr | 0x01;
1573+ FBR4 = fbi->dma4->fdadr | 0x01;
1574+ }
1575+ }
1576+
1577+ fbi->state = C_ENABLE;
1578+ return 0;
1579+}
1580+
1581+static int overlay2fb_disable(struct fb_info *info)
1582+{
1583+ struct overlayfb_info *fbi = (struct overlayfb_info*)info;
1584+ int done;
1585+
1586+ if (fbi->state == C_DISABLE)
1587+ return 0;
1588+ if (fbi->state == C_BLANK) {
1589+ fbi->state = C_DISABLE;
1590+ return 0;
1591+ }
1592+
1593+ fbi->state = C_DISABLE;
1594+
1595+ /* clear O2EN */
1596+ OVL2C1 &= ~OVL2C1_O2EN;
1597+
1598+ /* Make overlay2 can't disable/enable
1599+ * correctly sometimes.
1600+ */
1601+ CLEAR_LCD_INTR(LCSR1, LCSR1_BS2);
1602+
1603+ if (fbi->format == 0)
1604+ FBR2 = 0x3;
1605+ else {
1606+ FBR2 = 0x3;
1607+ FBR3 = 0x3;
1608+ FBR4 = 0x3;
1609+ }
1610+
1611+ done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS2, 100);
1612+
1613+ if (!done) {
1614+ pr_debug(KERN_INFO "%s: timeout\n", __FUNCTION__);
1615+ return -1;
1616+ }
1617+ return 0;
1618+}
1619+
1620+static int overlay2fb_blank(int blank, struct fb_info *info)
1621+{
1622+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1623+ int err=0;
1624+
1625+ switch(blank)
1626+ {
1627+ case 0:
1628+ err = overlay2fb_enable(info);
1629+ if (err) {
1630+ fbi->state = C_DISABLE;
1631+ pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
1632+ }
1633+ break;
1634+ case 1:
1635+ err = overlay2fb_disable(info);
1636+ if (err) {
1637+ fbi->state = C_DISABLE;
1638+ pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
1639+ }
1640+ break;
1641+ default:
1642+ /* reserved */
1643+ break;
1644+ }
1645+
1646+ return err;
1647+}
1648+
1649+
1650+static int overlay2fb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
1651+{
1652+ int xpos, ypos, xres, yres;
1653+ int format;
1654+ struct overlayfb_info *fbi=(struct overlayfb_info*)info;
1655+
1656+ xres=yres=0;
1657+
1658+ xpos = (var->nonstd & 0x3ff);
1659+ ypos = (var->nonstd >> 10) & 0x3ff;
1660+ format = (var->nonstd >>20) & 0x7;
1661+
1662+
1663+ /* Palnar YCbCr444, YCbCr422, YCbCr420 */
1664+ if ( (format != 0x4) && (format != 0x3) && (format != 0x2) && (format !=0x0))
1665+ return -EINVAL;
1666+
1667+ /* dummy pixels */
1668+ switch(format) {
1669+ case 0x0: /* RGB */
1670+ xres = var->xres;
1671+ break;
1672+ case 0x2: /* 444 */
1673+ xres = (var->xres + 0x3) & ~(0x3);
1674+ break;
1675+ case 0x3: /* 422 */
1676+ xres = (var->xres + 0x7) & ~(0x7);
1677+ break;
1678+ case 0x4: /* 420 */
1679+ xres = (var->xres + 0xf) & ~(0xf);
1680+ break;
1681+ }
1682+ yres = var->yres;
1683+
1684+ if ( (xpos + xres) > fbi->basefb->fb.var.xres )
1685+ return -EINVAL;
1686+
1687+ if ( (ypos + yres) > fbi->basefb->fb.var.yres )
1688+ return -EINVAL;
1689+
1690+ fbi->old_var=*var;
1691+
1692+ var->activate=FB_ACTIVATE_NOW;
1693+
1694+ return 0;
1695+
1696+}
1697+
1698+
1699+/*
1700+ * overlay2fb_set_var()
1701+ *
1702+ * var.nonstd is used as YCbCr format.
1703+ * var.red/green/blue is used as (Y/Cb/Cr) vector
1704+ */
1705+
1706+static int overlay2fb_set_par(struct fb_info *info)
1707+{
1708+ unsigned int xpos, ypos;
1709+ int format, err;
1710+
1711+ struct overlayfb_info *fbi=(struct overlayfb_info*)info;
1712+ struct fb_var_screeninfo *var = &fbi->fb.var;
1713+
1714+ info->flags &= ~FBINFO_MISC_USEREVENT;
1715+
1716+ if (fbi->state == C_BLANK)
1717+ return 0;
1718+
1719+ if (fbi->state == C_DISABLE)
1720+ goto out1;
1721+
1722+ if ( (var->xres == fbi->old_var.xres) &&
1723+ (var->yres == fbi->old_var.yres) &&
1724+ (var->bits_per_pixel == fbi->old_var.bits_per_pixel) &&
1725+ (((var->nonstd>>20) & 0x7) == fbi->format) )
1726+ goto out2;
1727+
1728+out1:
1729+ xpos = var->nonstd & 0x3ff;
1730+ ypos = (var->nonstd>>10) & 0x3ff;
1731+ format = (var->nonstd>>20) & 0x7;
1732+
1733+
1734+ fbi->format = format;
1735+ if ( fbi->format==0 )
1736+ err = overlay2fb_map_RGB_memory(info);
1737+ else
1738+ err = overlay2fb_map_YUV_memory(info);
1739+
1740+ if (err) return err;
1741+
1742+out2:
1743+ /* position */
1744+ fbi->xpos = var->nonstd & 0x3ff;
1745+ fbi->ypos = (var->nonstd>>10) & 0x3ff;
1746+
1747+ overlay2fb_enable(info);
1748+
1749+ return 0;
1750+}
1751+
1752+static struct fb_ops overlay2fb_ops = {
1753+ .owner = THIS_MODULE,
1754+ .fb_open = overlay2fb_open,
1755+ .fb_release = overlay2fb_release,
1756+ .fb_check_var = overlay2fb_check_var,
1757+ .fb_set_par = overlay2fb_set_par,
1758+ .fb_blank = overlay2fb_blank,
1759+ .fb_fillrect = cfb_fillrect,
1760+ .fb_copyarea = cfb_copyarea,
1761+ .fb_imageblit = cfb_imageblit,
1762+};
1763+
1764+/* Hardware cursor */
1765+
1766+/* Bulverde Cursor Modes */
1767+struct cursorfb_mode{
1768+ int xres;
1769+ int yres;
1770+ int bpp;
1771+};
1772+
1773+static struct cursorfb_mode cursorfb_modes[]={
1774+ { 32, 32, 2},
1775+ { 32, 32, 2},
1776+ { 32, 32, 2},
1777+ { 64, 64, 2},
1778+ { 64, 64, 2},
1779+ { 64, 64, 2},
1780+ {128, 128, 1},
1781+ {128, 128, 1}
1782+};
1783+
1784+static int cursorfb_enable(struct fb_info *info)
1785+{
1786+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1787+
1788+ if (!fbi->map_cpu) return -EINVAL;
1789+
1790+ CCR &= ~CCR_CEN;
1791+
1792+ /* set palette format
1793+ *
1794+ * FIXME: if only cursor uses palette
1795+ */
1796+ LCCR4 = (LCCR4 & (~(0x3<<15))) | (0x1<<15);
1797+
1798+ /* disable branch/start/end of frame interrupt */
1799+ LCCR5 |= (LCCR5_IUM5 | LCCR5_BSM5 | LCCR5_EOFM5 | LCCR5_SOFM5);
1800+
1801+ /* load palette and frame data */
1802+ if (fbi->state == C_DISABLE) {
1803+ FDADR5 = fbi->dma5_pal->fdadr;
1804+ udelay(1);
1805+ FDADR5 = fbi->dma5_frame->fdadr;
1806+ udelay(1);
1807+
1808+ }
1809+ else {
1810+ FBR5 = fbi->dma5_pal->fdadr | 0x1;
1811+ udelay(1);
1812+ FBR5 = fbi->dma5_frame->fdadr | 0x1;
1813+ udelay(1);
1814+ }
1815+
1816+ CCR = CCR_CEN | (fbi->ypos << 15) | (fbi->xpos << 5) | (fbi->format);
1817+
1818+ fbi->state = C_ENABLE;
1819+
1820+ return 0;
1821+}
1822+
1823+static int cursorfb_disable(struct fb_info *info)
1824+{
1825+ struct overlayfb_info *fbi = (struct overlayfb_info*)info;
1826+ int done, ret = 0;
1827+
1828+ fbi->state = C_DISABLE;
1829+
1830+ done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS5, 100);
1831+ if (!done) ret = -1;
1832+
1833+ CCR &= ~CCR_CEN;
1834+
1835+ return ret;
1836+}
1837+
1838+static int cursorfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1839+ u_int trans, struct fb_info *info)
1840+{
1841+ struct overlayfb_info *fbi = (struct overlayfb_info *)info;
1842+ u_int val, ret = 1;
1843+ u_int *pal=(u_int*) fbi->palette_cpu;
1844+
1845+ /* 25bit with Transparcy for 16bpp format */
1846+ if (regno < fbi->palette_size) {
1847+ val = ((trans << 24) & 0x1000000);
1848+ val |= ((red << 16) & 0x0ff0000);
1849+ val |= ((green << 8 ) & 0x000ff00);
1850+ val |= ((blue << 0) & 0x00000ff);
1851+
1852+ pal[regno] = val;
1853+ ret = 0;
1854+ }
1855+ return ret;
1856+}
1857+
1858+int cursorfb_blank(int blank, struct fb_info *info)
1859+{
1860+ switch(blank)
1861+ {
1862+ case 0:
1863+ cursorfb_enable(info);
1864+ break;
1865+ case 1:
1866+ cursorfb_disable(info);
1867+ break;
1868+ default:
1869+ /* reserved */
1870+ break;
1871+ }
1872+ return 0;
1873+}
1874+
1875+static int cursorfb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
1876+{
1877+ int xpos, ypos, xres, yres;
1878+ int mode;
1879+ struct cursorfb_mode *cursor;
1880+ struct overlayfb_info *fbi=(struct overlayfb_info*)info;
1881+
1882+ mode = var->nonstd & 0x7;
1883+ xpos = (var->nonstd>>5) & 0x3ff;
1884+ ypos = (var->nonstd>>15) & 0x3ff;
1885+
1886+ if (mode>7 || mode <0 )
1887+ return -EINVAL;
1888+
1889+ cursor = cursorfb_modes + mode;
1890+
1891+ xres = cursor->xres;
1892+ yres = cursor->yres;
1893+
1894+ if ( (xpos + xres) > fbi->basefb->fb.var.xres )
1895+ return -EINVAL;
1896+
1897+ if ( (ypos + yres) > fbi->basefb->fb.var.yres )
1898+ return -EINVAL;
1899+
1900+ return 0;
1901+
1902+}
1903+
1904+static int cursorfb_set_par(struct fb_info *info)
1905+{
1906+ struct overlayfb_info *fbi = (struct overlayfb_info*) info;
1907+ struct fb_var_screeninfo *var = &fbi->fb.var;
1908+ struct cursorfb_mode *cursor;
1909+ int mode, xpos, ypos;
1910+ int err;
1911+
1912+ info->flags &= ~FBINFO_MISC_USEREVENT;
1913+
1914+ mode = var->nonstd & 0x7;
1915+ xpos = (var->nonstd>>5) & 0x3ff;
1916+ ypos = (var->nonstd>>15) & 0x3ff;
1917+
1918+ if (mode != fbi->format) {
1919+ cursor = cursorfb_modes + mode;
1920+
1921+ /* update "var" info */
1922+ fbi->fb.var.xres = cursor->xres;
1923+ fbi->fb.var.yres = cursor->yres;
1924+ fbi->fb.var.bits_per_pixel = cursor->bpp;
1925+
1926+ /* alloc video memory
1927+ *
1928+ * 4k is engouh for 128x128x1 cursor,
1929+ * - 2k for cursor pixels,
1930+ * - 2k for palette data, plus 2 dma descriptor
1931+ */
1932+ if (!fbi->map_cpu) {
1933+ fbi->map_size = PAGE_SIZE;
1934+ fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
1935+ &fbi->map_dma, GFP_KERNEL );
1936+ if (!fbi->map_cpu) return -ENOMEM;
1937+ }
1938+
1939+ cursor = cursorfb_modes + mode;
1940+
1941+ /* update overlay & fix "info" */
1942+ fbi->screen_cpu = fbi->map_cpu;
1943+ fbi->palette_cpu = fbi->map_cpu + (PAGE_SIZE/2);
1944+ fbi->screen_dma = fbi->map_dma;
1945+ fbi->palette_dma = fbi->map_dma + (PAGE_SIZE/2);
1946+
1947+ fbi->format = mode;
1948+ fbi->palette_size = (1<<cursor->bpp);
1949+ fbi->fb.fix.smem_start = fbi->screen_dma;
1950+ fbi->fb.fix.smem_len = cursor->xres * cursor->yres * cursor->bpp / 8;
1951+ fbi->fb.fix.line_length = cursor->xres * cursor->bpp / 8;
1952+
1953+ fbi->dma5_pal = (struct pxafb_dma_descriptor*)(fbi->map_cpu + PAGE_SIZE - 16 );
1954+ fbi->dma5_pal->fdadr = (fbi->map_dma + PAGE_SIZE - 16);
1955+ fbi->dma5_pal->fsadr = fbi->palette_dma;
1956+ fbi->dma5_pal->fidr = 0;
1957+ fbi->dma5_pal->ldcmd = (fbi->palette_size<<2) | LDCMD_PAL;
1958+
1959+ fbi->dma5_frame = (struct pxafb_dma_descriptor*)(fbi->map_cpu + PAGE_SIZE - 32 );
1960+ fbi->dma5_frame->fdadr = (fbi->map_dma + PAGE_SIZE - 32);
1961+ fbi->dma5_frame->fsadr = fbi->screen_dma;
1962+ fbi->dma5_frame->fidr = 0;
1963+ fbi->dma5_frame->ldcmd = fbi->fb.fix.smem_len;
1964+
1965+ /* alloc & set default cmap */
1966+ err = fb_alloc_cmap(&fbi->fb.cmap, fbi->palette_size, 0);
1967+ if (err) return err;
1968+ err = fb_set_cmap(&fbi->fb.cmap, info);
1969+ if (err) return err;
1970+ }
1971+
1972+ /* update overlay info */
1973+ if ( (xpos != fbi->xpos) || (ypos != fbi->ypos) ) {
1974+ fbi->xpos = xpos;
1975+ fbi->ypos = ypos;
1976+ }
1977+
1978+ cursorfb_enable(info);
1979+ pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
1980+
1981+ return 0;
1982+}
1983+
1984+static struct fb_ops cursorfb_ops = {
1985+ .owner = THIS_MODULE,
1986+ .fb_check_var = cursorfb_check_var,
1987+ .fb_set_par = cursorfb_set_par,
1988+ .fb_blank = cursorfb_blank,
1989+ .fb_fillrect = cfb_fillrect,
1990+ .fb_copyarea = cfb_copyarea,
1991+ .fb_imageblit = cfb_imageblit,
1992+ .fb_setcolreg = cursorfb_setcolreg,
1993+};
1994+
1995+static struct overlayfb_info * __init overlay1fb_init_fbinfo(void)
1996+{
1997+ struct overlayfb_info *fbi;
1998+
1999+ fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
2000+ if (!fbi)
2001+ return NULL;
2002+
2003+ memset(fbi, 0, sizeof(struct overlayfb_info) );
2004+
2005+ fbi->refcount = 0;
2006+ init_MUTEX(&fbi->mutex);
2007+
2008+ strcpy(fbi->fb.fix.id, "overlay1");
2009+
2010+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
2011+ fbi->fb.fix.type_aux = 0;
2012+ fbi->fb.fix.xpanstep = 0;
2013+ fbi->fb.fix.ypanstep = 0;
2014+ fbi->fb.fix.ywrapstep = 0;
2015+ fbi->fb.fix.accel = FB_ACCEL_NONE;
2016+
2017+ fbi->fb.var.nonstd = 0;
2018+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
2019+ fbi->fb.var.height = -1;
2020+ fbi->fb.var.width = -1;
2021+ fbi->fb.var.accel_flags = 0;
2022+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
2023+
2024+
2025+ fbi->fb.fbops = &overlay1fb_ops;
2026+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
2027+ fbi->fb.node = -1;
2028+ fbi->fb.pseudo_palette = NULL;
2029+
2030+ fbi->xpos = 0;
2031+ fbi->ypos = 0;
2032+ fbi->format = -1;
2033+ fbi->state = C_DISABLE;
2034+
2035+ return fbi;
2036+}
2037+
2038+static struct overlayfb_info * __init overlay2fb_init_fbinfo(void)
2039+{
2040+ struct overlayfb_info *fbi;
2041+
2042+ fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
2043+ if (!fbi)
2044+ return NULL;
2045+
2046+ memset(fbi, 0, sizeof(struct overlayfb_info) );
2047+
2048+ fbi->refcount = 0;
2049+ init_MUTEX(&fbi->mutex);
2050+
2051+ strcpy(fbi->fb.fix.id, "overlay2");
2052+
2053+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
2054+ fbi->fb.fix.type_aux = 0;
2055+ fbi->fb.fix.xpanstep = 0;
2056+ fbi->fb.fix.ypanstep = 0;
2057+ fbi->fb.fix.ywrapstep = 0;
2058+ fbi->fb.fix.accel = FB_ACCEL_NONE;
2059+
2060+ fbi->fb.var.nonstd = 0;
2061+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
2062+ fbi->fb.var.height = -1;
2063+ fbi->fb.var.width = -1;
2064+ fbi->fb.var.accel_flags = 0;
2065+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
2066+
2067+ fbi->fb.fbops = &overlay2fb_ops;
2068+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
2069+ fbi->fb.node = -1;
2070+ fbi->fb.pseudo_palette = NULL;
2071+
2072+ fbi->xpos = 0;
2073+ fbi->ypos = 0;
2074+ fbi->format = -1;
2075+ fbi->state = C_DISABLE;
2076+
2077+ return fbi;
2078+}
2079+
2080+static struct overlayfb_info * __init cursorfb_init_fbinfo(void)
2081+{
2082+ struct overlayfb_info *fbi;
2083+
2084+ fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
2085+ if (!fbi)
2086+ return NULL;
2087+
2088+ memset(fbi, 0, sizeof(struct overlayfb_info) );
2089+
2090+ fbi->refcount = 0;
2091+ init_MUTEX(&fbi->mutex);
2092+
2093+ strcpy(fbi->fb.fix.id, "cursor");
2094+
2095+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
2096+ fbi->fb.fix.type_aux = 0;
2097+ fbi->fb.fix.xpanstep = 0;
2098+ fbi->fb.fix.ypanstep = 0;
2099+ fbi->fb.fix.ywrapstep = 0;
2100+ fbi->fb.fix.accel = FB_ACCEL_NONE;
2101+
2102+ fbi->fb.var.nonstd = 0;
2103+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
2104+ fbi->fb.var.height = -1;
2105+ fbi->fb.var.width = -1;
2106+ fbi->fb.var.accel_flags = 0;
2107+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
2108+
2109+ fbi->fb.fbops = &cursorfb_ops;
2110+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
2111+ fbi->fb.node = -1;
2112+ fbi->fb.pseudo_palette = NULL;
2113+
2114+
2115+ fbi->xpos = 0;
2116+ fbi->ypos = 0;
2117+ fbi->format = -1;
2118+ fbi->state = C_DISABLE;
2119+
2120+ return fbi;
2121+}
2122+
2123+
2124+void pxa_set_overlay_ctrlr_state(struct pxafb_info *fbi, u_int state)
2125+{
2126+ switch (state) {
2127+ case C_DISABLE:
2128+ DISABLE_OVERLAYS(fbi);
2129+ break;
2130+ case C_ENABLE:
2131+ ENABLE_OVERLAYS(fbi);
2132+ break;
2133+ case C_BLANK:
2134+ BLANK_OVERLAYS(fbi);
2135+ break;
2136+ case C_UNBLANK:
2137+ UNBLANK_OVERLAYS(fbi);
2138+ break;
2139+ default:
2140+ break;
2141+ }
2142+}
2143+
2144+static int is_pxafb_device(struct device * dev, void * data)
2145+{
2146+ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
2147+
2148+ return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0);
2149+}
2150+
2151+static int __devinit pxafb_overlay_init(void)
2152+{
2153+ int ret;
2154+ struct overlayfb_info *overlay1fb, *overlay2fb, *cursorfb;
2155+ struct pxafb_info *fbi;
2156+ struct device *dev;
2157+
2158+ ret = -1;
2159+ overlay1fb = overlay2fb = cursorfb = NULL;
2160+ fbi = NULL;
2161+
2162+ dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
2163+ if (!dev) {
2164+ printk(KERN_INFO "Base framebuffer not exists, failed to load overlay driver!\n");
2165+ return ret;
2166+ }
2167+
2168+ fbi = dev_get_drvdata(dev);
2169+ if (fbi == NULL) {
2170+ printk(KERN_INFO "Base framebuffer not initialized, failed to load overlay driver!\n");
2171+ return ret;
2172+ }
2173+
2174+ /* Overlay 1 windows */
2175+ overlay1fb = overlay1fb_init_fbinfo();
2176+
2177+ if (!overlay1fb) {
2178+ ret = -ENOMEM;
2179+ printk("overlay1fb_init_fbinfo failed\n");
2180+ goto failed;
2181+ }
2182+
2183+ ret = register_framebuffer(&overlay1fb->fb);
2184+ if (ret < 0)
2185+ goto failed;
2186+
2187+ /* Overlay 2 window */
2188+ overlay2fb = overlay2fb_init_fbinfo();
2189+
2190+ if (!overlay2fb) {
2191+ ret = -ENOMEM;
2192+ printk("overlay2fb_init_fbinfo failed\n");
2193+ goto failed;
2194+ }
2195+
2196+ ret = register_framebuffer(&overlay2fb->fb);
2197+ if (ret < 0) goto failed;
2198+
2199+ /* Hardware cursor window */
2200+ cursorfb = cursorfb_init_fbinfo();
2201+
2202+ if (!cursorfb) {
2203+ ret = -ENOMEM;
2204+ printk("cursorfb_init_fbinfo failed\n");
2205+ goto failed;
2206+ }
2207+
2208+ ret = register_framebuffer(&cursorfb->fb);
2209+ if (ret < 0) goto failed;
2210+
2211+
2212+ /* set refernce to Overlays */
2213+ fbi->overlay1fb = overlay1fb;
2214+ fbi->overlay2fb = overlay2fb;
2215+ fbi->cursorfb = cursorfb;
2216+ fbi->set_overlay_ctrlr_state=pxa_set_overlay_ctrlr_state;
2217+
2218+ /* set refernce to BaseFrame */
2219+ overlay1fb->basefb = fbi;
2220+ overlay2fb->basefb = fbi;
2221+ cursorfb->basefb = fbi;
2222+
2223+ printk(KERN_INFO "Load PXA Overlay driver successfully!\n");
2224+
2225+ return 0;
2226+
2227+failed:
2228+ if (overlay1fb)
2229+ kfree(overlay1fb);
2230+ if (overlay2fb)
2231+ kfree(overlay2fb);
2232+ if (cursorfb)
2233+ kfree(cursorfb);
2234+ printk(KERN_INFO "Load PXA Overlay driver failed!\n");
2235+ return ret;
2236+}
2237+
2238+static void __exit pxafb_overlay_exit(void)
2239+{
2240+ struct pxafb_info *fbi;
2241+ struct device *dev;
2242+
2243+ dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
2244+ if (!dev)
2245+ return;
2246+
2247+ fbi = dev_get_drvdata(dev);
2248+ if (!fbi)
2249+ return;
2250+
2251+ if (fbi->overlay1fb) {
2252+ unregister_framebuffer(&(fbi->overlay1fb->fb));
2253+ kfree(fbi->overlay1fb);
2254+ fbi->overlay1fb = NULL;
2255+ }
2256+
2257+ if (fbi->overlay2fb) {
2258+ unregister_framebuffer(&(fbi->overlay2fb->fb));
2259+ kfree(fbi->overlay2fb);
2260+ fbi->overlay2fb = NULL;
2261+ }
2262+
2263+ if (fbi->cursorfb) {
2264+ unregister_framebuffer(&(fbi->cursorfb->fb));
2265+ kfree(fbi->cursorfb);
2266+ fbi->cursorfb = NULL;
2267+ }
2268+
2269+ fbi->set_overlay_ctrlr_state = NULL;
2270+
2271+ printk(KERN_INFO "Unload PXA Overlay driver successfully!\n");
2272+ return;
2273+}
2274+
2275+
2276+module_init(pxafb_overlay_init);
2277+module_exit(pxafb_overlay_exit);
2278+
2279+MODULE_DESCRIPTION("Loadable framebuffer overlay driver for PXA");
2280+MODULE_LICENSE("GPL");
2281+
2282--- linux-2.6.24-rc1.orig/include/asm-arm/arch-pxa/pxa-regs.h
2283+++ linux-2.6.24-rc1/include/asm-arm/arch-pxa/pxa-regs.h
2284@@ -789,11 +789,18 @@
2285 #define UDC_INT_PACKETCMP (0x1)
2286
2287 #define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
2288+/* Older defines, do not use. */
2289 #define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */
2290 #define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */
2291 #define UDCICR1_IERU (1 << 29) /* IntEn - Resume */
2292 #define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */
2293 #define UDCICR1_IERS (1 << 27) /* IntEn - Reset */
2294+/* New defines. */
2295+#define UDCISR1_IRCC (1 << 31) /* IntEn - Configuration Change */
2296+#define UDCISR1_IRSOF (1 << 30) /* IntEn - Start of Frame */
2297+#define UDCISR1_IRRU (1 << 29) /* IntEn - Resume */
2298+#define UDCISR1_IRSU (1 << 28) /* IntEn - Suspend */
2299+#define UDCISR1_IRRS (1 << 27) /* IntEn - Reset */
2300
2301 #define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
2302 #define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */
2303@@ -1827,6 +1834,8 @@
2304 #define DFBR0 __REG(0x44000020) /* DMA Channel 0 Frame Branch Register */
2305 #define DFBR1 __REG(0x44000024) /* DMA Channel 1 Frame Branch Register */
2306 #define LCSR __REG(0x44000038) /* LCD Controller Status Register */
2307+#define LCSR0 __REG(0x44000038) /* LCD Controller Status Register */
2308+#define LCSR1 __REG(0x44000034) /* LCD Controller Status Register */
2309 #define LIIDR __REG(0x4400003C) /* LCD Controller Interrupt ID Register */
2310 #define TMEDRGBR __REG(0x44000040) /* TMED RGB Seed Register */
2311 #define TMEDCR __REG(0x44000044) /* TMED Control Register */
2312@@ -1836,6 +1845,10 @@
2313 #define LCCR3_4BPP (2 << 24)
2314 #define LCCR3_8BPP (3 << 24)
2315 #define LCCR3_16BPP (4 << 24)
2316+#define LCCR3_18BPP (6 << 24)
2317+#define LCCR3_19BPP (8 << 24)
2318+#define LCCR3_24BPP (9 << 24)
2319+#define LCCR3_25BPP (10<< 24)
2320
2321 #define LCCR3_PDFOR_0 (0 << 30)
2322 #define LCCR3_PDFOR_1 (1 << 30)
2323@@ -2010,6 +2023,104 @@
2324
2325 #define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
2326
2327+/* Overlay1 & Overlay2 & Hardware Cursor */
2328+#define LCSR1_SOF1 (1 << 0)
2329+#define LCSR1_SOF2 (1 << 1)
2330+#define LCSR1_SOF3 (1 << 2)
2331+#define LCSR1_SOF4 (1 << 3)
2332+#define LCSR1_SOF5 (1 << 4)
2333+#define LCSR1_SOF6 (1 << 5)
2334+
2335+#define LCSR1_EOF1 (1 << 8)
2336+#define LCSR1_EOF2 (1 << 9)
2337+#define LCSR1_EOF3 (1 << 10)
2338+#define LCSR1_EOF4 (1 << 11)
2339+#define LCSR1_EOF5 (1 << 12)
2340+#define LCSR1_EOF6 (1 << 13)
2341+
2342+#define LCSR1_BS1 (1 << 16)
2343+#define LCSR1_BS2 (1 << 17)
2344+#define LCSR1_BS3 (1 << 18)
2345+#define LCSR1_BS4 (1 << 19)
2346+#define LCSR1_BS5 (1 << 20)
2347+#define LCSR1_BS6 (1 << 21)
2348+
2349+#define LCSR1_IU2 (1 << 25)
2350+#define LCSR1_IU3 (1 << 26)
2351+#define LCSR1_IU4 (1 << 27)
2352+#define LCSR1_IU5 (1 << 28)
2353+#define LCSR1_IU6 (1 << 29)
2354+
2355+#define LDCMD_SOFINT (1 << 22)
2356+#define LDCMD_EOFINT (1 << 21)
2357+
2358+
2359+#define LCCR5_SOFM1 (1<<0) /* Start Of Frame Mask for Overlay 1 (channel 1) */
2360+#define LCCR5_SOFM2 (1<<1) /* Start Of Frame Mask for Overlay 2 (channel 2) */
2361+#define LCCR5_SOFM3 (1<<2) /* Start Of Frame Mask for Overlay 2 (channel 3) */
2362+#define LCCR5_SOFM4 (1<<3) /* Start Of Frame Mask for Overlay 2 (channel 4) */
2363+#define LCCR5_SOFM5 (1<<4) /* Start Of Frame Mask for cursor (channel 5) */
2364+#define LCCR5_SOFM6 (1<<5) /* Start Of Frame Mask for command data (channel 6) */
2365+
2366+#define LCCR5_EOFM1 (1<<8) /* End Of Frame Mask for Overlay 1 (channel 1) */
2367+#define LCCR5_EOFM2 (1<<9) /* End Of Frame Mask for Overlay 2 (channel 2) */
2368+#define LCCR5_EOFM3 (1<<10) /* End Of Frame Mask for Overlay 2 (channel 3) */
2369+#define LCCR5_EOFM4 (1<<11) /* End Of Frame Mask for Overlay 2 (channel 4) */
2370+#define LCCR5_EOFM5 (1<<12) /* End Of Frame Mask for cursor (channel 5) */
2371+#define LCCR5_EOFM6 (1<<13) /* End Of Frame Mask for command data (channel 6) */
2372+
2373+#define LCCR5_BSM1 (1<<16) /* Branch mask for Overlay 1 (channel 1) */
2374+#define LCCR5_BSM2 (1<<17) /* Branch mask for Overlay 2 (channel 2) */
2375+#define LCCR5_BSM3 (1<<18) /* Branch mask for Overlay 2 (channel 3) */
2376+#define LCCR5_BSM4 (1<<19) /* Branch mask for Overlay 2 (channel 4) */
2377+#define LCCR5_BSM5 (1<<20) /* Branch mask for cursor (channel 5) */
2378+#define LCCR5_BSM6 (1<<21) /* Branch mask for data command (channel 6) */
2379+
2380+#define LCCR5_IUM1 (1<<24) /* Input FIFO Underrun Mask for Overlay 1 */
2381+#define LCCR5_IUM2 (1<<25) /* Input FIFO Underrun Mask for Overlay 2 */
2382+#define LCCR5_IUM3 (1<<26) /* Input FIFO Underrun Mask for Overlay 2 */
2383+#define LCCR5_IUM4 (1<<27) /* Input FIFO Underrun Mask for Overlay 2 */
2384+#define LCCR5_IUM5 (1<<28) /* Input FIFO Underrun Mask for cursor */
2385+#define LCCR5_IUM6 (1<<29) /* Input FIFO Underrun Mask for data command */
2386+
2387+#define OVL1C1_O1EN (1<<31) /* Enable bit for Overlay 1 */
2388+#define OVL2C1_O2EN (1<<31) /* Enable bit for Overlay 2 */
2389+#define CCR_CEN (1<<31) /* Enable bit for Cursor */
2390+
2391+/* LCD registers */
2392+#define LCCR4 __REG(0x44000010) /* LCD Controller Control Register 4 */
2393+#define LCCR5 __REG(0x44000014) /* LCD Controller Control Register 5 */
2394+#define FBR0 __REG(0x44000020) /* DMA Channel 0 Frame Branch Register */
2395+#define FBR1 __REG(0x44000024) /* DMA Channel 1 Frame Branch Register */
2396+#define FBR2 __REG(0x44000028) /* DMA Channel 2 Frame Branch Register */
2397+#define FBR3 __REG(0x4400002C) /* DMA Channel 3 Frame Branch Register */
2398+#define FBR4 __REG(0x44000030) /* DMA Channel 4 Frame Branch Register */
2399+#define FDADR2 __REG(0x44000220) /* DMA Channel 2 Frame Descriptor Address Register */
2400+#define FSADR2 __REG(0x44000224) /* DMA Channel 2 Frame Source Address Register */
2401+#define FIDR2 __REG(0x44000228) /* DMA Channel 2 Frame ID Register */
2402+#define LDCMD2 __REG(0x4400022C) /* DMA Channel 2 Command Register */
2403+#define FDADR3 __REG(0x44000230) /* DMA Channel 3 Frame Descriptor Address Register */
2404+#define FSADR3 __REG(0x44000234) /* DMA Channel 3 Frame Source Address Register */
2405+#define FIDR3 __REG(0x44000238) /* DMA Channel 3 Frame ID Register */
2406+#define LDCMD3 __REG(0x4400023C) /* DMA Channel 3 Command Register */
2407+#define FDADR4 __REG(0x44000240) /* DMA Channel 4 Frame Descriptor Address Register */
2408+#define FSADR4 __REG(0x44000244) /* DMA Channel 4 Frame Source Address Register */
2409+#define FIDR4 __REG(0x44000248) /* DMA Channel 4 Frame ID Register */
2410+#define LDCMD4 __REG(0x4400024C) /* DMA Channel 4 Command Register */
2411+#define FDADR5 __REG(0x44000250) /* DMA Channel 5 Frame Descriptor Address Register */
2412+#define FSADR5 __REG(0x44000254) /* DMA Channel 5 Frame Source Address Register */
2413+#define FIDR5 __REG(0x44000258) /* DMA Channel 5 Frame ID Register */
2414+#define LDCMD5 __REG(0x4400025C) /* DMA Channel 5 Command Register */
2415+
2416+#define OVL1C1 __REG(0x44000050) /* Overlay 1 Control Register 1 */
2417+#define OVL1C2 __REG(0x44000060) /* Overlay 1 Control Register 2 */
2418+#define OVL2C1 __REG(0x44000070) /* Overlay 2 Control Register 1 */
2419+#define OVL2C2 __REG(0x44000080) /* Overlay 2 Control Register 2 */
2420+#define CCR __REG(0x44000090) /* Cursor Control Register */
2421+
2422+#define FBR5 __REG(0x44000110) /* DMA Channel 5 Frame Branch Register */
2423+#define FBR6 __REG(0x44000114) /* DMA Channel 6 Frame Branch Register */
2424+
2425 /*
2426 * Memory controller
2427 */
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 @@
1 fs/Kconfig | 65 +
2 fs/Makefile | 1
3 fs/squashfs/Makefile | 7
4 fs/squashfs/inode.c | 2122 +++++++++++++++++++++++++++++++++++++++++
5 fs/squashfs/squashfs.h | 86 +
6 fs/squashfs/squashfs2_0.c | 757 ++++++++++++++
7 include/linux/squashfs_fs.h | 911 +++++++++++++++++
8 include/linux/squashfs_fs_i.h | 45
9 include/linux/squashfs_fs_sb.h | 74 +
10 init/do_mounts_rd.c | 13
11 10 files changed, 4081 insertions(+)
12
13Index: linux-2.6.22/fs/Kconfig
14===================================================================
15--- linux-2.6.22.orig/fs/Kconfig 2007-08-28 21:56:32.000000000 +0100
16+++ linux-2.6.22/fs/Kconfig 2007-08-28 21:56:34.000000000 +0100
17@@ -1394,6 +1394,71 @@ config CRAMFS
18
19 If unsure, say N.
20
21+config SQUASHFS
22+ tristate "SquashFS 3.0 - Squashed file system support"
23+ select ZLIB_INFLATE
24+ help
25+ Saying Y here includes support for SquashFS 3.0 (a Compressed Read-Only File
26+ System). Squashfs is a highly compressed read-only filesystem for Linux.
27+ It uses zlib compression to compress both files, inodes and directories.
28+ Inodes in the system are very small and all blocks are packed to minimise
29+ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
30+ SquashFS 3.0 supports 64 bit filesystems and files (larger than 4GB), full
31+ uid/gid information, hard links and timestamps.
32+
33+ Squashfs is intended for general read-only filesystem use, for archival
34+ use (i.e. in cases where a .tar.gz file may be used), and in embedded
35+ systems where low overhead is needed. Further information and filesystem tools
36+ are available from http://squashfs.sourceforge.net.
37+
38+ If you want to compile this as a module ( = code which can be
39+ inserted in and removed from the running kernel whenever you want),
40+ say M here and read <file:Documentation/modules.txt>. The module
41+ will be called squashfs. Note that the root file system (the one
42+ containing the directory /) cannot be compiled as a module.
43+
44+ If unsure, say N.
45+
46+config SQUASHFS_EMBEDDED
47+
48+ bool "Additional options for memory-constrained systems"
49+ depends on SQUASHFS
50+ default n
51+ help
52+ Saying Y here allows you to specify cache sizes and how Squashfs
53+ allocates memory. This is only intended for memory constrained
54+ systems.
55+
56+ If unsure, say N.
57+
58+config SQUASHFS_FRAGMENT_CACHE_SIZE
59+ int "Number of fragments cached" if SQUASHFS_EMBEDDED
60+ depends on SQUASHFS
61+ default "3"
62+ help
63+ By default SquashFS caches the last 3 fragments read from
64+ the filesystem. Increasing this amount may mean SquashFS
65+ has to re-read fragments less often from disk, at the expense
66+ of extra system memory. Decreasing this amount will mean
67+ SquashFS uses less memory at the expense of extra reads from disk.
68+
69+ Note there must be at least one cached fragment. Anything
70+ much more than three will probably not make much difference.
71+
72+config SQUASHFS_VMALLOC
73+ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
74+ depends on SQUASHFS
75+ default n
76+ help
77+ By default SquashFS uses kmalloc to obtain fragment cache memory.
78+ Kmalloc memory is the standard kernel allocator, but it can fail
79+ on memory constrained systems. Because of the way Vmalloc works,
80+ Vmalloc can succeed when kmalloc fails. Specifying this option
81+ will make SquashFS always use Vmalloc to allocate the
82+ fragment cache memory.
83+
84+ If unsure, say N.
85+
86 config VXFS_FS
87 tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
88 depends on BLOCK
89Index: linux-2.6.22/fs/Makefile
90===================================================================
91--- linux-2.6.22.orig/fs/Makefile 2007-08-28 21:54:14.000000000 +0100
92+++ linux-2.6.22/fs/Makefile 2007-08-28 21:56:34.000000000 +0100
93@@ -72,6 +72,7 @@ obj-$(CONFIG_JBD) += jbd/
94 obj-$(CONFIG_JBD2) += jbd2/
95 obj-$(CONFIG_EXT2_FS) += ext2/
96 obj-$(CONFIG_CRAMFS) += cramfs/
97+obj-$(CONFIG_SQUASHFS) += squashfs/
98 obj-$(CONFIG_RAMFS) += ramfs/
99 obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
100 obj-$(CONFIG_CODA_FS) += coda/
101Index: linux-2.6.22/fs/squashfs/inode.c
102===================================================================
103--- /dev/null 1970-01-01 00:00:00.000000000 +0000
104+++ linux-2.6.22/fs/squashfs/inode.c 2007-08-28 22:12:03.000000000 +0100
105@@ -0,0 +1,2122 @@
106+/*
107+ * Squashfs - a compressed read only filesystem for Linux
108+ *
109+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
110+ * Phillip Lougher <phillip@lougher.org.uk>
111+ *
112+ * This program is free software; you can redistribute it and/or
113+ * modify it under the terms of the GNU General Public License
114+ * as published by the Free Software Foundation; either version 2,
115+ * or (at your option) any later version.
116+ *
117+ * This program is distributed in the hope that it will be useful,
118+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
119+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
120+ * GNU General Public License for more details.
121+ *
122+ * You should have received a copy of the GNU General Public License
123+ * along with this program; if not, write to the Free Software
124+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
125+ *
126+ * inode.c
127+ */
128+
129+#include <linux/types.h>
130+#include <linux/squashfs_fs.h>
131+#include <linux/module.h>
132+#include <linux/errno.h>
133+#include <linux/slab.h>
134+#include <linux/fs.h>
135+#include <linux/smp_lock.h>
136+#include <linux/slab.h>
137+#include <linux/squashfs_fs_sb.h>
138+#include <linux/squashfs_fs_i.h>
139+#include <linux/buffer_head.h>
140+#include <linux/vfs.h>
141+#include <linux/init.h>
142+#include <linux/dcache.h>
143+#include <linux/wait.h>
144+#include <linux/zlib.h>
145+#include <linux/blkdev.h>
146+#include <linux/vmalloc.h>
147+#include <asm/uaccess.h>
148+#include <asm/semaphore.h>
149+
150+#include "squashfs.h"
151+
152+static void squashfs_put_super(struct super_block *);
153+static int squashfs_statfs(struct dentry *, struct kstatfs *);
154+static int squashfs_symlink_readpage(struct file *file, struct page *page);
155+static int squashfs_readpage(struct file *file, struct page *page);
156+static int squashfs_readpage4K(struct file *file, struct page *page);
157+static int squashfs_readdir(struct file *, void *, filldir_t);
158+static struct inode *squashfs_alloc_inode(struct super_block *sb);
159+static void squashfs_destroy_inode(struct inode *inode);
160+static int init_inodecache(void);
161+static void destroy_inodecache(void);
162+static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
163+ struct nameidata *);
164+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
165+static long long read_blocklist(struct inode *inode, int index,
166+ int readahead_blks, char *block_list,
167+ unsigned short **block_p, unsigned int *bsize);
168+static int squashfs_get_sb(struct file_system_type *, int,
169+ const char *, void *, struct vfsmount *);
170+
171+
172+static z_stream stream;
173+
174+static struct file_system_type squashfs_fs_type = {
175+ .owner = THIS_MODULE,
176+ .name = "squashfs",
177+ .get_sb = squashfs_get_sb,
178+ .kill_sb = kill_block_super,
179+ .fs_flags = FS_REQUIRES_DEV
180+};
181+
182+static unsigned char squashfs_filetype_table[] = {
183+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
184+};
185+
186+static struct super_operations squashfs_ops = {
187+ .alloc_inode = squashfs_alloc_inode,
188+ .destroy_inode = squashfs_destroy_inode,
189+ .statfs = squashfs_statfs,
190+ .put_super = squashfs_put_super,
191+};
192+
193+SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
194+ .readpage = squashfs_symlink_readpage
195+};
196+
197+SQSH_EXTERN struct address_space_operations squashfs_aops = {
198+ .readpage = squashfs_readpage
199+};
200+
201+SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
202+ .readpage = squashfs_readpage4K
203+};
204+
205+static struct file_operations squashfs_dir_ops = {
206+ .read = generic_read_dir,
207+ .readdir = squashfs_readdir
208+};
209+
210+SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
211+ .lookup = squashfs_lookup
212+};
213+
214+
215+static struct buffer_head *get_block_length(struct super_block *s,
216+ int *cur_index, int *offset, int *c_byte)
217+{
218+ struct squashfs_sb_info *msblk = s->s_fs_info;
219+ unsigned short temp;
220+ struct buffer_head *bh;
221+
222+ if (!(bh = sb_bread(s, *cur_index)))
223+ goto out;
224+
225+ if (msblk->devblksize - *offset == 1) {
226+ if (msblk->swap)
227+ ((unsigned char *) &temp)[1] = *((unsigned char *)
228+ (bh->b_data + *offset));
229+ else
230+ ((unsigned char *) &temp)[0] = *((unsigned char *)
231+ (bh->b_data + *offset));
232+ brelse(bh);
233+ if (!(bh = sb_bread(s, ++(*cur_index))))
234+ goto out;
235+ if (msblk->swap)
236+ ((unsigned char *) &temp)[0] = *((unsigned char *)
237+ bh->b_data);
238+ else
239+ ((unsigned char *) &temp)[1] = *((unsigned char *)
240+ bh->b_data);
241+ *c_byte = temp;
242+ *offset = 1;
243+ } else {
244+ if (msblk->swap) {
245+ ((unsigned char *) &temp)[1] = *((unsigned char *)
246+ (bh->b_data + *offset));
247+ ((unsigned char *) &temp)[0] = *((unsigned char *)
248+ (bh->b_data + *offset + 1));
249+ } else {
250+ ((unsigned char *) &temp)[0] = *((unsigned char *)
251+ (bh->b_data + *offset));
252+ ((unsigned char *) &temp)[1] = *((unsigned char *)
253+ (bh->b_data + *offset + 1));
254+ }
255+ *c_byte = temp;
256+ *offset += 2;
257+ }
258+
259+ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
260+ if (*offset == msblk->devblksize) {
261+ brelse(bh);
262+ if (!(bh = sb_bread(s, ++(*cur_index))))
263+ goto out;
264+ *offset = 0;
265+ }
266+ if (*((unsigned char *) (bh->b_data + *offset)) !=
267+ SQUASHFS_MARKER_BYTE) {
268+ ERROR("Metadata block marker corrupt @ %x\n",
269+ *cur_index);
270+ brelse(bh);
271+ goto out;
272+ }
273+ (*offset)++;
274+ }
275+ return bh;
276+
277+out:
278+ return NULL;
279+}
280+
281+
282+SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
283+ long long index, unsigned int length,
284+ long long *next_index)
285+{
286+ struct squashfs_sb_info *msblk = s->s_fs_info;
287+ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
288+ msblk->devblksize_log2) + 2];
289+ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
290+ unsigned int cur_index = index >> msblk->devblksize_log2;
291+ int bytes, avail_bytes, b = 0, k;
292+ char *c_buffer;
293+ unsigned int compressed;
294+ unsigned int c_byte = length;
295+
296+ if (c_byte) {
297+ bytes = msblk->devblksize - offset;
298+ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
299+ c_buffer = compressed ? msblk->read_data : buffer;
300+ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
301+
302+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
303+ ? "" : "un", (unsigned int) c_byte);
304+
305+ if (!(bh[0] = sb_getblk(s, cur_index)))
306+ goto block_release;
307+
308+ for (b = 1; bytes < c_byte; b++) {
309+ if (!(bh[b] = sb_getblk(s, ++cur_index)))
310+ goto block_release;
311+ bytes += msblk->devblksize;
312+ }
313+ ll_rw_block(READ, b, bh);
314+ } else {
315+ if (!(bh[0] = get_block_length(s, &cur_index, &offset,
316+ &c_byte)))
317+ goto read_failure;
318+
319+ bytes = msblk->devblksize - offset;
320+ compressed = SQUASHFS_COMPRESSED(c_byte);
321+ c_buffer = compressed ? msblk->read_data : buffer;
322+ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
323+
324+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
325+ ? "" : "un", (unsigned int) c_byte);
326+
327+ for (b = 1; bytes < c_byte; b++) {
328+ if (!(bh[b] = sb_getblk(s, ++cur_index)))
329+ goto block_release;
330+ bytes += msblk->devblksize;
331+ }
332+ ll_rw_block(READ, b - 1, bh + 1);
333+ }
334+
335+ if (compressed)
336+ down(&msblk->read_data_mutex);
337+
338+ for (bytes = 0, k = 0; k < b; k++) {
339+ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
340+ msblk->devblksize - offset :
341+ c_byte - bytes;
342+ wait_on_buffer(bh[k]);
343+ if (!buffer_uptodate(bh[k]))
344+ goto block_release;
345+ memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
346+ bytes += avail_bytes;
347+ offset = 0;
348+ brelse(bh[k]);
349+ }
350+
351+ /*
352+ * uncompress block
353+ */
354+ if (compressed) {
355+ int zlib_err;
356+
357+ stream.next_in = c_buffer;
358+ stream.avail_in = c_byte;
359+ stream.next_out = buffer;
360+ stream.avail_out = msblk->read_size;
361+
362+ if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
363+ ((zlib_err = zlib_inflate(&stream, Z_FINISH))
364+ != Z_STREAM_END) || ((zlib_err =
365+ zlib_inflateEnd(&stream)) != Z_OK)) {
366+ ERROR("zlib_fs returned unexpected result 0x%x\n",
367+ zlib_err);
368+ bytes = 0;
369+ } else
370+ bytes = stream.total_out;
371+
372+ up(&msblk->read_data_mutex);
373+ }
374+
375+ if (next_index)
376+ *next_index = index + c_byte + (length ? 0 :
377+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
378+ ? 3 : 2));
379+ return bytes;
380+
381+block_release:
382+ while (--b >= 0)
383+ brelse(bh[b]);
384+
385+read_failure:
386+ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
387+ return 0;
388+}
389+
390+
391+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
392+ long long block, unsigned int offset,
393+ int length, long long *next_block,
394+ unsigned int *next_offset)
395+{
396+ struct squashfs_sb_info *msblk = s->s_fs_info;
397+ int n, i, bytes, return_length = length;
398+ long long next_index;
399+
400+ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
401+
402+ while ( 1 ) {
403+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
404+ if (msblk->block_cache[i].block == block)
405+ break;
406+
407+ down(&msblk->block_cache_mutex);
408+
409+ if (i == SQUASHFS_CACHED_BLKS) {
410+ /* read inode header block */
411+ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
412+ n ; n --, i = (i + 1) %
413+ SQUASHFS_CACHED_BLKS)
414+ if (msblk->block_cache[i].block !=
415+ SQUASHFS_USED_BLK)
416+ break;
417+
418+ if (n == 0) {
419+ wait_queue_t wait;
420+
421+ init_waitqueue_entry(&wait, current);
422+ add_wait_queue(&msblk->waitq, &wait);
423+ set_current_state(TASK_UNINTERRUPTIBLE);
424+ up(&msblk->block_cache_mutex);
425+ schedule();
426+ set_current_state(TASK_RUNNING);
427+ remove_wait_queue(&msblk->waitq, &wait);
428+ continue;
429+ }
430+ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
431+
432+ if (msblk->block_cache[i].block ==
433+ SQUASHFS_INVALID_BLK) {
434+ if (!(msblk->block_cache[i].data =
435+ kmalloc(SQUASHFS_METADATA_SIZE,
436+ GFP_KERNEL))) {
437+ ERROR("Failed to allocate cache"
438+ "block\n");
439+ up(&msblk->block_cache_mutex);
440+ goto out;
441+ }
442+ }
443+
444+ msblk->block_cache[i].block = SQUASHFS_USED_BLK;
445+ up(&msblk->block_cache_mutex);
446+
447+ if (!(msblk->block_cache[i].length =
448+ squashfs_read_data(s,
449+ msblk->block_cache[i].data,
450+ block, 0, &next_index))) {
451+ ERROR("Unable to read cache block [%llx:%x]\n",
452+ block, offset);
453+ goto out;
454+ }
455+
456+ down(&msblk->block_cache_mutex);
457+ wake_up(&msblk->waitq);
458+ msblk->block_cache[i].block = block;
459+ msblk->block_cache[i].next_index = next_index;
460+ TRACE("Read cache block [%llx:%x]\n", block, offset);
461+ }
462+
463+ if (msblk->block_cache[i].block != block) {
464+ up(&msblk->block_cache_mutex);
465+ continue;
466+ }
467+
468+ if ((bytes = msblk->block_cache[i].length - offset) >= length) {
469+ if (buffer)
470+ memcpy(buffer, msblk->block_cache[i].data +
471+ offset, length);
472+ if (msblk->block_cache[i].length - offset == length) {
473+ *next_block = msblk->block_cache[i].next_index;
474+ *next_offset = 0;
475+ } else {
476+ *next_block = block;
477+ *next_offset = offset + length;
478+ }
479+ up(&msblk->block_cache_mutex);
480+ goto finish;
481+ } else {
482+ if (buffer) {
483+ memcpy(buffer, msblk->block_cache[i].data +
484+ offset, bytes);
485+ buffer += bytes;
486+ }
487+ block = msblk->block_cache[i].next_index;
488+ up(&msblk->block_cache_mutex);
489+ length -= bytes;
490+ offset = 0;
491+ }
492+ }
493+
494+finish:
495+ return return_length;
496+out:
497+ return 0;
498+}
499+
500+
501+static int get_fragment_location(struct super_block *s, unsigned int fragment,
502+ long long *fragment_start_block,
503+ unsigned int *fragment_size)
504+{
505+ struct squashfs_sb_info *msblk = s->s_fs_info;
506+ long long start_block =
507+ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
508+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
509+ struct squashfs_fragment_entry fragment_entry;
510+
511+ if (msblk->swap) {
512+ struct squashfs_fragment_entry sfragment_entry;
513+
514+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
515+ start_block, offset,
516+ sizeof(sfragment_entry), &start_block,
517+ &offset))
518+ goto out;
519+ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
520+ } else
521+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
522+ start_block, offset,
523+ sizeof(fragment_entry), &start_block,
524+ &offset))
525+ goto out;
526+
527+ *fragment_start_block = fragment_entry.start_block;
528+ *fragment_size = fragment_entry.size;
529+
530+ return 1;
531+
532+out:
533+ return 0;
534+}
535+
536+
537+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
538+ squashfs_fragment_cache *fragment)
539+{
540+ down(&msblk->fragment_mutex);
541+ fragment->locked --;
542+ wake_up(&msblk->fragment_wait_queue);
543+ up(&msblk->fragment_mutex);
544+}
545+
546+
547+SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
548+ *s, long long start_block,
549+ int length)
550+{
551+ int i, n, nf;
552+ struct squashfs_sb_info *msblk = s->s_fs_info;
553+
554+ while ( 1 ) {
555+ down(&msblk->fragment_mutex);
556+
557+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
558+ msblk->fragment[i].block != start_block; i++);
559+
560+ if (i == SQUASHFS_CACHED_FRAGMENTS) {
561+ nf = (msblk->next_fragment + 1) %
562+ SQUASHFS_CACHED_FRAGMENTS;
563+ for (i = msblk->next_fragment, n =
564+ SQUASHFS_CACHED_FRAGMENTS; n &&
565+ msblk->fragment[i].locked; n--, i = (i + 1) %
566+ SQUASHFS_CACHED_FRAGMENTS);
567+
568+ if (n == 0) {
569+ wait_queue_t wait;
570+
571+ init_waitqueue_entry(&wait, current);
572+ add_wait_queue(&msblk->fragment_wait_queue,
573+ &wait);
574+ set_current_state(TASK_UNINTERRUPTIBLE);
575+ up(&msblk->fragment_mutex);
576+ schedule();
577+ set_current_state(TASK_RUNNING);
578+ remove_wait_queue(&msblk->fragment_wait_queue,
579+ &wait);
580+ continue;
581+ }
582+ msblk->next_fragment = nf;
583+
584+ if (msblk->fragment[i].data == NULL)
585+ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
586+ (SQUASHFS_FILE_MAX_SIZE))) {
587+ ERROR("Failed to allocate fragment "
588+ "cache block\n");
589+ up(&msblk->fragment_mutex);
590+ goto out;
591+ }
592+
593+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
594+ msblk->fragment[i].locked = 1;
595+ up(&msblk->fragment_mutex);
596+
597+ if (!(msblk->fragment[i].length = squashfs_read_data(s,
598+ msblk->fragment[i].data,
599+ start_block, length, NULL))) {
600+ ERROR("Unable to read fragment cache block "
601+ "[%llx]\n", start_block);
602+ msblk->fragment[i].locked = 0;
603+ goto out;
604+ }
605+
606+ msblk->fragment[i].block = start_block;
607+ TRACE("New fragment %d, start block %lld, locked %d\n",
608+ i, msblk->fragment[i].block,
609+ msblk->fragment[i].locked);
610+ break;
611+ }
612+
613+ msblk->fragment[i].locked++;
614+ up(&msblk->fragment_mutex);
615+ TRACE("Got fragment %d, start block %lld, locked %d\n", i,
616+ msblk->fragment[i].block,
617+ msblk->fragment[i].locked);
618+ break;
619+ }
620+
621+ return &msblk->fragment[i];
622+
623+out:
624+ return NULL;
625+}
626+
627+
628+static struct inode *squashfs_new_inode(struct super_block *s,
629+ struct squashfs_base_inode_header *inodeb)
630+{
631+ struct squashfs_sb_info *msblk = s->s_fs_info;
632+ struct inode *i = new_inode(s);
633+
634+ if (i) {
635+ i->i_ino = inodeb->inode_number;
636+ i->i_mtime.tv_sec = inodeb->mtime;
637+ i->i_atime.tv_sec = inodeb->mtime;
638+ i->i_ctime.tv_sec = inodeb->mtime;
639+ i->i_uid = msblk->uid[inodeb->uid];
640+ i->i_mode = inodeb->mode;
641+ i->i_size = 0;
642+ if (inodeb->guid == SQUASHFS_GUIDS)
643+ i->i_gid = i->i_uid;
644+ else
645+ i->i_gid = msblk->guid[inodeb->guid];
646+ }
647+
648+ return i;
649+}
650+
651+
652+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
653+{
654+ struct inode *i;
655+ struct squashfs_sb_info *msblk = s->s_fs_info;
656+ struct squashfs_super_block *sblk = &msblk->sblk;
657+ long long block = SQUASHFS_INODE_BLK(inode) +
658+ sblk->inode_table_start;
659+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
660+ long long next_block;
661+ unsigned int next_offset;
662+ union squashfs_inode_header id, sid;
663+ struct squashfs_base_inode_header *inodeb = &id.base,
664+ *sinodeb = &sid.base;
665+
666+ TRACE("Entered squashfs_iget\n");
667+
668+ if (msblk->swap) {
669+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
670+ offset, sizeof(*sinodeb), &next_block,
671+ &next_offset))
672+ goto failed_read;
673+ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
674+ sizeof(*sinodeb));
675+ } else
676+ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
677+ offset, sizeof(*inodeb), &next_block,
678+ &next_offset))
679+ goto failed_read;
680+
681+ switch(inodeb->inode_type) {
682+ case SQUASHFS_FILE_TYPE: {
683+ unsigned int frag_size;
684+ long long frag_blk;
685+ struct squashfs_reg_inode_header *inodep = &id.reg;
686+ struct squashfs_reg_inode_header *sinodep = &sid.reg;
687+
688+ if (msblk->swap) {
689+ if (!squashfs_get_cached_block(s, (char *)
690+ sinodep, block, offset,
691+ sizeof(*sinodep), &next_block,
692+ &next_offset))
693+ goto failed_read;
694+ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
695+ } else
696+ if (!squashfs_get_cached_block(s, (char *)
697+ inodep, block, offset,
698+ sizeof(*inodep), &next_block,
699+ &next_offset))
700+ goto failed_read;
701+
702+ frag_blk = SQUASHFS_INVALID_BLK;
703+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
704+ !get_fragment_location(s,
705+ inodep->fragment, &frag_blk, &frag_size))
706+ goto failed_read;
707+
708+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
709+ goto failed_read1;
710+
711+ i->i_nlink = 1;
712+ i->i_size = inodep->file_size;
713+ i->i_fop = &generic_ro_fops;
714+ i->i_mode |= S_IFREG;
715+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
716+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
717+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
718+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
719+ SQUASHFS_I(i)->start_block = inodep->start_block;
720+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
721+ SQUASHFS_I(i)->offset = next_offset;
722+ if (sblk->block_size > 4096)
723+ i->i_data.a_ops = &squashfs_aops;
724+ else
725+ i->i_data.a_ops = &squashfs_aops_4K;
726+
727+ TRACE("File inode %x:%x, start_block %llx, "
728+ "block_list_start %llx, offset %x\n",
729+ SQUASHFS_INODE_BLK(inode), offset,
730+ inodep->start_block, next_block,
731+ next_offset);
732+ break;
733+ }
734+ case SQUASHFS_LREG_TYPE: {
735+ unsigned int frag_size;
736+ long long frag_blk;
737+ struct squashfs_lreg_inode_header *inodep = &id.lreg;
738+ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
739+
740+ if (msblk->swap) {
741+ if (!squashfs_get_cached_block(s, (char *)
742+ sinodep, block, offset,
743+ sizeof(*sinodep), &next_block,
744+ &next_offset))
745+ goto failed_read;
746+ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
747+ } else
748+ if (!squashfs_get_cached_block(s, (char *)
749+ inodep, block, offset,
750+ sizeof(*inodep), &next_block,
751+ &next_offset))
752+ goto failed_read;
753+
754+ frag_blk = SQUASHFS_INVALID_BLK;
755+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
756+ !get_fragment_location(s,
757+ inodep->fragment, &frag_blk, &frag_size))
758+ goto failed_read;
759+
760+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
761+ goto failed_read1;
762+
763+ i->i_nlink = inodep->nlink;
764+ i->i_size = inodep->file_size;
765+ i->i_fop = &generic_ro_fops;
766+ i->i_mode |= S_IFREG;
767+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
768+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
769+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
770+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
771+ SQUASHFS_I(i)->start_block = inodep->start_block;
772+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
773+ SQUASHFS_I(i)->offset = next_offset;
774+ if (sblk->block_size > 4096)
775+ i->i_data.a_ops = &squashfs_aops;
776+ else
777+ i->i_data.a_ops = &squashfs_aops_4K;
778+
779+ TRACE("File inode %x:%x, start_block %llx, "
780+ "block_list_start %llx, offset %x\n",
781+ SQUASHFS_INODE_BLK(inode), offset,
782+ inodep->start_block, next_block,
783+ next_offset);
784+ break;
785+ }
786+ case SQUASHFS_DIR_TYPE: {
787+ struct squashfs_dir_inode_header *inodep = &id.dir;
788+ struct squashfs_dir_inode_header *sinodep = &sid.dir;
789+
790+ if (msblk->swap) {
791+ if (!squashfs_get_cached_block(s, (char *)
792+ sinodep, block, offset,
793+ sizeof(*sinodep), &next_block,
794+ &next_offset))
795+ goto failed_read;
796+ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
797+ } else
798+ if (!squashfs_get_cached_block(s, (char *)
799+ inodep, block, offset,
800+ sizeof(*inodep), &next_block,
801+ &next_offset))
802+ goto failed_read;
803+
804+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
805+ goto failed_read1;
806+
807+ i->i_nlink = inodep->nlink;
808+ i->i_size = inodep->file_size;
809+ i->i_op = &squashfs_dir_inode_ops;
810+ i->i_fop = &squashfs_dir_ops;
811+ i->i_mode |= S_IFDIR;
812+ SQUASHFS_I(i)->start_block = inodep->start_block;
813+ SQUASHFS_I(i)->offset = inodep->offset;
814+ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
815+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
816+
817+ TRACE("Directory inode %x:%x, start_block %x, offset "
818+ "%x\n", SQUASHFS_INODE_BLK(inode),
819+ offset, inodep->start_block,
820+ inodep->offset);
821+ break;
822+ }
823+ case SQUASHFS_LDIR_TYPE: {
824+ struct squashfs_ldir_inode_header *inodep = &id.ldir;
825+ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
826+
827+ if (msblk->swap) {
828+ if (!squashfs_get_cached_block(s, (char *)
829+ sinodep, block, offset,
830+ sizeof(*sinodep), &next_block,
831+ &next_offset))
832+ goto failed_read;
833+ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
834+ sinodep);
835+ } else
836+ if (!squashfs_get_cached_block(s, (char *)
837+ inodep, block, offset,
838+ sizeof(*inodep), &next_block,
839+ &next_offset))
840+ goto failed_read;
841+
842+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
843+ goto failed_read1;
844+
845+ i->i_nlink = inodep->nlink;
846+ i->i_size = inodep->file_size;
847+ i->i_op = &squashfs_dir_inode_ops;
848+ i->i_fop = &squashfs_dir_ops;
849+ i->i_mode |= S_IFDIR;
850+ SQUASHFS_I(i)->start_block = inodep->start_block;
851+ SQUASHFS_I(i)->offset = inodep->offset;
852+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
853+ SQUASHFS_I(i)->u.s2.directory_index_offset =
854+ next_offset;
855+ SQUASHFS_I(i)->u.s2.directory_index_count =
856+ inodep->i_count;
857+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
858+
859+ TRACE("Long directory inode %x:%x, start_block %x, "
860+ "offset %x\n",
861+ SQUASHFS_INODE_BLK(inode), offset,
862+ inodep->start_block, inodep->offset);
863+ break;
864+ }
865+ case SQUASHFS_SYMLINK_TYPE: {
866+ struct squashfs_symlink_inode_header *inodep =
867+ &id.symlink;
868+ struct squashfs_symlink_inode_header *sinodep =
869+ &sid.symlink;
870+
871+ if (msblk->swap) {
872+ if (!squashfs_get_cached_block(s, (char *)
873+ sinodep, block, offset,
874+ sizeof(*sinodep), &next_block,
875+ &next_offset))
876+ goto failed_read;
877+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
878+ sinodep);
879+ } else
880+ if (!squashfs_get_cached_block(s, (char *)
881+ inodep, block, offset,
882+ sizeof(*inodep), &next_block,
883+ &next_offset))
884+ goto failed_read;
885+
886+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
887+ goto failed_read1;
888+
889+ i->i_nlink = inodep->nlink;
890+ i->i_size = inodep->symlink_size;
891+ i->i_op = &page_symlink_inode_operations;
892+ i->i_data.a_ops = &squashfs_symlink_aops;
893+ i->i_mode |= S_IFLNK;
894+ SQUASHFS_I(i)->start_block = next_block;
895+ SQUASHFS_I(i)->offset = next_offset;
896+
897+ TRACE("Symbolic link inode %x:%x, start_block %llx, "
898+ "offset %x\n",
899+ SQUASHFS_INODE_BLK(inode), offset,
900+ next_block, next_offset);
901+ break;
902+ }
903+ case SQUASHFS_BLKDEV_TYPE:
904+ case SQUASHFS_CHRDEV_TYPE: {
905+ struct squashfs_dev_inode_header *inodep = &id.dev;
906+ struct squashfs_dev_inode_header *sinodep = &sid.dev;
907+
908+ if (msblk->swap) {
909+ if (!squashfs_get_cached_block(s, (char *)
910+ sinodep, block, offset,
911+ sizeof(*sinodep), &next_block,
912+ &next_offset))
913+ goto failed_read;
914+ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
915+ } else
916+ if (!squashfs_get_cached_block(s, (char *)
917+ inodep, block, offset,
918+ sizeof(*inodep), &next_block,
919+ &next_offset))
920+ goto failed_read;
921+
922+ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
923+ goto failed_read1;
924+
925+ i->i_nlink = inodep->nlink;
926+ i->i_mode |= (inodeb->inode_type ==
927+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
928+ S_IFBLK;
929+ init_special_inode(i, i->i_mode,
930+ old_decode_dev(inodep->rdev));
931+
932+ TRACE("Device inode %x:%x, rdev %x\n",
933+ SQUASHFS_INODE_BLK(inode), offset,
934+ inodep->rdev);
935+ break;
936+ }
937+ case SQUASHFS_FIFO_TYPE:
938+ case SQUASHFS_SOCKET_TYPE: {
939+ struct squashfs_ipc_inode_header *inodep = &id.ipc;
940+ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
941+
942+ if (msblk->swap) {
943+ if (!squashfs_get_cached_block(s, (char *)
944+ sinodep, block, offset,
945+ sizeof(*sinodep), &next_block,
946+ &next_offset))
947+ goto failed_read;
948+ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
949+ } else
950+ if (!squashfs_get_cached_block(s, (char *)
951+ inodep, block, offset,
952+ sizeof(*inodep), &next_block,
953+ &next_offset))
954+ goto failed_read;
955+
956+ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
957+ goto failed_read1;
958+
959+ i->i_nlink = inodep->nlink;
960+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
961+ ? S_IFIFO : S_IFSOCK;
962+ init_special_inode(i, i->i_mode, 0);
963+ break;
964+ }
965+ default:
966+ ERROR("Unknown inode type %d in squashfs_iget!\n",
967+ inodeb->inode_type);
968+ goto failed_read1;
969+ }
970+
971+ insert_inode_hash(i);
972+ return i;
973+
974+failed_read:
975+ ERROR("Unable to read inode [%llx:%x]\n", block, offset);
976+
977+failed_read1:
978+ return NULL;
979+}
980+
981+
982+static int read_fragment_index_table(struct super_block *s)
983+{
984+ struct squashfs_sb_info *msblk = s->s_fs_info;
985+ struct squashfs_super_block *sblk = &msblk->sblk;
986+
987+ /* Allocate fragment index table */
988+ if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
989+ (sblk->fragments), GFP_KERNEL))) {
990+ ERROR("Failed to allocate uid/gid table\n");
991+ return 0;
992+ }
993+
994+ if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
995+ !squashfs_read_data(s, (char *)
996+ msblk->fragment_index,
997+ sblk->fragment_table_start,
998+ SQUASHFS_FRAGMENT_INDEX_BYTES
999+ (sblk->fragments) |
1000+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
1001+ ERROR("unable to read fragment index table\n");
1002+ return 0;
1003+ }
1004+
1005+ if (msblk->swap) {
1006+ int i;
1007+ long long fragment;
1008+
1009+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
1010+ i++) {
1011+ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
1012+ &msblk->fragment_index[i], 1);
1013+ msblk->fragment_index[i] = fragment;
1014+ }
1015+ }
1016+
1017+ return 1;
1018+}
1019+
1020+
1021+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
1022+{
1023+ struct squashfs_super_block *sblk = &msblk->sblk;
1024+
1025+ msblk->iget = squashfs_iget;
1026+ msblk->read_blocklist = read_blocklist;
1027+ msblk->read_fragment_index_table = read_fragment_index_table;
1028+
1029+ if (sblk->s_major == 1) {
1030+ if (!squashfs_1_0_supported(msblk)) {
1031+ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
1032+ "are unsupported\n");
1033+ SERROR("Please recompile with "
1034+ "Squashfs 1.0 support enabled\n");
1035+ return 0;
1036+ }
1037+ } else if (sblk->s_major == 2) {
1038+ if (!squashfs_2_0_supported(msblk)) {
1039+ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
1040+ "are unsupported\n");
1041+ SERROR("Please recompile with "
1042+ "Squashfs 2.0 support enabled\n");
1043+ return 0;
1044+ }
1045+ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
1046+ SQUASHFS_MINOR) {
1047+ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
1048+ "filesystem\n", sblk->s_major, sblk->s_minor);
1049+ SERROR("Please update your kernel\n");
1050+ return 0;
1051+ }
1052+
1053+ return 1;
1054+}
1055+
1056+
1057+static int squashfs_fill_super(struct super_block *s, void *data, int silent)
1058+{
1059+ struct squashfs_sb_info *msblk;
1060+ struct squashfs_super_block *sblk;
1061+ int i;
1062+ char b[BDEVNAME_SIZE];
1063+ struct inode *root;
1064+
1065+ TRACE("Entered squashfs_read_superblock\n");
1066+
1067+ if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
1068+ GFP_KERNEL))) {
1069+ ERROR("Failed to allocate superblock\n");
1070+ goto failure;
1071+ }
1072+ memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
1073+ msblk = s->s_fs_info;
1074+ sblk = &msblk->sblk;
1075+
1076+ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
1077+ msblk->devblksize_log2 = ffz(~msblk->devblksize);
1078+
1079+ init_MUTEX(&msblk->read_data_mutex);
1080+ init_MUTEX(&msblk->read_page_mutex);
1081+ init_MUTEX(&msblk->block_cache_mutex);
1082+ init_MUTEX(&msblk->fragment_mutex);
1083+ init_MUTEX(&msblk->meta_index_mutex);
1084+
1085+ init_waitqueue_head(&msblk->waitq);
1086+ init_waitqueue_head(&msblk->fragment_wait_queue);
1087+
1088+ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
1089+ sizeof(struct squashfs_super_block) |
1090+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
1091+ SERROR("unable to read superblock\n");
1092+ goto failed_mount;
1093+ }
1094+
1095+ /* Check it is a SQUASHFS superblock */
1096+ msblk->swap = 0;
1097+ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
1098+ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
1099+ struct squashfs_super_block ssblk;
1100+
1101+ WARNING("Mounting a different endian SQUASHFS "
1102+ "filesystem on %s\n", bdevname(s->s_bdev, b));
1103+
1104+ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
1105+ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
1106+ msblk->swap = 1;
1107+ } else {
1108+ SERROR("Can't find a SQUASHFS superblock on %s\n",
1109+ bdevname(s->s_bdev, b));
1110+ goto failed_mount;
1111+ }
1112+ }
1113+
1114+ /* Check the MAJOR & MINOR versions */
1115+ if(!supported_squashfs_filesystem(msblk, silent))
1116+ goto failed_mount;
1117+
1118+ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
1119+ TRACE("Inodes are %scompressed\n",
1120+ SQUASHFS_UNCOMPRESSED_INODES
1121+ (sblk->flags) ? "un" : "");
1122+ TRACE("Data is %scompressed\n",
1123+ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
1124+ ? "un" : "");
1125+ TRACE("Check data is %s present in the filesystem\n",
1126+ SQUASHFS_CHECK_DATA(sblk->flags) ?
1127+ "" : "not");
1128+ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
1129+ TRACE("Block size %d\n", sblk->block_size);
1130+ TRACE("Number of inodes %d\n", sblk->inodes);
1131+ if (sblk->s_major > 1)
1132+ TRACE("Number of fragments %d\n", sblk->fragments);
1133+ TRACE("Number of uids %d\n", sblk->no_uids);
1134+ TRACE("Number of gids %d\n", sblk->no_guids);
1135+ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
1136+ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
1137+ if (sblk->s_major > 1)
1138+ TRACE("sblk->fragment_table_start %llx\n",
1139+ sblk->fragment_table_start);
1140+ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
1141+
1142+ s->s_flags |= MS_RDONLY;
1143+ s->s_op = &squashfs_ops;
1144+
1145+ /* Init inode_table block pointer array */
1146+ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
1147+ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
1148+ ERROR("Failed to allocate block cache\n");
1149+ goto failed_mount;
1150+ }
1151+
1152+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
1153+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
1154+
1155+ msblk->next_cache = 0;
1156+
1157+ /* Allocate read_data block */
1158+ msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
1159+ SQUASHFS_METADATA_SIZE :
1160+ sblk->block_size;
1161+
1162+ if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
1163+ ERROR("Failed to allocate read_data block\n");
1164+ goto failed_mount;
1165+ }
1166+
1167+ /* Allocate read_page block */
1168+ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
1169+ ERROR("Failed to allocate read_page block\n");
1170+ goto failed_mount;
1171+ }
1172+
1173+ /* Allocate uid and gid tables */
1174+ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
1175+ sizeof(unsigned int), GFP_KERNEL))) {
1176+ ERROR("Failed to allocate uid/gid table\n");
1177+ goto failed_mount;
1178+ }
1179+ msblk->guid = msblk->uid + sblk->no_uids;
1180+
1181+ if (msblk->swap) {
1182+ unsigned int suid[sblk->no_uids + sblk->no_guids];
1183+
1184+ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
1185+ ((sblk->no_uids + sblk->no_guids) *
1186+ sizeof(unsigned int)) |
1187+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
1188+ ERROR("unable to read uid/gid table\n");
1189+ goto failed_mount;
1190+ }
1191+
1192+ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
1193+ sblk->no_guids), (sizeof(unsigned int) * 8));
1194+ } else
1195+ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
1196+ ((sblk->no_uids + sblk->no_guids) *
1197+ sizeof(unsigned int)) |
1198+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
1199+ ERROR("unable to read uid/gid table\n");
1200+ goto failed_mount;
1201+ }
1202+
1203+
1204+ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
1205+ goto allocate_root;
1206+
1207+ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
1208+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
1209+ ERROR("Failed to allocate fragment block cache\n");
1210+ goto failed_mount;
1211+ }
1212+
1213+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
1214+ msblk->fragment[i].locked = 0;
1215+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
1216+ msblk->fragment[i].data = NULL;
1217+ }
1218+
1219+ msblk->next_fragment = 0;
1220+
1221+ /* Allocate fragment index table */
1222+ if (msblk->read_fragment_index_table(s) == 0)
1223+ goto failed_mount;
1224+
1225+allocate_root:
1226+ if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
1227+ goto failed_mount;
1228+
1229+ if ((s->s_root = d_alloc_root(root)) == NULL) {
1230+ ERROR("Root inode create failed\n");
1231+ iput(root);
1232+ goto failed_mount;
1233+ }
1234+
1235+ TRACE("Leaving squashfs_read_super\n");
1236+ return 0;
1237+
1238+failed_mount:
1239+ kfree(msblk->fragment_index);
1240+ kfree(msblk->fragment);
1241+ kfree(msblk->uid);
1242+ kfree(msblk->read_page);
1243+ kfree(msblk->read_data);
1244+ kfree(msblk->block_cache);
1245+ kfree(msblk->fragment_index_2);
1246+ kfree(s->s_fs_info);
1247+ s->s_fs_info = NULL;
1248+ return -EINVAL;
1249+
1250+failure:
1251+ return -ENOMEM;
1252+}
1253+
1254+
1255+static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1256+{
1257+ struct super_block *s = dentry->d_sb;
1258+ struct squashfs_sb_info *msblk = s->s_fs_info;
1259+ struct squashfs_super_block *sblk = &msblk->sblk;
1260+
1261+ TRACE("Entered squashfs_statfs\n");
1262+
1263+ buf->f_type = SQUASHFS_MAGIC;
1264+ buf->f_bsize = sblk->block_size;
1265+ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
1266+ buf->f_bfree = buf->f_bavail = 0;
1267+ buf->f_files = sblk->inodes;
1268+ buf->f_ffree = 0;
1269+ buf->f_namelen = SQUASHFS_NAME_LEN;
1270+
1271+ return 0;
1272+}
1273+
1274+
1275+static int squashfs_symlink_readpage(struct file *file, struct page *page)
1276+{
1277+ struct inode *inode = page->mapping->host;
1278+ int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
1279+ long long block = SQUASHFS_I(inode)->start_block;
1280+ int offset = SQUASHFS_I(inode)->offset;
1281+ void *pageaddr = kmap(page);
1282+
1283+ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
1284+ "%llx, offset %x\n", page->index,
1285+ SQUASHFS_I(inode)->start_block,
1286+ SQUASHFS_I(inode)->offset);
1287+
1288+ for (length = 0; length < index; length += bytes) {
1289+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
1290+ block, offset, PAGE_CACHE_SIZE, &block,
1291+ &offset))) {
1292+ ERROR("Unable to read symbolic link [%llx:%x]\n", block,
1293+ offset);
1294+ goto skip_read;
1295+ }
1296+ }
1297+
1298+ if (length != index) {
1299+ ERROR("(squashfs_symlink_readpage) length != index\n");
1300+ bytes = 0;
1301+ goto skip_read;
1302+ }
1303+
1304+ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
1305+ i_size_read(inode) - length;
1306+
1307+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
1308+ offset, bytes, &block, &offset)))
1309+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1310+
1311+skip_read:
1312+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1313+ kunmap(page);
1314+ SetPageUptodate(page);
1315+ unlock_page(page);
1316+
1317+ return 0;
1318+}
1319+
1320+
1321+struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
1322+{
1323+ struct meta_index *meta = NULL;
1324+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1325+ int i;
1326+
1327+ down(&msblk->meta_index_mutex);
1328+
1329+ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
1330+
1331+ if(msblk->meta_index == NULL)
1332+ goto not_allocated;
1333+
1334+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
1335+ if (msblk->meta_index[i].inode_number == inode->i_ino &&
1336+ msblk->meta_index[i].offset >= offset &&
1337+ msblk->meta_index[i].offset <= index &&
1338+ msblk->meta_index[i].locked == 0) {
1339+ TRACE("locate_meta_index: entry %d, offset %d\n", i,
1340+ msblk->meta_index[i].offset);
1341+ meta = &msblk->meta_index[i];
1342+ offset = meta->offset;
1343+ }
1344+
1345+ if (meta)
1346+ meta->locked = 1;
1347+
1348+not_allocated:
1349+ up(&msblk->meta_index_mutex);
1350+
1351+ return meta;
1352+}
1353+
1354+
1355+struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
1356+{
1357+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1358+ struct meta_index *meta = NULL;
1359+ int i;
1360+
1361+ down(&msblk->meta_index_mutex);
1362+
1363+ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
1364+
1365+ if(msblk->meta_index == NULL) {
1366+ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
1367+ SQUASHFS_META_NUMBER, GFP_KERNEL))) {
1368+ ERROR("Failed to allocate meta_index\n");
1369+ goto failed;
1370+ }
1371+ for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
1372+ msblk->meta_index[i].inode_number = 0;
1373+ msblk->meta_index[i].locked = 0;
1374+ }
1375+ msblk->next_meta_index = 0;
1376+ }
1377+
1378+ for(i = SQUASHFS_META_NUMBER; i &&
1379+ msblk->meta_index[msblk->next_meta_index].locked; i --)
1380+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
1381+ SQUASHFS_META_NUMBER;
1382+
1383+ if(i == 0) {
1384+ TRACE("empty_meta_index: failed!\n");
1385+ goto failed;
1386+ }
1387+
1388+ TRACE("empty_meta_index: returned meta entry %d, %p\n",
1389+ msblk->next_meta_index,
1390+ &msblk->meta_index[msblk->next_meta_index]);
1391+
1392+ meta = &msblk->meta_index[msblk->next_meta_index];
1393+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
1394+ SQUASHFS_META_NUMBER;
1395+
1396+ meta->inode_number = inode->i_ino;
1397+ meta->offset = offset;
1398+ meta->skip = skip;
1399+ meta->entries = 0;
1400+ meta->locked = 1;
1401+
1402+failed:
1403+ up(&msblk->meta_index_mutex);
1404+ return meta;
1405+}
1406+
1407+
1408+void release_meta_index(struct inode *inode, struct meta_index *meta)
1409+{
1410+ meta->locked = 0;
1411+}
1412+
1413+
1414+static int read_block_index(struct super_block *s, int blocks, char *block_list,
1415+ long long *start_block, int *offset)
1416+{
1417+ struct squashfs_sb_info *msblk = s->s_fs_info;
1418+ unsigned int *block_listp;
1419+ int block = 0;
1420+
1421+ if (msblk->swap) {
1422+ char sblock_list[blocks << 2];
1423+
1424+ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
1425+ *offset, blocks << 2, start_block, offset)) {
1426+ ERROR("Unable to read block list [%llx:%x]\n",
1427+ *start_block, *offset);
1428+ goto failure;
1429+ }
1430+ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
1431+ ((unsigned int *)sblock_list), blocks);
1432+ } else
1433+ if (!squashfs_get_cached_block(s, block_list, *start_block,
1434+ *offset, blocks << 2, start_block, offset)) {
1435+ ERROR("Unable to read block list [%llx:%x]\n",
1436+ *start_block, *offset);
1437+ goto failure;
1438+ }
1439+
1440+ for (block_listp = (unsigned int *) block_list; blocks;
1441+ block_listp++, blocks --)
1442+ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
1443+
1444+ return block;
1445+
1446+failure:
1447+ return -1;
1448+}
1449+
1450+
1451+#define SIZE 256
1452+
1453+static inline int calculate_skip(int blocks) {
1454+ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
1455+ return skip >= 7 ? 7 : skip + 1;
1456+}
1457+
1458+
1459+static int get_meta_index(struct inode *inode, int index,
1460+ long long *index_block, int *index_offset,
1461+ long long *data_block, char *block_list)
1462+{
1463+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1464+ struct squashfs_super_block *sblk = &msblk->sblk;
1465+ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
1466+ int offset = 0;
1467+ struct meta_index *meta;
1468+ struct meta_entry *meta_entry;
1469+ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
1470+ int cur_offset = SQUASHFS_I(inode)->offset;
1471+ long long cur_data_block = SQUASHFS_I(inode)->start_block;
1472+ int i;
1473+
1474+ index /= SQUASHFS_META_INDEXES * skip;
1475+
1476+ while ( offset < index ) {
1477+ meta = locate_meta_index(inode, index, offset + 1);
1478+
1479+ if (meta == NULL) {
1480+ if ((meta = empty_meta_index(inode, offset + 1,
1481+ skip)) == NULL)
1482+ goto all_done;
1483+ } else {
1484+ offset = index < meta->offset + meta->entries ? index :
1485+ meta->offset + meta->entries - 1;
1486+ meta_entry = &meta->meta_entry[offset - meta->offset];
1487+ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
1488+ cur_offset = meta_entry->offset;
1489+ cur_data_block = meta_entry->data_block;
1490+ TRACE("get_meta_index: offset %d, meta->offset %d, "
1491+ "meta->entries %d\n", offset, meta->offset,
1492+ meta->entries);
1493+ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
1494+ " data_block 0x%llx\n", cur_index_block,
1495+ cur_offset, cur_data_block);
1496+ }
1497+
1498+ for (i = meta->offset + meta->entries; i <= index &&
1499+ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
1500+ int blocks = skip * SQUASHFS_META_INDEXES;
1501+
1502+ while (blocks) {
1503+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
1504+ blocks;
1505+ int res = read_block_index(inode->i_sb, block,
1506+ block_list, &cur_index_block,
1507+ &cur_offset);
1508+
1509+ if (res == -1)
1510+ goto failed;
1511+
1512+ cur_data_block += res;
1513+ blocks -= block;
1514+ }
1515+
1516+ meta_entry = &meta->meta_entry[i - meta->offset];
1517+ meta_entry->index_block = cur_index_block - sblk->inode_table_start;
1518+ meta_entry->offset = cur_offset;
1519+ meta_entry->data_block = cur_data_block;
1520+ meta->entries ++;
1521+ offset ++;
1522+ }
1523+
1524+ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
1525+ meta->offset, meta->entries);
1526+
1527+ release_meta_index(inode, meta);
1528+ }
1529+
1530+all_done:
1531+ *index_block = cur_index_block;
1532+ *index_offset = cur_offset;
1533+ *data_block = cur_data_block;
1534+
1535+ return offset * SQUASHFS_META_INDEXES * skip;
1536+
1537+failed:
1538+ release_meta_index(inode, meta);
1539+ return -1;
1540+}
1541+
1542+
1543+static long long read_blocklist(struct inode *inode, int index,
1544+ int readahead_blks, char *block_list,
1545+ unsigned short **block_p, unsigned int *bsize)
1546+{
1547+ long long block_ptr;
1548+ int offset;
1549+ long long block;
1550+ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
1551+ block_list);
1552+
1553+ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
1554+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
1555+ block);
1556+
1557+ if(res == -1)
1558+ goto failure;
1559+
1560+ index -= res;
1561+
1562+ while ( index ) {
1563+ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
1564+ int res = read_block_index(inode->i_sb, blocks, block_list,
1565+ &block_ptr, &offset);
1566+ if (res == -1)
1567+ goto failure;
1568+ block += res;
1569+ index -= blocks;
1570+ }
1571+
1572+ if (read_block_index(inode->i_sb, 1, block_list,
1573+ &block_ptr, &offset) == -1)
1574+ goto failure;
1575+ *bsize = *((unsigned int *) block_list);
1576+
1577+ return block;
1578+
1579+failure:
1580+ return 0;
1581+}
1582+
1583+
1584+static int squashfs_readpage(struct file *file, struct page *page)
1585+{
1586+ struct inode *inode = page->mapping->host;
1587+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1588+ struct squashfs_super_block *sblk = &msblk->sblk;
1589+ unsigned char block_list[SIZE];
1590+ long long block;
1591+ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
1592+ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
1593+ void *pageaddr;
1594+ struct squashfs_fragment_cache *fragment = NULL;
1595+ char *data_ptr = msblk->read_page;
1596+
1597+ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
1598+ int start_index = page->index & ~mask;
1599+ int end_index = start_index | mask;
1600+
1601+ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
1602+ page->index,
1603+ SQUASHFS_I(inode)->start_block);
1604+
1605+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1606+ PAGE_CACHE_SHIFT))
1607+ goto skip_read;
1608+
1609+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1610+ || index < (i_size_read(inode) >>
1611+ sblk->block_log)) {
1612+ if ((block = (msblk->read_blocklist)(inode, index, 1,
1613+ block_list, NULL, &bsize)) == 0)
1614+ goto skip_read;
1615+
1616+ down(&msblk->read_page_mutex);
1617+
1618+ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
1619+ block, bsize, NULL))) {
1620+ ERROR("Unable to read page, block %llx, size %x\n", block,
1621+ bsize);
1622+ up(&msblk->read_page_mutex);
1623+ goto skip_read;
1624+ }
1625+ } else {
1626+ if ((fragment = get_cached_fragment(inode->i_sb,
1627+ SQUASHFS_I(inode)->
1628+ u.s1.fragment_start_block,
1629+ SQUASHFS_I(inode)->u.s1.fragment_size))
1630+ == NULL) {
1631+ ERROR("Unable to read page, block %llx, size %x\n",
1632+ SQUASHFS_I(inode)->
1633+ u.s1.fragment_start_block,
1634+ (int) SQUASHFS_I(inode)->
1635+ u.s1.fragment_size);
1636+ goto skip_read;
1637+ }
1638+ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
1639+ (i_size_read(inode) & (sblk->block_size
1640+ - 1));
1641+ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
1642+ data_ptr = fragment->data;
1643+ }
1644+
1645+ for (i = start_index; i <= end_index && byte_offset < bytes;
1646+ i++, byte_offset += PAGE_CACHE_SIZE) {
1647+ struct page *push_page;
1648+ int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
1649+ PAGE_CACHE_SIZE : bytes - byte_offset;
1650+
1651+ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
1652+ bytes, i, byte_offset, available_bytes);
1653+
1654+ if (i == page->index) {
1655+ pageaddr = kmap_atomic(page, KM_USER0);
1656+ memcpy(pageaddr, data_ptr + byte_offset,
1657+ available_bytes);
1658+ memset(pageaddr + available_bytes, 0,
1659+ PAGE_CACHE_SIZE - available_bytes);
1660+ kunmap_atomic(pageaddr, KM_USER0);
1661+ flush_dcache_page(page);
1662+ SetPageUptodate(page);
1663+ unlock_page(page);
1664+ } else if ((push_page =
1665+ grab_cache_page_nowait(page->mapping, i))) {
1666+ pageaddr = kmap_atomic(push_page, KM_USER0);
1667+
1668+ memcpy(pageaddr, data_ptr + byte_offset,
1669+ available_bytes);
1670+ memset(pageaddr + available_bytes, 0,
1671+ PAGE_CACHE_SIZE - available_bytes);
1672+ kunmap_atomic(pageaddr, KM_USER0);
1673+ flush_dcache_page(push_page);
1674+ SetPageUptodate(push_page);
1675+ unlock_page(push_page);
1676+ page_cache_release(push_page);
1677+ }
1678+ }
1679+
1680+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1681+ || index < (i_size_read(inode) >>
1682+ sblk->block_log))
1683+ up(&msblk->read_page_mutex);
1684+ else
1685+ release_cached_fragment(msblk, fragment);
1686+
1687+ return 0;
1688+
1689+skip_read:
1690+ pageaddr = kmap_atomic(page, KM_USER0);
1691+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1692+ kunmap_atomic(pageaddr, KM_USER0);
1693+ flush_dcache_page(page);
1694+ SetPageUptodate(page);
1695+ unlock_page(page);
1696+
1697+ return 0;
1698+}
1699+
1700+
1701+static int squashfs_readpage4K(struct file *file, struct page *page)
1702+{
1703+ struct inode *inode = page->mapping->host;
1704+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1705+ struct squashfs_super_block *sblk = &msblk->sblk;
1706+ unsigned char block_list[SIZE];
1707+ long long block;
1708+ unsigned int bsize, bytes = 0;
1709+ void *pageaddr;
1710+
1711+ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
1712+ page->index,
1713+ SQUASHFS_I(inode)->start_block);
1714+
1715+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1716+ PAGE_CACHE_SHIFT)) {
1717+ pageaddr = kmap_atomic(page, KM_USER0);
1718+ goto skip_read;
1719+ }
1720+
1721+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1722+ || page->index < (i_size_read(inode) >>
1723+ sblk->block_log)) {
1724+ block = (msblk->read_blocklist)(inode, page->index, 1,
1725+ block_list, NULL, &bsize);
1726+
1727+ down(&msblk->read_page_mutex);
1728+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
1729+ bsize, NULL);
1730+ pageaddr = kmap_atomic(page, KM_USER0);
1731+ if (bytes)
1732+ memcpy(pageaddr, msblk->read_page, bytes);
1733+ else
1734+ ERROR("Unable to read page, block %llx, size %x\n",
1735+ block, bsize);
1736+ up(&msblk->read_page_mutex);
1737+ } else {
1738+ struct squashfs_fragment_cache *fragment =
1739+ get_cached_fragment(inode->i_sb,
1740+ SQUASHFS_I(inode)->
1741+ u.s1.fragment_start_block,
1742+ SQUASHFS_I(inode)-> u.s1.fragment_size);
1743+ pageaddr = kmap_atomic(page, KM_USER0);
1744+ if (fragment) {
1745+ bytes = i_size_read(inode) & (sblk->block_size - 1);
1746+ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
1747+ u.s1.fragment_offset, bytes);
1748+ release_cached_fragment(msblk, fragment);
1749+ } else
1750+ ERROR("Unable to read page, block %llx, size %x\n",
1751+ SQUASHFS_I(inode)->
1752+ u.s1.fragment_start_block, (int)
1753+ SQUASHFS_I(inode)-> u.s1.fragment_size);
1754+ }
1755+
1756+skip_read:
1757+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1758+ kunmap_atomic(pageaddr, KM_USER0);
1759+ flush_dcache_page(page);
1760+ SetPageUptodate(page);
1761+ unlock_page(page);
1762+
1763+ return 0;
1764+}
1765+
1766+
1767+static int get_dir_index_using_offset(struct super_block *s, long long
1768+ *next_block, unsigned int *next_offset,
1769+ long long index_start,
1770+ unsigned int index_offset, int i_count,
1771+ long long f_pos)
1772+{
1773+ struct squashfs_sb_info *msblk = s->s_fs_info;
1774+ struct squashfs_super_block *sblk = &msblk->sblk;
1775+ int i, length = 0;
1776+ struct squashfs_dir_index index;
1777+
1778+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
1779+ i_count, (unsigned int) f_pos);
1780+
1781+ f_pos =- 3;
1782+ if (f_pos == 0)
1783+ goto finish;
1784+
1785+ for (i = 0; i < i_count; i++) {
1786+ if (msblk->swap) {
1787+ struct squashfs_dir_index sindex;
1788+ squashfs_get_cached_block(s, (char *) &sindex,
1789+ index_start, index_offset,
1790+ sizeof(sindex), &index_start,
1791+ &index_offset);
1792+ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
1793+ } else
1794+ squashfs_get_cached_block(s, (char *) &index,
1795+ index_start, index_offset,
1796+ sizeof(index), &index_start,
1797+ &index_offset);
1798+
1799+ if (index.index > f_pos)
1800+ break;
1801+
1802+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
1803+ index.size + 1, &index_start,
1804+ &index_offset);
1805+
1806+ length = index.index;
1807+ *next_block = index.start_block + sblk->directory_table_start;
1808+ }
1809+
1810+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1811+
1812+finish:
1813+ return length + 3;
1814+}
1815+
1816+
1817+static int get_dir_index_using_name(struct super_block *s, long long
1818+ *next_block, unsigned int *next_offset,
1819+ long long index_start,
1820+ unsigned int index_offset, int i_count,
1821+ const char *name, int size)
1822+{
1823+ struct squashfs_sb_info *msblk = s->s_fs_info;
1824+ struct squashfs_super_block *sblk = &msblk->sblk;
1825+ int i, length = 0;
1826+ char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
1827+ struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
1828+ char str[SQUASHFS_NAME_LEN + 1];
1829+
1830+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
1831+
1832+ strncpy(str, name, size);
1833+ str[size] = '\0';
1834+
1835+ for (i = 0; i < i_count; i++) {
1836+ if (msblk->swap) {
1837+ struct squashfs_dir_index sindex;
1838+ squashfs_get_cached_block(s, (char *) &sindex,
1839+ index_start, index_offset,
1840+ sizeof(sindex), &index_start,
1841+ &index_offset);
1842+ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
1843+ } else
1844+ squashfs_get_cached_block(s, (char *) index,
1845+ index_start, index_offset,
1846+ sizeof(struct squashfs_dir_index),
1847+ &index_start, &index_offset);
1848+
1849+ squashfs_get_cached_block(s, index->name, index_start,
1850+ index_offset, index->size + 1,
1851+ &index_start, &index_offset);
1852+
1853+ index->name[index->size + 1] = '\0';
1854+
1855+ if (strcmp(index->name, str) > 0)
1856+ break;
1857+
1858+ length = index->index;
1859+ *next_block = index->start_block + sblk->directory_table_start;
1860+ }
1861+
1862+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1863+ return length + 3;
1864+}
1865+
1866+
1867+static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
1868+{
1869+ struct inode *i = file->f_dentry->d_inode;
1870+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
1871+ struct squashfs_super_block *sblk = &msblk->sblk;
1872+ long long next_block = SQUASHFS_I(i)->start_block +
1873+ sblk->directory_table_start;
1874+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
1875+ dir_count;
1876+ struct squashfs_dir_header dirh;
1877+ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
1878+ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
1879+
1880+ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
1881+
1882+ while(file->f_pos < 3) {
1883+ char *name;
1884+ int size, i_ino;
1885+
1886+ if(file->f_pos == 0) {
1887+ name = ".";
1888+ size = 1;
1889+ i_ino = i->i_ino;
1890+ } else {
1891+ name = "..";
1892+ size = 2;
1893+ i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
1894+ }
1895+ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
1896+ (unsigned int) dirent, name, size, (int)
1897+ file->f_pos, i_ino,
1898+ squashfs_filetype_table[1]);
1899+
1900+ if (filldir(dirent, name, size,
1901+ file->f_pos, i_ino,
1902+ squashfs_filetype_table[1]) < 0) {
1903+ TRACE("Filldir returned less than 0\n");
1904+ goto finish;
1905+ }
1906+ file->f_pos += size;
1907+ dirs_read++;
1908+ }
1909+
1910+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
1911+ SQUASHFS_I(i)->u.s2.directory_index_start,
1912+ SQUASHFS_I(i)->u.s2.directory_index_offset,
1913+ SQUASHFS_I(i)->u.s2.directory_index_count,
1914+ file->f_pos);
1915+
1916+ while (length < i_size_read(i)) {
1917+ /* read directory header */
1918+ if (msblk->swap) {
1919+ struct squashfs_dir_header sdirh;
1920+
1921+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
1922+ next_block, next_offset, sizeof(sdirh),
1923+ &next_block, &next_offset))
1924+ goto failed_read;
1925+
1926+ length += sizeof(sdirh);
1927+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
1928+ } else {
1929+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
1930+ next_block, next_offset, sizeof(dirh),
1931+ &next_block, &next_offset))
1932+ goto failed_read;
1933+
1934+ length += sizeof(dirh);
1935+ }
1936+
1937+ dir_count = dirh.count + 1;
1938+ while (dir_count--) {
1939+ if (msblk->swap) {
1940+ struct squashfs_dir_entry sdire;
1941+ if (!squashfs_get_cached_block(i->i_sb, (char *)
1942+ &sdire, next_block, next_offset,
1943+ sizeof(sdire), &next_block,
1944+ &next_offset))
1945+ goto failed_read;
1946+
1947+ length += sizeof(sdire);
1948+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
1949+ } else {
1950+ if (!squashfs_get_cached_block(i->i_sb, (char *)
1951+ dire, next_block, next_offset,
1952+ sizeof(*dire), &next_block,
1953+ &next_offset))
1954+ goto failed_read;
1955+
1956+ length += sizeof(*dire);
1957+ }
1958+
1959+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
1960+ next_block, next_offset,
1961+ dire->size + 1, &next_block,
1962+ &next_offset))
1963+ goto failed_read;
1964+
1965+ length += dire->size + 1;
1966+
1967+ if (file->f_pos >= length)
1968+ continue;
1969+
1970+ dire->name[dire->size + 1] = '\0';
1971+
1972+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
1973+ (unsigned int) dirent, dire->name,
1974+ dire->size + 1, (int) file->f_pos,
1975+ dirh.start_block, dire->offset,
1976+ dirh.inode_number + dire->inode_number,
1977+ squashfs_filetype_table[dire->type]);
1978+
1979+ if (filldir(dirent, dire->name, dire->size + 1,
1980+ file->f_pos,
1981+ dirh.inode_number + dire->inode_number,
1982+ squashfs_filetype_table[dire->type])
1983+ < 0) {
1984+ TRACE("Filldir returned less than 0\n");
1985+ goto finish;
1986+ }
1987+ file->f_pos = length;
1988+ dirs_read++;
1989+ }
1990+ }
1991+
1992+finish:
1993+ return dirs_read;
1994+
1995+failed_read:
1996+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
1997+ next_offset);
1998+ return 0;
1999+}
2000+
2001+
2002+static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
2003+ struct nameidata *nd)
2004+{
2005+ const unsigned char *name = dentry->d_name.name;
2006+ int len = dentry->d_name.len;
2007+ struct inode *inode = NULL;
2008+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2009+ struct squashfs_super_block *sblk = &msblk->sblk;
2010+ long long next_block = SQUASHFS_I(i)->start_block +
2011+ sblk->directory_table_start;
2012+ int next_offset = SQUASHFS_I(i)->offset, length = 0,
2013+ dir_count;
2014+ struct squashfs_dir_header dirh;
2015+ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
2016+ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
2017+
2018+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
2019+
2020+ if (len > SQUASHFS_NAME_LEN)
2021+ goto exit_loop;
2022+
2023+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
2024+ SQUASHFS_I(i)->u.s2.directory_index_start,
2025+ SQUASHFS_I(i)->u.s2.directory_index_offset,
2026+ SQUASHFS_I(i)->u.s2.directory_index_count, name,
2027+ len);
2028+
2029+ while (length < i_size_read(i)) {
2030+ /* read directory header */
2031+ if (msblk->swap) {
2032+ struct squashfs_dir_header sdirh;
2033+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2034+ next_block, next_offset, sizeof(sdirh),
2035+ &next_block, &next_offset))
2036+ goto failed_read;
2037+
2038+ length += sizeof(sdirh);
2039+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
2040+ } else {
2041+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2042+ next_block, next_offset, sizeof(dirh),
2043+ &next_block, &next_offset))
2044+ goto failed_read;
2045+
2046+ length += sizeof(dirh);
2047+ }
2048+
2049+ dir_count = dirh.count + 1;
2050+ while (dir_count--) {
2051+ if (msblk->swap) {
2052+ struct squashfs_dir_entry sdire;
2053+ if (!squashfs_get_cached_block(i->i_sb, (char *)
2054+ &sdire, next_block,next_offset,
2055+ sizeof(sdire), &next_block,
2056+ &next_offset))
2057+ goto failed_read;
2058+
2059+ length += sizeof(sdire);
2060+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2061+ } else {
2062+ if (!squashfs_get_cached_block(i->i_sb, (char *)
2063+ dire, next_block,next_offset,
2064+ sizeof(*dire), &next_block,
2065+ &next_offset))
2066+ goto failed_read;
2067+
2068+ length += sizeof(*dire);
2069+ }
2070+
2071+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
2072+ next_block, next_offset, dire->size + 1,
2073+ &next_block, &next_offset))
2074+ goto failed_read;
2075+
2076+ length += dire->size + 1;
2077+
2078+ if (name[0] < dire->name[0])
2079+ goto exit_loop;
2080+
2081+ if ((len == dire->size + 1) && !strncmp(name,
2082+ dire->name, len)) {
2083+ squashfs_inode_t ino =
2084+ SQUASHFS_MKINODE(dirh.start_block,
2085+ dire->offset);
2086+
2087+ TRACE("calling squashfs_iget for directory "
2088+ "entry %s, inode %x:%x, %d\n", name,
2089+ dirh.start_block, dire->offset,
2090+ dirh.inode_number + dire->inode_number);
2091+
2092+ inode = (msblk->iget)(i->i_sb, ino);
2093+
2094+ goto exit_loop;
2095+ }
2096+ }
2097+ }
2098+
2099+exit_loop:
2100+ d_add(dentry, inode);
2101+ return ERR_PTR(0);
2102+
2103+failed_read:
2104+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2105+ next_offset);
2106+ goto exit_loop;
2107+}
2108+
2109+
2110+static void squashfs_put_super(struct super_block *s)
2111+{
2112+ int i;
2113+
2114+ if (s->s_fs_info) {
2115+ struct squashfs_sb_info *sbi = s->s_fs_info;
2116+ if (sbi->block_cache)
2117+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
2118+ if (sbi->block_cache[i].block !=
2119+ SQUASHFS_INVALID_BLK)
2120+ kfree(sbi->block_cache[i].data);
2121+ if (sbi->fragment)
2122+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
2123+ SQUASHFS_FREE(sbi->fragment[i].data);
2124+ kfree(sbi->fragment);
2125+ kfree(sbi->block_cache);
2126+ kfree(sbi->read_data);
2127+ kfree(sbi->read_page);
2128+ kfree(sbi->uid);
2129+ kfree(sbi->fragment_index);
2130+ kfree(sbi->fragment_index_2);
2131+ kfree(sbi->meta_index);
2132+ kfree(s->s_fs_info);
2133+ s->s_fs_info = NULL;
2134+ }
2135+}
2136+
2137+
2138+static int squashfs_get_sb(struct file_system_type *fs_type,
2139+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
2140+{
2141+ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, mnt);
2142+}
2143+
2144+
2145+static int __init init_squashfs_fs(void)
2146+{
2147+ int err = init_inodecache();
2148+ if (err)
2149+ goto out;
2150+
2151+ printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
2152+ "Phillip Lougher\n");
2153+
2154+ if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
2155+ ERROR("Failed to allocate zlib workspace\n");
2156+ destroy_inodecache();
2157+ err = -ENOMEM;
2158+ goto out;
2159+ }
2160+
2161+ if ((err = register_filesystem(&squashfs_fs_type))) {
2162+ vfree(stream.workspace);
2163+ destroy_inodecache();
2164+ }
2165+
2166+out:
2167+ return err;
2168+}
2169+
2170+
2171+static void __exit exit_squashfs_fs(void)
2172+{
2173+ vfree(stream.workspace);
2174+ unregister_filesystem(&squashfs_fs_type);
2175+ destroy_inodecache();
2176+}
2177+
2178+
2179+static struct kmem_cache* squashfs_inode_cachep;
2180+
2181+
2182+static struct inode *squashfs_alloc_inode(struct super_block *sb)
2183+{
2184+ struct squashfs_inode_info *ei;
2185+ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
2186+ if (!ei)
2187+ return NULL;
2188+ return &ei->vfs_inode;
2189+}
2190+
2191+
2192+static void squashfs_destroy_inode(struct inode *inode)
2193+{
2194+ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
2195+}
2196+
2197+
2198+static void init_once(void * foo, struct kmem_cache *cachep, unsigned long flags)
2199+{
2200+ struct squashfs_inode_info *ei = foo;
2201+
2202+ inode_init_once(&ei->vfs_inode);
2203+}
2204+
2205+
2206+static int __init init_inodecache(void)
2207+{
2208+ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
2209+ sizeof(struct squashfs_inode_info),
2210+ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
2211+ init_once);
2212+ if (squashfs_inode_cachep == NULL)
2213+ return -ENOMEM;
2214+ return 0;
2215+}
2216+
2217+
2218+static void destroy_inodecache(void)
2219+{
2220+ kmem_cache_destroy(squashfs_inode_cachep);
2221+}
2222+
2223+
2224+module_init(init_squashfs_fs);
2225+module_exit(exit_squashfs_fs);
2226+MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem");
2227+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
2228Index: linux-2.6.22/fs/squashfs/Makefile
2229===================================================================
2230--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2231+++ linux-2.6.22/fs/squashfs/Makefile 2007-08-28 21:56:34.000000000 +0100
2232@@ -0,0 +1,7 @@
2233+#
2234+# Makefile for the linux squashfs routines.
2235+#
2236+
2237+obj-$(CONFIG_SQUASHFS) += squashfs.o
2238+squashfs-y += inode.o
2239+squashfs-y += squashfs2_0.o
2240Index: linux-2.6.22/fs/squashfs/squashfs2_0.c
2241===================================================================
2242--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2243+++ linux-2.6.22/fs/squashfs/squashfs2_0.c 2007-08-28 21:56:34.000000000 +0100
2244@@ -0,0 +1,757 @@
2245+/*
2246+ * Squashfs - a compressed read only filesystem for Linux
2247+ *
2248+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
2249+ * Phillip Lougher <phillip@lougher.org.uk>
2250+ *
2251+ * This program is free software; you can redistribute it and/or
2252+ * modify it under the terms of the GNU General Public License
2253+ * as published by the Free Software Foundation; either version 2,
2254+ * or (at your option) any later version.
2255+ *
2256+ * This program is distributed in the hope that it will be useful,
2257+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2258+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2259+ * GNU General Public License for more details.
2260+ *
2261+ * You should have received a copy of the GNU General Public License
2262+ * along with this program; if not, write to the Free Software
2263+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2264+ *
2265+ * squashfs2_0.c
2266+ */
2267+
2268+#include <linux/types.h>
2269+#include <linux/squashfs_fs.h>
2270+#include <linux/module.h>
2271+#include <linux/errno.h>
2272+#include <linux/slab.h>
2273+#include <linux/fs.h>
2274+#include <linux/smp_lock.h>
2275+#include <linux/slab.h>
2276+#include <linux/squashfs_fs_sb.h>
2277+#include <linux/squashfs_fs_i.h>
2278+#include <linux/buffer_head.h>
2279+#include <linux/vfs.h>
2280+#include <linux/init.h>
2281+#include <linux/dcache.h>
2282+#include <linux/wait.h>
2283+#include <linux/zlib.h>
2284+#include <linux/blkdev.h>
2285+#include <linux/vmalloc.h>
2286+#include <asm/uaccess.h>
2287+#include <asm/semaphore.h>
2288+
2289+#include "squashfs.h"
2290+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
2291+static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
2292+ struct nameidata *);
2293+
2294+static struct file_operations squashfs_dir_ops_2 = {
2295+ .read = generic_read_dir,
2296+ .readdir = squashfs_readdir_2
2297+};
2298+
2299+static struct inode_operations squashfs_dir_inode_ops_2 = {
2300+ .lookup = squashfs_lookup_2
2301+};
2302+
2303+static unsigned char squashfs_filetype_table[] = {
2304+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
2305+};
2306+
2307+static int read_fragment_index_table_2(struct super_block *s)
2308+{
2309+ struct squashfs_sb_info *msblk = s->s_fs_info;
2310+ struct squashfs_super_block *sblk = &msblk->sblk;
2311+
2312+ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
2313+ (sblk->fragments), GFP_KERNEL))) {
2314+ ERROR("Failed to allocate uid/gid table\n");
2315+ return 0;
2316+ }
2317+
2318+ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
2319+ !squashfs_read_data(s, (char *)
2320+ msblk->fragment_index_2,
2321+ sblk->fragment_table_start,
2322+ SQUASHFS_FRAGMENT_INDEX_BYTES_2
2323+ (sblk->fragments) |
2324+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
2325+ ERROR("unable to read fragment index table\n");
2326+ return 0;
2327+ }
2328+
2329+ if (msblk->swap) {
2330+ int i;
2331+ unsigned int fragment;
2332+
2333+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
2334+ i++) {
2335+ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
2336+ &msblk->fragment_index_2[i], 1);
2337+ msblk->fragment_index_2[i] = fragment;
2338+ }
2339+ }
2340+
2341+ return 1;
2342+}
2343+
2344+
2345+static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
2346+ long long *fragment_start_block,
2347+ unsigned int *fragment_size)
2348+{
2349+ struct squashfs_sb_info *msblk = s->s_fs_info;
2350+ long long start_block =
2351+ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
2352+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
2353+ struct squashfs_fragment_entry_2 fragment_entry;
2354+
2355+ if (msblk->swap) {
2356+ struct squashfs_fragment_entry_2 sfragment_entry;
2357+
2358+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
2359+ start_block, offset,
2360+ sizeof(sfragment_entry), &start_block,
2361+ &offset))
2362+ goto out;
2363+ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
2364+ } else
2365+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
2366+ start_block, offset,
2367+ sizeof(fragment_entry), &start_block,
2368+ &offset))
2369+ goto out;
2370+
2371+ *fragment_start_block = fragment_entry.start_block;
2372+ *fragment_size = fragment_entry.size;
2373+
2374+ return 1;
2375+
2376+out:
2377+ return 0;
2378+}
2379+
2380+
2381+static struct inode *squashfs_new_inode(struct super_block *s,
2382+ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
2383+{
2384+ struct squashfs_sb_info *msblk = s->s_fs_info;
2385+ struct squashfs_super_block *sblk = &msblk->sblk;
2386+ struct inode *i = new_inode(s);
2387+
2388+ if (i) {
2389+ i->i_ino = ino;
2390+ i->i_mtime.tv_sec = sblk->mkfs_time;
2391+ i->i_atime.tv_sec = sblk->mkfs_time;
2392+ i->i_ctime.tv_sec = sblk->mkfs_time;
2393+ i->i_uid = msblk->uid[inodeb->uid];
2394+ i->i_mode = inodeb->mode;
2395+ i->i_nlink = 1;
2396+ i->i_size = 0;
2397+ if (inodeb->guid == SQUASHFS_GUIDS)
2398+ i->i_gid = i->i_uid;
2399+ else
2400+ i->i_gid = msblk->guid[inodeb->guid];
2401+ }
2402+
2403+ return i;
2404+}
2405+
2406+
2407+static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
2408+{
2409+ struct inode *i;
2410+ struct squashfs_sb_info *msblk = s->s_fs_info;
2411+ struct squashfs_super_block *sblk = &msblk->sblk;
2412+ unsigned int block = SQUASHFS_INODE_BLK(inode) +
2413+ sblk->inode_table_start;
2414+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
2415+ unsigned int ino = SQUASHFS_MK_VFS_INODE(block
2416+ - sblk->inode_table_start, offset);
2417+ long long next_block;
2418+ unsigned int next_offset;
2419+ union squashfs_inode_header_2 id, sid;
2420+ struct squashfs_base_inode_header_2 *inodeb = &id.base,
2421+ *sinodeb = &sid.base;
2422+
2423+ TRACE("Entered squashfs_iget\n");
2424+
2425+ if (msblk->swap) {
2426+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
2427+ offset, sizeof(*sinodeb), &next_block,
2428+ &next_offset))
2429+ goto failed_read;
2430+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
2431+ sizeof(*sinodeb));
2432+ } else
2433+ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
2434+ offset, sizeof(*inodeb), &next_block,
2435+ &next_offset))
2436+ goto failed_read;
2437+
2438+ switch(inodeb->inode_type) {
2439+ case SQUASHFS_FILE_TYPE: {
2440+ struct squashfs_reg_inode_header_2 *inodep = &id.reg;
2441+ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
2442+ long long frag_blk;
2443+ unsigned int frag_size;
2444+
2445+ if (msblk->swap) {
2446+ if (!squashfs_get_cached_block(s, (char *)
2447+ sinodep, block, offset,
2448+ sizeof(*sinodep), &next_block,
2449+ &next_offset))
2450+ goto failed_read;
2451+ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
2452+ } else
2453+ if (!squashfs_get_cached_block(s, (char *)
2454+ inodep, block, offset,
2455+ sizeof(*inodep), &next_block,
2456+ &next_offset))
2457+ goto failed_read;
2458+
2459+ frag_blk = SQUASHFS_INVALID_BLK;
2460+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
2461+ !get_fragment_location_2(s,
2462+ inodep->fragment, &frag_blk, &frag_size))
2463+ goto failed_read;
2464+
2465+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
2466+ goto failed_read1;
2467+
2468+ i->i_size = inodep->file_size;
2469+ i->i_fop = &generic_ro_fops;
2470+ i->i_mode |= S_IFREG;
2471+ i->i_mtime.tv_sec = inodep->mtime;
2472+ i->i_atime.tv_sec = inodep->mtime;
2473+ i->i_ctime.tv_sec = inodep->mtime;
2474+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
2475+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
2476+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
2477+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
2478+ SQUASHFS_I(i)->start_block = inodep->start_block;
2479+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
2480+ SQUASHFS_I(i)->offset = next_offset;
2481+ if (sblk->block_size > 4096)
2482+ i->i_data.a_ops = &squashfs_aops;
2483+ else
2484+ i->i_data.a_ops = &squashfs_aops_4K;
2485+
2486+ TRACE("File inode %x:%x, start_block %x, "
2487+ "block_list_start %llx, offset %x\n",
2488+ SQUASHFS_INODE_BLK(inode), offset,
2489+ inodep->start_block, next_block,
2490+ next_offset);
2491+ break;
2492+ }
2493+ case SQUASHFS_DIR_TYPE: {
2494+ struct squashfs_dir_inode_header_2 *inodep = &id.dir;
2495+ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
2496+
2497+ if (msblk->swap) {
2498+ if (!squashfs_get_cached_block(s, (char *)
2499+ sinodep, block, offset,
2500+ sizeof(*sinodep), &next_block,
2501+ &next_offset))
2502+ goto failed_read;
2503+ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
2504+ } else
2505+ if (!squashfs_get_cached_block(s, (char *)
2506+ inodep, block, offset,
2507+ sizeof(*inodep), &next_block,
2508+ &next_offset))
2509+ goto failed_read;
2510+
2511+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
2512+ goto failed_read1;
2513+
2514+ i->i_size = inodep->file_size;
2515+ i->i_op = &squashfs_dir_inode_ops_2;
2516+ i->i_fop = &squashfs_dir_ops_2;
2517+ i->i_mode |= S_IFDIR;
2518+ i->i_mtime.tv_sec = inodep->mtime;
2519+ i->i_atime.tv_sec = inodep->mtime;
2520+ i->i_ctime.tv_sec = inodep->mtime;
2521+ SQUASHFS_I(i)->start_block = inodep->start_block;
2522+ SQUASHFS_I(i)->offset = inodep->offset;
2523+ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
2524+ SQUASHFS_I(i)->u.s2.parent_inode = 0;
2525+
2526+ TRACE("Directory inode %x:%x, start_block %x, offset "
2527+ "%x\n", SQUASHFS_INODE_BLK(inode),
2528+ offset, inodep->start_block,
2529+ inodep->offset);
2530+ break;
2531+ }
2532+ case SQUASHFS_LDIR_TYPE: {
2533+ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
2534+ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
2535+
2536+ if (msblk->swap) {
2537+ if (!squashfs_get_cached_block(s, (char *)
2538+ sinodep, block, offset,
2539+ sizeof(*sinodep), &next_block,
2540+ &next_offset))
2541+ goto failed_read;
2542+ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
2543+ sinodep);
2544+ } else
2545+ if (!squashfs_get_cached_block(s, (char *)
2546+ inodep, block, offset,
2547+ sizeof(*inodep), &next_block,
2548+ &next_offset))
2549+ goto failed_read;
2550+
2551+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
2552+ goto failed_read1;
2553+
2554+ i->i_size = inodep->file_size;
2555+ i->i_op = &squashfs_dir_inode_ops_2;
2556+ i->i_fop = &squashfs_dir_ops_2;
2557+ i->i_mode |= S_IFDIR;
2558+ i->i_mtime.tv_sec = inodep->mtime;
2559+ i->i_atime.tv_sec = inodep->mtime;
2560+ i->i_ctime.tv_sec = inodep->mtime;
2561+ SQUASHFS_I(i)->start_block = inodep->start_block;
2562+ SQUASHFS_I(i)->offset = inodep->offset;
2563+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
2564+ SQUASHFS_I(i)->u.s2.directory_index_offset =
2565+ next_offset;
2566+ SQUASHFS_I(i)->u.s2.directory_index_count =
2567+ inodep->i_count;
2568+ SQUASHFS_I(i)->u.s2.parent_inode = 0;
2569+
2570+ TRACE("Long directory inode %x:%x, start_block %x, "
2571+ "offset %x\n",
2572+ SQUASHFS_INODE_BLK(inode), offset,
2573+ inodep->start_block, inodep->offset);
2574+ break;
2575+ }
2576+ case SQUASHFS_SYMLINK_TYPE: {
2577+ struct squashfs_symlink_inode_header_2 *inodep =
2578+ &id.symlink;
2579+ struct squashfs_symlink_inode_header_2 *sinodep =
2580+ &sid.symlink;
2581+
2582+ if (msblk->swap) {
2583+ if (!squashfs_get_cached_block(s, (char *)
2584+ sinodep, block, offset,
2585+ sizeof(*sinodep), &next_block,
2586+ &next_offset))
2587+ goto failed_read;
2588+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
2589+ sinodep);
2590+ } else
2591+ if (!squashfs_get_cached_block(s, (char *)
2592+ inodep, block, offset,
2593+ sizeof(*inodep), &next_block,
2594+ &next_offset))
2595+ goto failed_read;
2596+
2597+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
2598+ goto failed_read1;
2599+
2600+ i->i_size = inodep->symlink_size;
2601+ i->i_op = &page_symlink_inode_operations;
2602+ i->i_data.a_ops = &squashfs_symlink_aops;
2603+ i->i_mode |= S_IFLNK;
2604+ SQUASHFS_I(i)->start_block = next_block;
2605+ SQUASHFS_I(i)->offset = next_offset;
2606+
2607+ TRACE("Symbolic link inode %x:%x, start_block %llx, "
2608+ "offset %x\n",
2609+ SQUASHFS_INODE_BLK(inode), offset,
2610+ next_block, next_offset);
2611+ break;
2612+ }
2613+ case SQUASHFS_BLKDEV_TYPE:
2614+ case SQUASHFS_CHRDEV_TYPE: {
2615+ struct squashfs_dev_inode_header_2 *inodep = &id.dev;
2616+ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
2617+
2618+ if (msblk->swap) {
2619+ if (!squashfs_get_cached_block(s, (char *)
2620+ sinodep, block, offset,
2621+ sizeof(*sinodep), &next_block,
2622+ &next_offset))
2623+ goto failed_read;
2624+ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
2625+ } else
2626+ if (!squashfs_get_cached_block(s, (char *)
2627+ inodep, block, offset,
2628+ sizeof(*inodep), &next_block,
2629+ &next_offset))
2630+ goto failed_read;
2631+
2632+ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
2633+ goto failed_read1;
2634+
2635+ i->i_mode |= (inodeb->inode_type ==
2636+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
2637+ S_IFBLK;
2638+ init_special_inode(i, i->i_mode,
2639+ old_decode_dev(inodep->rdev));
2640+
2641+ TRACE("Device inode %x:%x, rdev %x\n",
2642+ SQUASHFS_INODE_BLK(inode), offset,
2643+ inodep->rdev);
2644+ break;
2645+ }
2646+ case SQUASHFS_FIFO_TYPE:
2647+ case SQUASHFS_SOCKET_TYPE: {
2648+ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
2649+ goto failed_read1;
2650+
2651+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
2652+ ? S_IFIFO : S_IFSOCK;
2653+ init_special_inode(i, i->i_mode, 0);
2654+ break;
2655+ }
2656+ default:
2657+ ERROR("Unknown inode type %d in squashfs_iget!\n",
2658+ inodeb->inode_type);
2659+ goto failed_read1;
2660+ }
2661+
2662+ insert_inode_hash(i);
2663+ return i;
2664+
2665+failed_read:
2666+ ERROR("Unable to read inode [%x:%x]\n", block, offset);
2667+
2668+failed_read1:
2669+ return NULL;
2670+}
2671+
2672+
2673+static int get_dir_index_using_offset(struct super_block *s, long long
2674+ *next_block, unsigned int *next_offset,
2675+ long long index_start,
2676+ unsigned int index_offset, int i_count,
2677+ long long f_pos)
2678+{
2679+ struct squashfs_sb_info *msblk = s->s_fs_info;
2680+ struct squashfs_super_block *sblk = &msblk->sblk;
2681+ int i, length = 0;
2682+ struct squashfs_dir_index_2 index;
2683+
2684+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
2685+ i_count, (unsigned int) f_pos);
2686+
2687+ if (f_pos == 0)
2688+ goto finish;
2689+
2690+ for (i = 0; i < i_count; i++) {
2691+ if (msblk->swap) {
2692+ struct squashfs_dir_index_2 sindex;
2693+ squashfs_get_cached_block(s, (char *) &sindex,
2694+ index_start, index_offset,
2695+ sizeof(sindex), &index_start,
2696+ &index_offset);
2697+ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
2698+ } else
2699+ squashfs_get_cached_block(s, (char *) &index,
2700+ index_start, index_offset,
2701+ sizeof(index), &index_start,
2702+ &index_offset);
2703+
2704+ if (index.index > f_pos)
2705+ break;
2706+
2707+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
2708+ index.size + 1, &index_start,
2709+ &index_offset);
2710+
2711+ length = index.index;
2712+ *next_block = index.start_block + sblk->directory_table_start;
2713+ }
2714+
2715+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2716+
2717+finish:
2718+ return length;
2719+}
2720+
2721+
2722+static int get_dir_index_using_name(struct super_block *s, long long
2723+ *next_block, unsigned int *next_offset,
2724+ long long index_start,
2725+ unsigned int index_offset, int i_count,
2726+ const char *name, int size)
2727+{
2728+ struct squashfs_sb_info *msblk = s->s_fs_info;
2729+ struct squashfs_super_block *sblk = &msblk->sblk;
2730+ int i, length = 0;
2731+ char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
2732+ struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
2733+ char str[SQUASHFS_NAME_LEN + 1];
2734+
2735+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
2736+
2737+ strncpy(str, name, size);
2738+ str[size] = '\0';
2739+
2740+ for (i = 0; i < i_count; i++) {
2741+ if (msblk->swap) {
2742+ struct squashfs_dir_index_2 sindex;
2743+ squashfs_get_cached_block(s, (char *) &sindex,
2744+ index_start, index_offset,
2745+ sizeof(sindex), &index_start,
2746+ &index_offset);
2747+ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
2748+ } else
2749+ squashfs_get_cached_block(s, (char *) index,
2750+ index_start, index_offset,
2751+ sizeof(struct squashfs_dir_index_2),
2752+ &index_start, &index_offset);
2753+
2754+ squashfs_get_cached_block(s, index->name, index_start,
2755+ index_offset, index->size + 1,
2756+ &index_start, &index_offset);
2757+
2758+ index->name[index->size + 1] = '\0';
2759+
2760+ if (strcmp(index->name, str) > 0)
2761+ break;
2762+
2763+ length = index->index;
2764+ *next_block = index->start_block + sblk->directory_table_start;
2765+ }
2766+
2767+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2768+ return length;
2769+}
2770+
2771+
2772+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
2773+{
2774+ struct inode *i = file->f_dentry->d_inode;
2775+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2776+ struct squashfs_super_block *sblk = &msblk->sblk;
2777+ long long next_block = SQUASHFS_I(i)->start_block +
2778+ sblk->directory_table_start;
2779+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
2780+ dir_count;
2781+ struct squashfs_dir_header_2 dirh;
2782+ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
2783+ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
2784+
2785+ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
2786+
2787+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
2788+ SQUASHFS_I(i)->u.s2.directory_index_start,
2789+ SQUASHFS_I(i)->u.s2.directory_index_offset,
2790+ SQUASHFS_I(i)->u.s2.directory_index_count,
2791+ file->f_pos);
2792+
2793+ while (length < i_size_read(i)) {
2794+ /* read directory header */
2795+ if (msblk->swap) {
2796+ struct squashfs_dir_header_2 sdirh;
2797+
2798+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2799+ next_block, next_offset, sizeof(sdirh),
2800+ &next_block, &next_offset))
2801+ goto failed_read;
2802+
2803+ length += sizeof(sdirh);
2804+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
2805+ } else {
2806+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2807+ next_block, next_offset, sizeof(dirh),
2808+ &next_block, &next_offset))
2809+ goto failed_read;
2810+
2811+ length += sizeof(dirh);
2812+ }
2813+
2814+ dir_count = dirh.count + 1;
2815+ while (dir_count--) {
2816+ if (msblk->swap) {
2817+ struct squashfs_dir_entry_2 sdire;
2818+ if (!squashfs_get_cached_block(i->i_sb, (char *)
2819+ &sdire, next_block, next_offset,
2820+ sizeof(sdire), &next_block,
2821+ &next_offset))
2822+ goto failed_read;
2823+
2824+ length += sizeof(sdire);
2825+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
2826+ } else {
2827+ if (!squashfs_get_cached_block(i->i_sb, (char *)
2828+ dire, next_block, next_offset,
2829+ sizeof(*dire), &next_block,
2830+ &next_offset))
2831+ goto failed_read;
2832+
2833+ length += sizeof(*dire);
2834+ }
2835+
2836+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
2837+ next_block, next_offset,
2838+ dire->size + 1, &next_block,
2839+ &next_offset))
2840+ goto failed_read;
2841+
2842+ length += dire->size + 1;
2843+
2844+ if (file->f_pos >= length)
2845+ continue;
2846+
2847+ dire->name[dire->size + 1] = '\0';
2848+
2849+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
2850+ (unsigned int) dirent, dire->name,
2851+ dire->size + 1, (int) file->f_pos,
2852+ dirh.start_block, dire->offset,
2853+ squashfs_filetype_table[dire->type]);
2854+
2855+ if (filldir(dirent, dire->name, dire->size + 1,
2856+ file->f_pos, SQUASHFS_MK_VFS_INODE(
2857+ dirh.start_block, dire->offset),
2858+ squashfs_filetype_table[dire->type])
2859+ < 0) {
2860+ TRACE("Filldir returned less than 0\n");
2861+ goto finish;
2862+ }
2863+ file->f_pos = length;
2864+ dirs_read++;
2865+ }
2866+ }
2867+
2868+finish:
2869+ return dirs_read;
2870+
2871+failed_read:
2872+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2873+ next_offset);
2874+ return 0;
2875+}
2876+
2877+
2878+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
2879+ struct nameidata *nd)
2880+{
2881+ const unsigned char *name = dentry->d_name.name;
2882+ int len = dentry->d_name.len;
2883+ struct inode *inode = NULL;
2884+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2885+ struct squashfs_super_block *sblk = &msblk->sblk;
2886+ long long next_block = SQUASHFS_I(i)->start_block +
2887+ sblk->directory_table_start;
2888+ int next_offset = SQUASHFS_I(i)->offset, length = 0,
2889+ dir_count;
2890+ struct squashfs_dir_header_2 dirh;
2891+ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
2892+ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
2893+ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
2894+
2895+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
2896+
2897+ if (len > SQUASHFS_NAME_LEN)
2898+ goto exit_loop;
2899+
2900+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
2901+ SQUASHFS_I(i)->u.s2.directory_index_start,
2902+ SQUASHFS_I(i)->u.s2.directory_index_offset,
2903+ SQUASHFS_I(i)->u.s2.directory_index_count, name,
2904+ len);
2905+
2906+ while (length < i_size_read(i)) {
2907+ /* read directory header */
2908+ if (msblk->swap) {
2909+ struct squashfs_dir_header_2 sdirh;
2910+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2911+ next_block, next_offset, sizeof(sdirh),
2912+ &next_block, &next_offset))
2913+ goto failed_read;
2914+
2915+ length += sizeof(sdirh);
2916+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
2917+ } else {
2918+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2919+ next_block, next_offset, sizeof(dirh),
2920+ &next_block, &next_offset))
2921+ goto failed_read;
2922+
2923+ length += sizeof(dirh);
2924+ }
2925+
2926+ dir_count = dirh.count + 1;
2927+ while (dir_count--) {
2928+ if (msblk->swap) {
2929+ struct squashfs_dir_entry_2 sdire;
2930+ if (!squashfs_get_cached_block(i->i_sb, (char *)
2931+ &sdire, next_block,next_offset,
2932+ sizeof(sdire), &next_block,
2933+ &next_offset))
2934+ goto failed_read;
2935+
2936+ length += sizeof(sdire);
2937+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
2938+ } else {
2939+ if (!squashfs_get_cached_block(i->i_sb, (char *)
2940+ dire, next_block,next_offset,
2941+ sizeof(*dire), &next_block,
2942+ &next_offset))
2943+ goto failed_read;
2944+
2945+ length += sizeof(*dire);
2946+ }
2947+
2948+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
2949+ next_block, next_offset, dire->size + 1,
2950+ &next_block, &next_offset))
2951+ goto failed_read;
2952+
2953+ length += dire->size + 1;
2954+
2955+ if (sorted && name[0] < dire->name[0])
2956+ goto exit_loop;
2957+
2958+ if ((len == dire->size + 1) && !strncmp(name,
2959+ dire->name, len)) {
2960+ squashfs_inode_t ino =
2961+ SQUASHFS_MKINODE(dirh.start_block,
2962+ dire->offset);
2963+
2964+ TRACE("calling squashfs_iget for directory "
2965+ "entry %s, inode %x:%x, %lld\n", name,
2966+ dirh.start_block, dire->offset, ino);
2967+
2968+ inode = (msblk->iget)(i->i_sb, ino);
2969+
2970+ goto exit_loop;
2971+ }
2972+ }
2973+ }
2974+
2975+exit_loop:
2976+ d_add(dentry, inode);
2977+ return ERR_PTR(0);
2978+
2979+failed_read:
2980+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2981+ next_offset);
2982+ goto exit_loop;
2983+}
2984+
2985+
2986+int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
2987+{
2988+ struct squashfs_super_block *sblk = &msblk->sblk;
2989+
2990+ msblk->iget = squashfs_iget_2;
2991+ msblk->read_fragment_index_table = read_fragment_index_table_2;
2992+
2993+ sblk->bytes_used = sblk->bytes_used_2;
2994+ sblk->uid_start = sblk->uid_start_2;
2995+ sblk->guid_start = sblk->guid_start_2;
2996+ sblk->inode_table_start = sblk->inode_table_start_2;
2997+ sblk->directory_table_start = sblk->directory_table_start_2;
2998+ sblk->fragment_table_start = sblk->fragment_table_start_2;
2999+
3000+ return 1;
3001+}
3002Index: linux-2.6.22/fs/squashfs/squashfs.h
3003===================================================================
3004--- /dev/null 1970-01-01 00:00:00.000000000 +0000
3005+++ linux-2.6.22/fs/squashfs/squashfs.h 2007-08-28 21:56:34.000000000 +0100
3006@@ -0,0 +1,86 @@
3007+/*
3008+ * Squashfs - a compressed read only filesystem for Linux
3009+ *
3010+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
3011+ * Phillip Lougher <phillip@lougher.org.uk>
3012+ *
3013+ * This program is free software; you can redistribute it and/or
3014+ * modify it under the terms of the GNU General Public License
3015+ * as published by the Free Software Foundation; either version 2,
3016+ * or (at your option) any later version.
3017+ *
3018+ * This program is distributed in the hope that it will be useful,
3019+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3020+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3021+ * GNU General Public License for more details.
3022+ *
3023+ * You should have received a copy of the GNU General Public License
3024+ * along with this program; if not, write to the Free Software
3025+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3026+ *
3027+ * squashfs.h
3028+ */
3029+
3030+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3031+#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3032+#endif
3033+
3034+#ifdef SQUASHFS_TRACE
3035+#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
3036+#else
3037+#define TRACE(s, args...) {}
3038+#endif
3039+
3040+#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
3041+
3042+#define SERROR(s, args...) do { \
3043+ if (!silent) \
3044+ printk(KERN_ERR "SQUASHFS error: "s, ## args);\
3045+ } while(0)
3046+
3047+#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
3048+
3049+static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
3050+{
3051+ return list_entry(inode, struct squashfs_inode_info, vfs_inode);
3052+}
3053+
3054+#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
3055+#define SQSH_EXTERN
3056+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
3057+ long long index, unsigned int length,
3058+ long long *next_index);
3059+extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
3060+ long long block, unsigned int offset,
3061+ int length, long long *next_block,
3062+ unsigned int *next_offset);
3063+extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
3064+ squashfs_fragment_cache *fragment);
3065+extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
3066+ *s, long long start_block,
3067+ int length);
3068+extern struct address_space_operations squashfs_symlink_aops;
3069+extern struct address_space_operations squashfs_aops;
3070+extern struct address_space_operations squashfs_aops_4K;
3071+extern struct inode_operations squashfs_dir_inode_ops;
3072+#else
3073+#define SQSH_EXTERN static
3074+#endif
3075+
3076+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3077+extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
3078+#else
3079+static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
3080+{
3081+ return 0;
3082+}
3083+#endif
3084+
3085+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3086+extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
3087+#else
3088+static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
3089+{
3090+ return 0;
3091+}
3092+#endif
3093Index: linux-2.6.22/include/linux/squashfs_fs.h
3094===================================================================
3095--- /dev/null 1970-01-01 00:00:00.000000000 +0000
3096+++ linux-2.6.22/include/linux/squashfs_fs.h 2007-08-28 21:56:34.000000000 +0100
3097@@ -0,0 +1,911 @@
3098+#ifndef SQUASHFS_FS
3099+#define SQUASHFS_FS
3100+
3101+/*
3102+ * Squashfs
3103+ *
3104+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
3105+ * Phillip Lougher <phillip@lougher.org.uk>
3106+ *
3107+ * This program is free software; you can redistribute it and/or
3108+ * modify it under the terms of the GNU General Public License
3109+ * as published by the Free Software Foundation; either version 2,
3110+ * or (at your option) any later version.
3111+ *
3112+ * This program is distributed in the hope that it will be useful,
3113+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3114+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3115+ * GNU General Public License for more details.
3116+ *
3117+ * You should have received a copy of the GNU General Public License
3118+ * along with this program; if not, write to the Free Software
3119+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3120+ *
3121+ * squashfs_fs.h
3122+ */
3123+
3124+#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3125+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
3126+#endif
3127+
3128+#ifdef CONFIG_SQUASHFS_VMALLOC
3129+#define SQUASHFS_ALLOC(a) vmalloc(a)
3130+#define SQUASHFS_FREE(a) vfree(a)
3131+#else
3132+#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL)
3133+#define SQUASHFS_FREE(a) kfree(a)
3134+#endif
3135+#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
3136+#define SQUASHFS_MAJOR 3
3137+#define SQUASHFS_MINOR 0
3138+#define SQUASHFS_MAGIC 0x73717368
3139+#define SQUASHFS_MAGIC_SWAP 0x68737173
3140+#define SQUASHFS_START 0
3141+
3142+/* size of metadata (inode and directory) blocks */
3143+#define SQUASHFS_METADATA_SIZE 8192
3144+#define SQUASHFS_METADATA_LOG 13
3145+
3146+/* default size of data blocks */
3147+#define SQUASHFS_FILE_SIZE 65536
3148+#define SQUASHFS_FILE_LOG 16
3149+
3150+#define SQUASHFS_FILE_MAX_SIZE 65536
3151+
3152+/* Max number of uids and gids */
3153+#define SQUASHFS_UIDS 256
3154+#define SQUASHFS_GUIDS 255
3155+
3156+/* Max length of filename (not 255) */
3157+#define SQUASHFS_NAME_LEN 256
3158+
3159+#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
3160+#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
3161+#define SQUASHFS_INVALID_BLK ((long long) -1)
3162+#define SQUASHFS_USED_BLK ((long long) -2)
3163+
3164+/* Filesystem flags */
3165+#define SQUASHFS_NOI 0
3166+#define SQUASHFS_NOD 1
3167+#define SQUASHFS_CHECK 2
3168+#define SQUASHFS_NOF 3
3169+#define SQUASHFS_NO_FRAG 4
3170+#define SQUASHFS_ALWAYS_FRAG 5
3171+#define SQUASHFS_DUPLICATE 6
3172+
3173+#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
3174+
3175+#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
3176+ SQUASHFS_NOI)
3177+
3178+#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
3179+ SQUASHFS_NOD)
3180+
3181+#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3182+ SQUASHFS_NOF)
3183+
3184+#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3185+ SQUASHFS_NO_FRAG)
3186+
3187+#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3188+ SQUASHFS_ALWAYS_FRAG)
3189+
3190+#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
3191+ SQUASHFS_DUPLICATE)
3192+
3193+#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
3194+ SQUASHFS_CHECK)
3195+
3196+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
3197+ duplicate_checking) (noi | (nod << 1) | (check_data << 2) \
3198+ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
3199+ (duplicate_checking << 6))
3200+
3201+/* Max number of types and file types */
3202+#define SQUASHFS_DIR_TYPE 1
3203+#define SQUASHFS_FILE_TYPE 2
3204+#define SQUASHFS_SYMLINK_TYPE 3
3205+#define SQUASHFS_BLKDEV_TYPE 4
3206+#define SQUASHFS_CHRDEV_TYPE 5
3207+#define SQUASHFS_FIFO_TYPE 6
3208+#define SQUASHFS_SOCKET_TYPE 7
3209+#define SQUASHFS_LDIR_TYPE 8
3210+#define SQUASHFS_LREG_TYPE 9
3211+
3212+/* 1.0 filesystem type definitions */
3213+#define SQUASHFS_TYPES 5
3214+#define SQUASHFS_IPC_TYPE 0
3215+
3216+/* Flag whether block is compressed or uncompressed, bit is set if block is
3217+ * uncompressed */
3218+#define SQUASHFS_COMPRESSED_BIT (1 << 15)
3219+
3220+#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
3221+ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
3222+
3223+#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
3224+
3225+#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
3226+
3227+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \
3228+ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
3229+ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
3230+
3231+#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
3232+
3233+/*
3234+ * Inode number ops. Inodes consist of a compressed block number, and an
3235+ * uncompressed offset within that block
3236+ */
3237+#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
3238+
3239+#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
3240+
3241+#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
3242+ << 16) + (B)))
3243+
3244+/* Compute 32 bit VFS inode number from squashfs inode number */
3245+#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
3246+ ((b) >> 2) + 1))
3247+/* XXX */
3248+
3249+/* Translate between VFS mode and squashfs mode */
3250+#define SQUASHFS_MODE(a) ((a) & 0xfff)
3251+
3252+/* fragment and fragment table defines */
3253+#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry))
3254+
3255+#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
3256+ SQUASHFS_METADATA_SIZE)
3257+
3258+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
3259+ SQUASHFS_METADATA_SIZE)
3260+
3261+#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
3262+ SQUASHFS_METADATA_SIZE - 1) / \
3263+ SQUASHFS_METADATA_SIZE)
3264+
3265+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
3266+ sizeof(long long))
3267+
3268+/* cached data constants for filesystem */
3269+#define SQUASHFS_CACHED_BLKS 8
3270+
3271+#define SQUASHFS_MAX_FILE_SIZE_LOG 64
3272+
3273+#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
3274+ (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
3275+
3276+#define SQUASHFS_MARKER_BYTE 0xff
3277+
3278+/* meta index cache */
3279+#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
3280+#define SQUASHFS_META_ENTRIES 31
3281+#define SQUASHFS_META_NUMBER 8
3282+#define SQUASHFS_SLOTS 4
3283+
3284+struct meta_entry {
3285+ long long data_block;
3286+ unsigned int index_block;
3287+ unsigned short offset;
3288+ unsigned short pad;
3289+};
3290+
3291+struct meta_index {
3292+ unsigned int inode_number;
3293+ unsigned int offset;
3294+ unsigned short entries;
3295+ unsigned short skip;
3296+ unsigned short locked;
3297+ unsigned short pad;
3298+ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
3299+};
3300+
3301+
3302+/*
3303+ * definitions for structures on disk
3304+ */
3305+
3306+typedef long long squashfs_block_t;
3307+typedef long long squashfs_inode_t;
3308+
3309+struct squashfs_super_block {
3310+ unsigned int s_magic;
3311+ unsigned int inodes;
3312+ unsigned int bytes_used_2;
3313+ unsigned int uid_start_2;
3314+ unsigned int guid_start_2;
3315+ unsigned int inode_table_start_2;
3316+ unsigned int directory_table_start_2;
3317+ unsigned int s_major:16;
3318+ unsigned int s_minor:16;
3319+ unsigned int block_size_1:16;
3320+ unsigned int block_log:16;
3321+ unsigned int flags:8;
3322+ unsigned int no_uids:8;
3323+ unsigned int no_guids:8;
3324+ unsigned int mkfs_time /* time of filesystem creation */;
3325+ squashfs_inode_t root_inode;
3326+ unsigned int block_size;
3327+ unsigned int fragments;
3328+ unsigned int fragment_table_start_2;
3329+ long long bytes_used;
3330+ long long uid_start;
3331+ long long guid_start;
3332+ long long inode_table_start;
3333+ long long directory_table_start;
3334+ long long fragment_table_start;
3335+ long long unused;
3336+} __attribute__ ((packed));
3337+
3338+struct squashfs_dir_index {
3339+ unsigned int index;
3340+ unsigned int start_block;
3341+ unsigned char size;
3342+ unsigned char name[0];
3343+} __attribute__ ((packed));
3344+
3345+#define SQUASHFS_BASE_INODE_HEADER \
3346+ unsigned int inode_type:4; \
3347+ unsigned int mode:12; \
3348+ unsigned int uid:8; \
3349+ unsigned int guid:8; \
3350+ unsigned int mtime; \
3351+ unsigned int inode_number;
3352+
3353+struct squashfs_base_inode_header {
3354+ SQUASHFS_BASE_INODE_HEADER;
3355+} __attribute__ ((packed));
3356+
3357+struct squashfs_ipc_inode_header {
3358+ SQUASHFS_BASE_INODE_HEADER;
3359+ unsigned int nlink;
3360+} __attribute__ ((packed));
3361+
3362+struct squashfs_dev_inode_header {
3363+ SQUASHFS_BASE_INODE_HEADER;
3364+ unsigned int nlink;
3365+ unsigned short rdev;
3366+} __attribute__ ((packed));
3367+
3368+struct squashfs_symlink_inode_header {
3369+ SQUASHFS_BASE_INODE_HEADER;
3370+ unsigned int nlink;
3371+ unsigned short symlink_size;
3372+ char symlink[0];
3373+} __attribute__ ((packed));
3374+
3375+struct squashfs_reg_inode_header {
3376+ SQUASHFS_BASE_INODE_HEADER;
3377+ squashfs_block_t start_block;
3378+ unsigned int fragment;
3379+ unsigned int offset;
3380+ unsigned int file_size;
3381+ unsigned short block_list[0];
3382+} __attribute__ ((packed));
3383+
3384+struct squashfs_lreg_inode_header {
3385+ SQUASHFS_BASE_INODE_HEADER;
3386+ unsigned int nlink;
3387+ squashfs_block_t start_block;
3388+ unsigned int fragment;
3389+ unsigned int offset;
3390+ long long file_size;
3391+ unsigned short block_list[0];
3392+} __attribute__ ((packed));
3393+
3394+struct squashfs_dir_inode_header {
3395+ SQUASHFS_BASE_INODE_HEADER;
3396+ unsigned int nlink;
3397+ unsigned int file_size:19;
3398+ unsigned int offset:13;
3399+ unsigned int start_block;
3400+ unsigned int parent_inode;
3401+} __attribute__ ((packed));
3402+
3403+struct squashfs_ldir_inode_header {
3404+ SQUASHFS_BASE_INODE_HEADER;
3405+ unsigned int nlink;
3406+ unsigned int file_size:27;
3407+ unsigned int offset:13;
3408+ unsigned int start_block;
3409+ unsigned int i_count:16;
3410+ unsigned int parent_inode;
3411+ struct squashfs_dir_index index[0];
3412+} __attribute__ ((packed));
3413+
3414+union squashfs_inode_header {
3415+ struct squashfs_base_inode_header base;
3416+ struct squashfs_dev_inode_header dev;
3417+ struct squashfs_symlink_inode_header symlink;
3418+ struct squashfs_reg_inode_header reg;
3419+ struct squashfs_lreg_inode_header lreg;
3420+ struct squashfs_dir_inode_header dir;
3421+ struct squashfs_ldir_inode_header ldir;
3422+ struct squashfs_ipc_inode_header ipc;
3423+};
3424+
3425+struct squashfs_dir_entry {
3426+ unsigned int offset:13;
3427+ unsigned int type:3;
3428+ unsigned int size:8;
3429+ int inode_number:16;
3430+ char name[0];
3431+} __attribute__ ((packed));
3432+
3433+struct squashfs_dir_header {
3434+ unsigned int count:8;
3435+ unsigned int start_block;
3436+ unsigned int inode_number;
3437+} __attribute__ ((packed));
3438+
3439+struct squashfs_fragment_entry {
3440+ long long start_block;
3441+ unsigned int size;
3442+ unsigned int unused;
3443+} __attribute__ ((packed));
3444+
3445+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
3446+extern int squashfs_uncompress_init(void);
3447+extern int squashfs_uncompress_exit(void);
3448+
3449+/*
3450+ * macros to convert each packed bitfield structure from little endian to big
3451+ * endian and vice versa. These are needed when creating or using a filesystem
3452+ * on a machine with different byte ordering to the target architecture.
3453+ *
3454+ */
3455+
3456+#define SQUASHFS_SWAP_START \
3457+ int bits;\
3458+ int b_pos;\
3459+ unsigned long long val;\
3460+ unsigned char *s;\
3461+ unsigned char *d;
3462+
3463+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
3464+ SQUASHFS_SWAP_START\
3465+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
3466+ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
3467+ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
3468+ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
3469+ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
3470+ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
3471+ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
3472+ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
3473+ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
3474+ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
3475+ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
3476+ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
3477+ SQUASHFS_SWAP((s)->flags, d, 288, 8);\
3478+ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
3479+ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
3480+ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
3481+ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
3482+ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
3483+ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
3484+ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
3485+ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
3486+ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
3487+ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
3488+ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
3489+ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
3490+ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
3491+ SQUASHFS_SWAP((s)->unused, d, 888, 64);\
3492+}
3493+
3494+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
3495+ SQUASHFS_MEMSET(s, d, n);\
3496+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3497+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3498+ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
3499+ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
3500+ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
3501+ SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
3502+
3503+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
3504+ SQUASHFS_SWAP_START\
3505+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
3506+}
3507+
3508+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
3509+ SQUASHFS_SWAP_START\
3510+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3511+ sizeof(struct squashfs_ipc_inode_header))\
3512+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3513+}
3514+
3515+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
3516+ SQUASHFS_SWAP_START\
3517+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3518+ sizeof(struct squashfs_dev_inode_header)); \
3519+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3520+ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
3521+}
3522+
3523+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
3524+ SQUASHFS_SWAP_START\
3525+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3526+ sizeof(struct squashfs_symlink_inode_header));\
3527+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3528+ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
3529+}
3530+
3531+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
3532+ SQUASHFS_SWAP_START\
3533+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3534+ sizeof(struct squashfs_reg_inode_header));\
3535+ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
3536+ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
3537+ SQUASHFS_SWAP((s)->offset, d, 192, 32);\
3538+ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
3539+}
3540+
3541+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
3542+ SQUASHFS_SWAP_START\
3543+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3544+ sizeof(struct squashfs_lreg_inode_header));\
3545+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3546+ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
3547+ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
3548+ SQUASHFS_SWAP((s)->offset, d, 224, 32);\
3549+ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
3550+}
3551+
3552+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
3553+ SQUASHFS_SWAP_START\
3554+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3555+ sizeof(struct squashfs_dir_inode_header));\
3556+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3557+ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
3558+ SQUASHFS_SWAP((s)->offset, d, 147, 13);\
3559+ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
3560+ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
3561+}
3562+
3563+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
3564+ SQUASHFS_SWAP_START\
3565+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3566+ sizeof(struct squashfs_ldir_inode_header));\
3567+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3568+ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
3569+ SQUASHFS_SWAP((s)->offset, d, 155, 13);\
3570+ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
3571+ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
3572+ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
3573+}
3574+
3575+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
3576+ SQUASHFS_SWAP_START\
3577+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
3578+ SQUASHFS_SWAP((s)->index, d, 0, 32);\
3579+ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
3580+ SQUASHFS_SWAP((s)->size, d, 64, 8);\
3581+}
3582+
3583+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
3584+ SQUASHFS_SWAP_START\
3585+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
3586+ SQUASHFS_SWAP((s)->count, d, 0, 8);\
3587+ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
3588+ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
3589+}
3590+
3591+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
3592+ SQUASHFS_SWAP_START\
3593+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
3594+ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
3595+ SQUASHFS_SWAP((s)->type, d, 13, 3);\
3596+ SQUASHFS_SWAP((s)->size, d, 16, 8);\
3597+ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
3598+}
3599+
3600+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
3601+ SQUASHFS_SWAP_START\
3602+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
3603+ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
3604+ SQUASHFS_SWAP((s)->size, d, 64, 32);\
3605+}
3606+
3607+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
3608+ int entry;\
3609+ int bit_position;\
3610+ SQUASHFS_SWAP_START\
3611+ SQUASHFS_MEMSET(s, d, n * 2);\
3612+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3613+ 16)\
3614+ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
3615+}
3616+
3617+#define SQUASHFS_SWAP_INTS(s, d, n) {\
3618+ int entry;\
3619+ int bit_position;\
3620+ SQUASHFS_SWAP_START\
3621+ SQUASHFS_MEMSET(s, d, n * 4);\
3622+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3623+ 32)\
3624+ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
3625+}
3626+
3627+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
3628+ int entry;\
3629+ int bit_position;\
3630+ SQUASHFS_SWAP_START\
3631+ SQUASHFS_MEMSET(s, d, n * 8);\
3632+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3633+ 64)\
3634+ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
3635+}
3636+
3637+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
3638+ int entry;\
3639+ int bit_position;\
3640+ SQUASHFS_SWAP_START\
3641+ SQUASHFS_MEMSET(s, d, n * bits / 8);\
3642+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3643+ bits)\
3644+ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
3645+}
3646+
3647+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
3648+
3649+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3650+
3651+struct squashfs_base_inode_header_1 {
3652+ unsigned int inode_type:4;
3653+ unsigned int mode:12; /* protection */
3654+ unsigned int uid:4; /* index into uid table */
3655+ unsigned int guid:4; /* index into guid table */
3656+} __attribute__ ((packed));
3657+
3658+struct squashfs_ipc_inode_header_1 {
3659+ unsigned int inode_type:4;
3660+ unsigned int mode:12; /* protection */
3661+ unsigned int uid:4; /* index into uid table */
3662+ unsigned int guid:4; /* index into guid table */
3663+ unsigned int type:4;
3664+ unsigned int offset:4;
3665+} __attribute__ ((packed));
3666+
3667+struct squashfs_dev_inode_header_1 {
3668+ unsigned int inode_type:4;
3669+ unsigned int mode:12; /* protection */
3670+ unsigned int uid:4; /* index into uid table */
3671+ unsigned int guid:4; /* index into guid table */
3672+ unsigned short rdev;
3673+} __attribute__ ((packed));
3674+
3675+struct squashfs_symlink_inode_header_1 {
3676+ unsigned int inode_type:4;
3677+ unsigned int mode:12; /* protection */
3678+ unsigned int uid:4; /* index into uid table */
3679+ unsigned int guid:4; /* index into guid table */
3680+ unsigned short symlink_size;
3681+ char symlink[0];
3682+} __attribute__ ((packed));
3683+
3684+struct squashfs_reg_inode_header_1 {
3685+ unsigned int inode_type:4;
3686+ unsigned int mode:12; /* protection */
3687+ unsigned int uid:4; /* index into uid table */
3688+ unsigned int guid:4; /* index into guid table */
3689+ unsigned int mtime;
3690+ unsigned int start_block;
3691+ unsigned int file_size:32;
3692+ unsigned short block_list[0];
3693+} __attribute__ ((packed));
3694+
3695+struct squashfs_dir_inode_header_1 {
3696+ unsigned int inode_type:4;
3697+ unsigned int mode:12; /* protection */
3698+ unsigned int uid:4; /* index into uid table */
3699+ unsigned int guid:4; /* index into guid table */
3700+ unsigned int file_size:19;
3701+ unsigned int offset:13;
3702+ unsigned int mtime;
3703+ unsigned int start_block:24;
3704+} __attribute__ ((packed));
3705+
3706+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
3707+ SQUASHFS_MEMSET(s, d, n);\
3708+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3709+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3710+ SQUASHFS_SWAP((s)->uid, d, 16, 4);\
3711+ SQUASHFS_SWAP((s)->guid, d, 20, 4);
3712+
3713+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
3714+ SQUASHFS_SWAP_START\
3715+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
3716+}
3717+
3718+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
3719+ SQUASHFS_SWAP_START\
3720+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3721+ sizeof(struct squashfs_ipc_inode_header_1));\
3722+ SQUASHFS_SWAP((s)->type, d, 24, 4);\
3723+ SQUASHFS_SWAP((s)->offset, d, 28, 4);\
3724+}
3725+
3726+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
3727+ SQUASHFS_SWAP_START\
3728+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3729+ sizeof(struct squashfs_dev_inode_header_1));\
3730+ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
3731+}
3732+
3733+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
3734+ SQUASHFS_SWAP_START\
3735+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3736+ sizeof(struct squashfs_symlink_inode_header_1));\
3737+ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
3738+}
3739+
3740+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
3741+ SQUASHFS_SWAP_START\
3742+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3743+ sizeof(struct squashfs_reg_inode_header_1));\
3744+ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
3745+ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
3746+ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
3747+}
3748+
3749+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
3750+ SQUASHFS_SWAP_START\
3751+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3752+ sizeof(struct squashfs_dir_inode_header_1));\
3753+ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
3754+ SQUASHFS_SWAP((s)->offset, d, 43, 13);\
3755+ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
3756+ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
3757+}
3758+
3759+#endif
3760+
3761+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3762+
3763+struct squashfs_dir_index_2 {
3764+ unsigned int index:27;
3765+ unsigned int start_block:29;
3766+ unsigned char size;
3767+ unsigned char name[0];
3768+} __attribute__ ((packed));
3769+
3770+struct squashfs_base_inode_header_2 {
3771+ unsigned int inode_type:4;
3772+ unsigned int mode:12; /* protection */
3773+ unsigned int uid:8; /* index into uid table */
3774+ unsigned int guid:8; /* index into guid table */
3775+} __attribute__ ((packed));
3776+
3777+struct squashfs_ipc_inode_header_2 {
3778+ unsigned int inode_type:4;
3779+ unsigned int mode:12; /* protection */
3780+ unsigned int uid:8; /* index into uid table */
3781+ unsigned int guid:8; /* index into guid table */
3782+} __attribute__ ((packed));
3783+
3784+struct squashfs_dev_inode_header_2 {
3785+ unsigned int inode_type:4;
3786+ unsigned int mode:12; /* protection */
3787+ unsigned int uid:8; /* index into uid table */
3788+ unsigned int guid:8; /* index into guid table */
3789+ unsigned short rdev;
3790+} __attribute__ ((packed));
3791+
3792+struct squashfs_symlink_inode_header_2 {
3793+ unsigned int inode_type:4;
3794+ unsigned int mode:12; /* protection */
3795+ unsigned int uid:8; /* index into uid table */
3796+ unsigned int guid:8; /* index into guid table */
3797+ unsigned short symlink_size;
3798+ char symlink[0];
3799+} __attribute__ ((packed));
3800+
3801+struct squashfs_reg_inode_header_2 {
3802+ unsigned int inode_type:4;
3803+ unsigned int mode:12; /* protection */
3804+ unsigned int uid:8; /* index into uid table */
3805+ unsigned int guid:8; /* index into guid table */
3806+ unsigned int mtime;
3807+ unsigned int start_block;
3808+ unsigned int fragment;
3809+ unsigned int offset;
3810+ unsigned int file_size:32;
3811+ unsigned short block_list[0];
3812+} __attribute__ ((packed));
3813+
3814+struct squashfs_dir_inode_header_2 {
3815+ unsigned int inode_type:4;
3816+ unsigned int mode:12; /* protection */
3817+ unsigned int uid:8; /* index into uid table */
3818+ unsigned int guid:8; /* index into guid table */
3819+ unsigned int file_size:19;
3820+ unsigned int offset:13;
3821+ unsigned int mtime;
3822+ unsigned int start_block:24;
3823+} __attribute__ ((packed));
3824+
3825+struct squashfs_ldir_inode_header_2 {
3826+ unsigned int inode_type:4;
3827+ unsigned int mode:12; /* protection */
3828+ unsigned int uid:8; /* index into uid table */
3829+ unsigned int guid:8; /* index into guid table */
3830+ unsigned int file_size:27;
3831+ unsigned int offset:13;
3832+ unsigned int mtime;
3833+ unsigned int start_block:24;
3834+ unsigned int i_count:16;
3835+ struct squashfs_dir_index_2 index[0];
3836+} __attribute__ ((packed));
3837+
3838+union squashfs_inode_header_2 {
3839+ struct squashfs_base_inode_header_2 base;
3840+ struct squashfs_dev_inode_header_2 dev;
3841+ struct squashfs_symlink_inode_header_2 symlink;
3842+ struct squashfs_reg_inode_header_2 reg;
3843+ struct squashfs_dir_inode_header_2 dir;
3844+ struct squashfs_ldir_inode_header_2 ldir;
3845+ struct squashfs_ipc_inode_header_2 ipc;
3846+};
3847+
3848+struct squashfs_dir_header_2 {
3849+ unsigned int count:8;
3850+ unsigned int start_block:24;
3851+} __attribute__ ((packed));
3852+
3853+struct squashfs_dir_entry_2 {
3854+ unsigned int offset:13;
3855+ unsigned int type:3;
3856+ unsigned int size:8;
3857+ char name[0];
3858+} __attribute__ ((packed));
3859+
3860+struct squashfs_fragment_entry_2 {
3861+ unsigned int start_block;
3862+ unsigned int size;
3863+} __attribute__ ((packed));
3864+
3865+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
3866+ SQUASHFS_MEMSET(s, d, n);\
3867+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3868+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3869+ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
3870+ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
3871+
3872+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
3873+ SQUASHFS_SWAP_START\
3874+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
3875+}
3876+
3877+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
3878+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
3879+
3880+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
3881+ SQUASHFS_SWAP_START\
3882+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3883+ sizeof(struct squashfs_dev_inode_header_2)); \
3884+ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
3885+}
3886+
3887+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
3888+ SQUASHFS_SWAP_START\
3889+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3890+ sizeof(struct squashfs_symlink_inode_header_2));\
3891+ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
3892+}
3893+
3894+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
3895+ SQUASHFS_SWAP_START\
3896+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3897+ sizeof(struct squashfs_reg_inode_header_2));\
3898+ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
3899+ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
3900+ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
3901+ SQUASHFS_SWAP((s)->offset, d, 128, 32);\
3902+ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
3903+}
3904+
3905+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
3906+ SQUASHFS_SWAP_START\
3907+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3908+ sizeof(struct squashfs_dir_inode_header_2));\
3909+ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
3910+ SQUASHFS_SWAP((s)->offset, d, 51, 13);\
3911+ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
3912+ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
3913+}
3914+
3915+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
3916+ SQUASHFS_SWAP_START\
3917+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3918+ sizeof(struct squashfs_ldir_inode_header_2));\
3919+ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
3920+ SQUASHFS_SWAP((s)->offset, d, 59, 13);\
3921+ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
3922+ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
3923+ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
3924+}
3925+
3926+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
3927+ SQUASHFS_SWAP_START\
3928+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
3929+ SQUASHFS_SWAP((s)->index, d, 0, 27);\
3930+ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
3931+ SQUASHFS_SWAP((s)->size, d, 56, 8);\
3932+}
3933+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
3934+ SQUASHFS_SWAP_START\
3935+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
3936+ SQUASHFS_SWAP((s)->count, d, 0, 8);\
3937+ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
3938+}
3939+
3940+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
3941+ SQUASHFS_SWAP_START\
3942+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
3943+ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
3944+ SQUASHFS_SWAP((s)->type, d, 13, 3);\
3945+ SQUASHFS_SWAP((s)->size, d, 16, 8);\
3946+}
3947+
3948+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
3949+ SQUASHFS_SWAP_START\
3950+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
3951+ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
3952+ SQUASHFS_SWAP((s)->size, d, 32, 32);\
3953+}
3954+
3955+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
3956+
3957+/* fragment and fragment table defines */
3958+#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
3959+
3960+#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
3961+ SQUASHFS_METADATA_SIZE)
3962+
3963+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
3964+ SQUASHFS_METADATA_SIZE)
3965+
3966+#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
3967+ SQUASHFS_METADATA_SIZE - 1) / \
3968+ SQUASHFS_METADATA_SIZE)
3969+
3970+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
3971+ sizeof(int))
3972+
3973+#endif
3974+
3975+#ifdef __KERNEL__
3976+
3977+/*
3978+ * macros used to swap each structure entry, taking into account
3979+ * bitfields and different bitfield placing conventions on differing
3980+ * architectures
3981+ */
3982+
3983+#include <asm/byteorder.h>
3984+
3985+#ifdef __BIG_ENDIAN
3986+ /* convert from little endian to big endian */
3987+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
3988+ tbits, b_pos)
3989+#else
3990+ /* convert from big endian to little endian */
3991+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
3992+ tbits, 64 - tbits - b_pos)
3993+#endif
3994+
3995+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
3996+ b_pos = pos % 8;\
3997+ val = 0;\
3998+ s = (unsigned char *)p + (pos / 8);\
3999+ d = ((unsigned char *) &val) + 7;\
4000+ for(bits = 0; bits < (tbits + b_pos); bits += 8) \
4001+ *d-- = *s++;\
4002+ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
4003+}
4004+
4005+#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
4006+
4007+#endif
4008+#endif
4009Index: linux-2.6.22/include/linux/squashfs_fs_i.h
4010===================================================================
4011--- /dev/null 1970-01-01 00:00:00.000000000 +0000
4012+++ linux-2.6.22/include/linux/squashfs_fs_i.h 2007-08-28 21:56:34.000000000 +0100
4013@@ -0,0 +1,45 @@
4014+#ifndef SQUASHFS_FS_I
4015+#define SQUASHFS_FS_I
4016+/*
4017+ * Squashfs
4018+ *
4019+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
4020+ * Phillip Lougher <phillip@lougher.org.uk>
4021+ *
4022+ * This program is free software; you can redistribute it and/or
4023+ * modify it under the terms of the GNU General Public License
4024+ * as published by the Free Software Foundation; either version 2,
4025+ * or (at your option) any later version.
4026+ *
4027+ * This program is distributed in the hope that it will be useful,
4028+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4029+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4030+ * GNU General Public License for more details.
4031+ *
4032+ * You should have received a copy of the GNU General Public License
4033+ * along with this program; if not, write to the Free Software
4034+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4035+ *
4036+ * squashfs_fs_i.h
4037+ */
4038+
4039+struct squashfs_inode_info {
4040+ long long start_block;
4041+ unsigned int offset;
4042+ union {
4043+ struct {
4044+ long long fragment_start_block;
4045+ unsigned int fragment_size;
4046+ unsigned int fragment_offset;
4047+ long long block_list_start;
4048+ } s1;
4049+ struct {
4050+ long long directory_index_start;
4051+ unsigned int directory_index_offset;
4052+ unsigned int directory_index_count;
4053+ unsigned int parent_inode;
4054+ } s2;
4055+ } u;
4056+ struct inode vfs_inode;
4057+};
4058+#endif
4059Index: linux-2.6.22/include/linux/squashfs_fs_sb.h
4060===================================================================
4061--- /dev/null 1970-01-01 00:00:00.000000000 +0000
4062+++ linux-2.6.22/include/linux/squashfs_fs_sb.h 2007-08-28 21:56:34.000000000 +0100
4063@@ -0,0 +1,74 @@
4064+#ifndef SQUASHFS_FS_SB
4065+#define SQUASHFS_FS_SB
4066+/*
4067+ * Squashfs
4068+ *
4069+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
4070+ * Phillip Lougher <phillip@lougher.org.uk>
4071+ *
4072+ * This program is free software; you can redistribute it and/or
4073+ * modify it under the terms of the GNU General Public License
4074+ * as published by the Free Software Foundation; either version 2,
4075+ * or (at your option) any later version.
4076+ *
4077+ * This program is distributed in the hope that it will be useful,
4078+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4079+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4080+ * GNU General Public License for more details.
4081+ *
4082+ * You should have received a copy of the GNU General Public License
4083+ * along with this program; if not, write to the Free Software
4084+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4085+ *
4086+ * squashfs_fs_sb.h
4087+ */
4088+
4089+#include <linux/squashfs_fs.h>
4090+
4091+struct squashfs_cache {
4092+ long long block;
4093+ int length;
4094+ long long next_index;
4095+ char *data;
4096+};
4097+
4098+struct squashfs_fragment_cache {
4099+ long long block;
4100+ int length;
4101+ unsigned int locked;
4102+ char *data;
4103+};
4104+
4105+struct squashfs_sb_info {
4106+ struct squashfs_super_block sblk;
4107+ int devblksize;
4108+ int devblksize_log2;
4109+ int swap;
4110+ struct squashfs_cache *block_cache;
4111+ struct squashfs_fragment_cache *fragment;
4112+ int next_cache;
4113+ int next_fragment;
4114+ int next_meta_index;
4115+ unsigned int *uid;
4116+ unsigned int *guid;
4117+ long long *fragment_index;
4118+ unsigned int *fragment_index_2;
4119+ unsigned int read_size;
4120+ char *read_data;
4121+ char *read_page;
4122+ struct semaphore read_data_mutex;
4123+ struct semaphore read_page_mutex;
4124+ struct semaphore block_cache_mutex;
4125+ struct semaphore fragment_mutex;
4126+ struct semaphore meta_index_mutex;
4127+ wait_queue_head_t waitq;
4128+ wait_queue_head_t fragment_wait_queue;
4129+ struct meta_index *meta_index;
4130+ struct inode *(*iget)(struct super_block *s, squashfs_inode_t \
4131+ inode);
4132+ long long (*read_blocklist)(struct inode *inode, int \
4133+ index, int readahead_blks, char *block_list, \
4134+ unsigned short **block_p, unsigned int *bsize);
4135+ int (*read_fragment_index_table)(struct super_block *s);
4136+};
4137+#endif
4138Index: linux-2.6.22/init/do_mounts_rd.c
4139===================================================================
4140--- linux-2.6.22.orig/init/do_mounts_rd.c 2007-08-28 21:54:14.000000000 +0100
4141+++ linux-2.6.22/init/do_mounts_rd.c 2007-08-28 21:56:34.000000000 +0100
4142@@ -5,6 +5,7 @@
4143 #include <linux/ext2_fs.h>
4144 #include <linux/romfs_fs.h>
4145 #include <linux/cramfs_fs.h>
4146+#include <linux/squashfs_fs.h>
4147 #include <linux/initrd.h>
4148 #include <linux/string.h>
4149
4150@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
4151 * numbers could not be found.
4152 *
4153 * We currently check for the following magic numbers:
4154+ * squashfs
4155 * minix
4156 * ext2
4157 * romfs
4158@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
4159 struct ext2_super_block *ext2sb;
4160 struct romfs_super_block *romfsb;
4161 struct cramfs_super *cramfsb;
4162+ struct squashfs_super_block *squashfsb;
4163 int nblocks = -1;
4164 unsigned char *buf;
4165
4166@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
4167 ext2sb = (struct ext2_super_block *) buf;
4168 romfsb = (struct romfs_super_block *) buf;
4169 cramfsb = (struct cramfs_super *) buf;
4170+ squashfsb = (struct squashfs_super_block *) buf;
4171 memset(buf, 0xe5, size);
4172
4173 /*
4174@@ -101,6 +105,15 @@ identify_ramdisk_image(int fd, int start
4175 goto done;
4176 }
4177
4178+ /* squashfs is at block zero too */
4179+ if (squashfsb->s_magic == SQUASHFS_MAGIC) {
4180+ printk(KERN_NOTICE
4181+ "RAMDISK: squashfs filesystem found at block %d\n",
4182+ start_block);
4183+ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
4184+ goto done;
4185+ }
4186+
4187 /*
4188 * Read block 1 to test for minix and ext2 superblock
4189 */
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 @@
1--- linux-2.6.24-rc1.orig/fs/Kconfig 1diff -x .gitignore -Nurp linux-2.6.24/fs/Kconfig linux-2.6.24-squashfs3.3/fs/Kconfig
2+++ linux-2.6.24-rc1/fs/Kconfig 2--- linux-2.6.24/fs/Kconfig 2007-10-25 17:41:45.000000000 +0100
3@@ -1405,6 +1405,71 @@ 3+++ linux-2.6.24-squashfs3.3/fs/Kconfig 2007-11-01 05:06:25.000000000 +0000
4@@ -1396,6 +1396,56 @@ config CRAMFS
4 5
5 If unsure, say N. 6 If unsure, say N.
6 7
7+config SQUASHFS 8+config SQUASHFS
8+ tristate "SquashFS 3.2 - Squashed file system support" 9+ tristate "SquashFS 3.3 - Squashed file system support"
9+ select ZLIB_INFLATE 10+ select ZLIB_INFLATE
10+ help 11+ help
11+ Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File 12+ Saying Y here includes support for SquashFS 3.3 (a Compressed
12+ System). Squashfs is a highly compressed read-only filesystem for Linux. 13+ Read-Only File System). Squashfs is a highly compressed read-only
13+ It uses zlib compression to compress both files, inodes and directories. 14+ filesystem for Linux. It uses zlib compression to compress both
14+ Inodes in the system are very small and all blocks are packed to minimise 15+ files, inodes and directories. Inodes in the system are very small
15+ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. 16+ and all blocks are packed to minimise data overhead. Block sizes
16+ SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full 17+ greater than 4K are supported up to a maximum of 1 Mbytes (default
17+ uid/gid information, hard links and timestamps. 18+ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files
18+ 19+ (larger than 4GB), full uid/gid information, hard links and timestamps.
19+ Squashfs is intended for general read-only filesystem use, for archival 20+
20+ use (i.e. in cases where a .tar.gz file may be used), and in embedded 21+ Squashfs is intended for general read-only filesystem use, for
21+ systems where low overhead is needed. Further information and filesystem tools 22+ archival use (i.e. in cases where a .tar.gz file may be used), and in
22+ are available from http://squashfs.sourceforge.net. 23+ embedded systems where low overhead is needed. Further information
24+ and filesystem tools are available from http://squashfs.sourceforge.net.
23+ 25+
24+ If you want to compile this as a module ( = code which can be 26+ If you want to compile this as a module ( = code which can be
25+ inserted in and removed from the running kernel whenever you want), 27+ inserted in and removed from the running kernel whenever you want),
@@ -31,13 +33,11 @@
31+ 33+
32+config SQUASHFS_EMBEDDED 34+config SQUASHFS_EMBEDDED
33+ 35+
34+ bool "Additional options for memory-constrained systems" 36+ bool "Additional option for memory-constrained systems"
35+ depends on SQUASHFS 37+ depends on SQUASHFS
36+ default n 38+ default n
37+ help 39+ help
38+ Saying Y here allows you to specify cache sizes and how Squashfs 40+ Saying Y here allows you to specify cache size.
39+ allocates memory. This is only intended for memory constrained
40+ systems.
41+ 41+
42+ If unsure, say N. 42+ If unsure, say N.
43+ 43+
@@ -55,26 +55,13 @@
55+ Note there must be at least one cached fragment. Anything 55+ Note there must be at least one cached fragment. Anything
56+ much more than three will probably not make much difference. 56+ much more than three will probably not make much difference.
57+ 57+
58+config SQUASHFS_VMALLOC
59+ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
60+ depends on SQUASHFS
61+ default n
62+ help
63+ By default SquashFS uses kmalloc to obtain fragment cache memory.
64+ Kmalloc memory is the standard kernel allocator, but it can fail
65+ on memory constrained systems. Because of the way Vmalloc works,
66+ Vmalloc can succeed when kmalloc fails. Specifying this option
67+ will make SquashFS always use Vmalloc to allocate the
68+ fragment cache memory.
69+
70+ If unsure, say N.
71+
72 config VXFS_FS 58 config VXFS_FS
73 tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" 59 tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
74 depends on BLOCK 60 depends on BLOCK
75--- linux-2.6.24-rc1.orig/fs/Makefile 61diff -x .gitignore -Nurp linux-2.6.24/fs/Makefile linux-2.6.24-squashfs3.3/fs/Makefile
76+++ linux-2.6.24-rc1/fs/Makefile 62--- linux-2.6.24/fs/Makefile 2007-10-25 17:41:45.000000000 +0100
77@@ -72,6 +72,7 @@ 63+++ linux-2.6.24-squashfs3.3/fs/Makefile 2007-11-01 05:08:09.000000000 +0000
64@@ -72,6 +72,7 @@ obj-$(CONFIG_JBD) += jbd/
78 obj-$(CONFIG_JBD2) += jbd2/ 65 obj-$(CONFIG_JBD2) += jbd2/
79 obj-$(CONFIG_EXT2_FS) += ext2/ 66 obj-$(CONFIG_EXT2_FS) += ext2/
80 obj-$(CONFIG_CRAMFS) += cramfs/ 67 obj-$(CONFIG_CRAMFS) += cramfs/
@@ -82,14 +69,15 @@
82 obj-y += ramfs/ 69 obj-y += ramfs/
83 obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ 70 obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
84 obj-$(CONFIG_CODA_FS) += coda/ 71 obj-$(CONFIG_CODA_FS) += coda/
85--- /dev/null 72diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/inode.c linux-2.6.24-squashfs3.3/fs/squashfs/inode.c
86+++ linux-2.6.24-rc1/fs/squashfs/inode.c 73--- linux-2.6.24/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100
87@@ -0,0 +1,2329 @@ 74+++ linux-2.6.24-squashfs3.3/fs/squashfs/inode.c 2007-11-01 05:05:00.000000000 +0000
75@@ -0,0 +1,2192 @@
88+/* 76+/*
89+ * Squashfs - a compressed read only filesystem for Linux 77+ * Squashfs - a compressed read only filesystem for Linux
90+ * 78+ *
91+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 79+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
92+ * Phillip Lougher <phillip@lougher.org.uk> 80+ * Phillip Lougher <phillip@lougher.demon.co.uk>
93+ * 81+ *
94+ * This program is free software; you can redistribute it and/or 82+ * This program is free software; you can redistribute it and/or
95+ * modify it under the terms of the GNU General Public License 83+ * modify it under the terms of the GNU General Public License
@@ -118,9 +106,12 @@
118+#include <linux/vfs.h> 106+#include <linux/vfs.h>
119+#include <linux/vmalloc.h> 107+#include <linux/vmalloc.h>
120+#include <linux/smp_lock.h> 108+#include <linux/smp_lock.h>
109+#include <linux/exportfs.h>
121+ 110+
122+#include "squashfs.h" 111+#include "squashfs.h"
123+ 112+
113+int squashfs_cached_blks;
114+
124+static void vfs_read_inode(struct inode *i); 115+static void vfs_read_inode(struct inode *i);
125+static struct dentry *squashfs_get_parent(struct dentry *child); 116+static struct dentry *squashfs_get_parent(struct dentry *child);
126+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); 117+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
@@ -130,7 +121,6 @@
130+ int readahead_blks, char *block_list, 121+ int readahead_blks, char *block_list,
131+ unsigned short **block_p, unsigned int *bsize); 122+ unsigned short **block_p, unsigned int *bsize);
132+static int squashfs_readpage(struct file *file, struct page *page); 123+static int squashfs_readpage(struct file *file, struct page *page);
133+static int squashfs_readpage4K(struct file *file, struct page *page);
134+static int squashfs_readdir(struct file *, void *, filldir_t); 124+static int squashfs_readdir(struct file *, void *, filldir_t);
135+static struct dentry *squashfs_lookup(struct inode *, struct dentry *, 125+static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
136+ struct nameidata *); 126+ struct nameidata *);
@@ -183,10 +173,6 @@
183+ .readpage = squashfs_readpage 173+ .readpage = squashfs_readpage
184+}; 174+};
185+ 175+
186+SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = {
187+ .readpage = squashfs_readpage4K
188+};
189+
190+static const struct file_operations squashfs_dir_ops = { 176+static const struct file_operations squashfs_dir_ops = {
191+ .read = generic_read_dir, 177+ .read = generic_read_dir,
192+ .readdir = squashfs_readdir 178+ .readdir = squashfs_readdir
@@ -270,30 +256,36 @@
270+{ 256+{
271+ struct squashfs_sb_info *msblk = s->s_fs_info; 257+ struct squashfs_sb_info *msblk = s->s_fs_info;
272+ struct squashfs_super_block *sblk = &msblk->sblk; 258+ struct squashfs_super_block *sblk = &msblk->sblk;
273+ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> 259+ struct buffer_head **bh;
274+ msblk->devblksize_log2) + 2];
275+ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); 260+ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
276+ unsigned int cur_index = index >> msblk->devblksize_log2; 261+ unsigned int cur_index = index >> msblk->devblksize_log2;
277+ int bytes, avail_bytes, b = 0, k = 0; 262+ int bytes, avail_bytes, b = 0, k = 0;
278+ unsigned int compressed; 263+ unsigned int compressed;
279+ unsigned int c_byte = length; 264+ unsigned int c_byte = length;
280+ 265+
266+ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
267+ sizeof(struct buffer_head *), GFP_KERNEL);
268+ if (bh == NULL)
269+ goto read_failure;
270+
281+ if (c_byte) { 271+ if (c_byte) {
282+ bytes = msblk->devblksize - offset; 272+ bytes = msblk->devblksize - offset;
283+ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); 273+ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
284+ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); 274+ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
285+ 275+
286+ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed 276+ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,
287+ ? "" : "un", (unsigned int) c_byte, srclength); 277+ compressed ? "" : "un", (unsigned int) c_byte, srclength);
288+ 278+
289+ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) 279+ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
290+ goto read_failure; 280+ goto read_failure;
291+ 281+
292+ if (!(bh[0] = sb_getblk(s, cur_index))) 282+ bh[0] = sb_getblk(s, cur_index);
283+ if (bh[0] == NULL)
293+ goto block_release; 284+ goto block_release;
294+ 285+
295+ for (b = 1; bytes < c_byte; b++) { 286+ for (b = 1; bytes < c_byte; b++) {
296+ if (!(bh[b] = sb_getblk(s, ++cur_index))) 287+ bh[b] = sb_getblk(s, ++cur_index);
288+ if (bh[b] == NULL)
297+ goto block_release; 289+ goto block_release;
298+ bytes += msblk->devblksize; 290+ bytes += msblk->devblksize;
299+ } 291+ }
@@ -302,8 +294,8 @@
302+ if (index < 0 || (index + 2) > sblk->bytes_used) 294+ if (index < 0 || (index + 2) > sblk->bytes_used)
303+ goto read_failure; 295+ goto read_failure;
304+ 296+
305+ if (!(bh[0] = get_block_length(s, &cur_index, &offset, 297+ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
306+ &c_byte))) 298+ if (bh[0] == NULL)
307+ goto read_failure; 299+ goto read_failure;
308+ 300+
309+ bytes = msblk->devblksize - offset; 301+ bytes = msblk->devblksize - offset;
@@ -317,7 +309,8 @@
317+ goto read_failure; 309+ goto read_failure;
318+ 310+
319+ for (b = 1; bytes < c_byte; b++) { 311+ for (b = 1; bytes < c_byte; b++) {
320+ if (!(bh[b] = sb_getblk(s, ++cur_index))) 312+ bh[b] = sb_getblk(s, ++cur_index);
313+ if (bh[b] == NULL)
321+ goto block_release; 314+ goto block_release;
322+ bytes += msblk->devblksize; 315+ bytes += msblk->devblksize;
323+ } 316+ }
@@ -337,9 +330,8 @@
337+ msblk->stream.avail_out = srclength; 330+ msblk->stream.avail_out = srclength;
338+ 331+
339+ for (bytes = 0; k < b; k++) { 332+ for (bytes = 0; k < b; k++) {
340+ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? 333+ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
341+ msblk->devblksize - offset : 334+
342+ c_byte - bytes;
343+ wait_on_buffer(bh[k]); 335+ wait_on_buffer(bh[k]);
344+ if (!buffer_uptodate(bh[k])) 336+ if (!buffer_uptodate(bh[k]))
345+ goto release_mutex; 337+ goto release_mutex;
@@ -350,8 +342,8 @@
350+ if (k == 0) { 342+ if (k == 0) {
351+ zlib_err = zlib_inflateInit(&msblk->stream); 343+ zlib_err = zlib_inflateInit(&msblk->stream);
352+ if (zlib_err != Z_OK) { 344+ if (zlib_err != Z_OK) {
353+ ERROR("zlib_inflateInit returned unexpected result 0x%x, srclength %d\n", 345+ ERROR("zlib_inflateInit returned unexpected result 0x%x,"
354+ zlib_err, srclength); 346+ " srclength %d\n", zlib_err, srclength);
355+ goto release_mutex; 347+ goto release_mutex;
356+ } 348+ }
357+ 349+
@@ -364,8 +356,9 @@
364+ 356+
365+ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); 357+ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
366+ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) { 358+ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
367+ ERROR("zlib_inflate returned unexpected result 0x%x, srclength %d, avail_in %d, avail_out %d\n", 359+ ERROR("zlib_inflate returned unexpected result 0x%x,"
368+ zlib_err, srclength, msblk->stream.avail_in, msblk->stream.avail_out); 360+ " srclength %d, avail_in %d, avail_out %d\n", zlib_err,
361+ srclength, msblk->stream.avail_in, msblk->stream.avail_out);
369+ goto release_mutex; 362+ goto release_mutex;
370+ } 363+ }
371+ 364+
@@ -379,8 +372,8 @@
379+ 372+
380+ zlib_err = zlib_inflateEnd(&msblk->stream); 373+ zlib_err = zlib_inflateEnd(&msblk->stream);
381+ if (zlib_err != Z_OK) { 374+ if (zlib_err != Z_OK) {
382+ ERROR("zlib_inflateEnd returned unexpected result 0x%x, srclength %d\n", 375+ ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
383+ zlib_err, srclength); 376+ " srclength %d\n", zlib_err, srclength);
384+ goto release_mutex; 377+ goto release_mutex;
385+ } 378+ }
386+ bytes = msblk->stream.total_out; 379+ bytes = msblk->stream.total_out;
@@ -390,14 +383,13 @@
390+ 383+
391+ for(i = 0; i < b; i++) { 384+ for(i = 0; i < b; i++) {
392+ wait_on_buffer(bh[i]); 385+ wait_on_buffer(bh[i]);
393+ if(!buffer_uptodate(bh[i])) 386+ if (!buffer_uptodate(bh[i]))
394+ goto block_release; 387+ goto block_release;
395+ } 388+ }
396+ 389+
397+ for (bytes = 0; k < b; k++) { 390+ for (bytes = 0; k < b; k++) {
398+ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? 391+ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
399+ msblk->devblksize - offset : 392+
400+ c_byte - bytes;
401+ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); 393+ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
402+ bytes += avail_bytes; 394+ bytes += avail_bytes;
403+ offset = 0; 395+ offset = 0;
@@ -407,8 +399,9 @@
407+ 399+
408+ if (next_index) 400+ if (next_index)
409+ *next_index = index + c_byte + (length ? 0 : 401+ *next_index = index + c_byte + (length ? 0 :
410+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) 402+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));
411+ ? 3 : 2)); 403+
404+ kfree(bh);
412+ return bytes; 405+ return bytes;
413+ 406+
414+release_mutex: 407+release_mutex:
@@ -420,11 +413,12 @@
420+ 413+
421+read_failure: 414+read_failure:
422+ ERROR("sb_bread failed reading block 0x%x\n", cur_index); 415+ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
416+ kfree(bh);
423+ return 0; 417+ return 0;
424+} 418+}
425+ 419+
426+ 420+
427+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, 421+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer,
428+ long long block, unsigned int offset, 422+ long long block, unsigned int offset,
429+ int length, long long *next_block, 423+ int length, long long *next_block,
430+ unsigned int *next_offset) 424+ unsigned int *next_offset)
@@ -435,68 +429,65 @@
435+ 429+
436+ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); 430+ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
437+ 431+
438+ while ( 1 ) { 432+ while (1) {
439+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 433+ for (i = 0; i < squashfs_cached_blks; i++)
440+ if (msblk->block_cache[i].block == block) 434+ if (msblk->block_cache[i].block == block)
441+ break; 435+ break;
442+ 436+
443+ mutex_lock(&msblk->block_cache_mutex); 437+ mutex_lock(&msblk->block_cache_mutex);
444+ 438+
445+ if (i == SQUASHFS_CACHED_BLKS) { 439+ if (i == squashfs_cached_blks) {
446+ /* read inode header block */ 440+ /* read inode header block */
447+ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS; 441+ if (msblk->unused_cache_blks == 0) {
448+ n ; n --, i = (i + 1) % 442+ mutex_unlock(&msblk->block_cache_mutex);
449+ SQUASHFS_CACHED_BLKS) 443+ wait_event(msblk->waitq, msblk->unused_cache_blks);
450+ if (msblk->block_cache[i].block != 444+ continue;
451+ SQUASHFS_USED_BLK) 445+ }
446+
447+ i = msblk->next_cache;
448+ for (n = 0; n < squashfs_cached_blks; n++) {
449+ if (msblk->block_cache[i].block != SQUASHFS_USED_BLK)
452+ break; 450+ break;
451+ i = (i + 1) % squashfs_cached_blks;
452+ }
453+ 453+
454+ if (n == 0) { 454+ msblk->next_cache = (i + 1) % squashfs_cached_blks;
455+ wait_queue_t wait;
456+ 455+
457+ init_waitqueue_entry(&wait, current); 456+ if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) {
458+ add_wait_queue(&msblk->waitq, &wait); 457+ msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE);
459+ set_current_state(TASK_UNINTERRUPTIBLE); 458+ if (msblk->block_cache[i].data == NULL) {
460+ mutex_unlock(&msblk->block_cache_mutex); 459+ ERROR("Failed to allocate cache block\n");
461+ schedule();
462+ set_current_state(TASK_RUNNING);
463+ remove_wait_queue(&msblk->waitq, &wait);
464+ continue;
465+ }
466+ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
467+
468+ if (msblk->block_cache[i].block ==
469+ SQUASHFS_INVALID_BLK) {
470+ if (!(msblk->block_cache[i].data =
471+ kmalloc(SQUASHFS_METADATA_SIZE,
472+ GFP_KERNEL))) {
473+ ERROR("Failed to allocate cache"
474+ "block\n");
475+ mutex_unlock(&msblk->block_cache_mutex); 460+ mutex_unlock(&msblk->block_cache_mutex);
476+ goto out; 461+ goto out;
477+ } 462+ }
478+ } 463+ }
479+ 464+
480+ msblk->block_cache[i].block = SQUASHFS_USED_BLK; 465+ msblk->block_cache[i].block = SQUASHFS_USED_BLK;
466+ msblk->unused_cache_blks --;
481+ mutex_unlock(&msblk->block_cache_mutex); 467+ mutex_unlock(&msblk->block_cache_mutex);
482+ 468+
483+ msblk->block_cache[i].length = squashfs_read_data(s, 469+ msblk->block_cache[i].length = squashfs_read_data(s,
484+ msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE); 470+ msblk->block_cache[i].data, block, 0, &next_index,
471+ SQUASHFS_METADATA_SIZE);
472+
485+ if (msblk->block_cache[i].length == 0) { 473+ if (msblk->block_cache[i].length == 0) {
486+ ERROR("Unable to read cache block [%llx:%x]\n", 474+ ERROR("Unable to read cache block [%llx:%x]\n", block, offset);
487+ block, offset);
488+ mutex_lock(&msblk->block_cache_mutex); 475+ mutex_lock(&msblk->block_cache_mutex);
489+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; 476+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
490+ kfree(msblk->block_cache[i].data); 477+ msblk->unused_cache_blks ++;
478+ smp_mb();
479+ vfree(msblk->block_cache[i].data);
491+ wake_up(&msblk->waitq); 480+ wake_up(&msblk->waitq);
492+ mutex_unlock(&msblk->block_cache_mutex); 481+ mutex_unlock(&msblk->block_cache_mutex);
493+ goto out; 482+ goto out;
494+ } 483+ }
495+ 484+
496+ mutex_lock(&msblk->block_cache_mutex); 485+ mutex_lock(&msblk->block_cache_mutex);
497+ wake_up(&msblk->waitq);
498+ msblk->block_cache[i].block = block; 486+ msblk->block_cache[i].block = block;
499+ msblk->block_cache[i].next_index = next_index; 487+ msblk->block_cache[i].next_index = next_index;
488+ msblk->unused_cache_blks ++;
489+ smp_mb();
490+ wake_up(&msblk->waitq);
500+ TRACE("Read cache block [%llx:%x]\n", block, offset); 491+ TRACE("Read cache block [%llx:%x]\n", block, offset);
501+ } 492+ }
502+ 493+
@@ -512,8 +503,7 @@
512+ goto out; 503+ goto out;
513+ } else if (bytes >= length) { 504+ } else if (bytes >= length) {
514+ if (buffer) 505+ if (buffer)
515+ memcpy(buffer, msblk->block_cache[i].data + 506+ memcpy(buffer, msblk->block_cache[i].data + offset, length);
516+ offset, length);
517+ if (msblk->block_cache[i].length - offset == length) { 507+ if (msblk->block_cache[i].length - offset == length) {
518+ *next_block = msblk->block_cache[i].next_index; 508+ *next_block = msblk->block_cache[i].next_index;
519+ *next_offset = 0; 509+ *next_offset = 0;
@@ -525,9 +515,8 @@
525+ goto finish; 515+ goto finish;
526+ } else { 516+ } else {
527+ if (buffer) { 517+ if (buffer) {
528+ memcpy(buffer, msblk->block_cache[i].data + 518+ memcpy(buffer, msblk->block_cache[i].data + offset, bytes);
529+ offset, bytes); 519+ buffer = (char *) buffer + bytes;
530+ buffer += bytes;
531+ } 520+ }
532+ block = msblk->block_cache[i].next_index; 521+ block = msblk->block_cache[i].next_index;
533+ mutex_unlock(&msblk->block_cache_mutex); 522+ mutex_unlock(&msblk->block_cache_mutex);
@@ -556,17 +545,13 @@
556+ if (msblk->swap) { 545+ if (msblk->swap) {
557+ struct squashfs_fragment_entry sfragment_entry; 546+ struct squashfs_fragment_entry sfragment_entry;
558+ 547+
559+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, 548+ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset,
560+ start_block, offset, 549+ sizeof(sfragment_entry), &start_block, &offset))
561+ sizeof(sfragment_entry), &start_block,
562+ &offset))
563+ goto out; 550+ goto out;
564+ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); 551+ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
565+ } else 552+ } else
566+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, 553+ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset,
567+ start_block, offset, 554+ sizeof(fragment_entry), &start_block, &offset))
568+ sizeof(fragment_entry), &start_block,
569+ &offset))
570+ goto out; 555+ goto out;
571+ 556+
572+ *fragment_start_block = fragment_entry.start_block; 557+ *fragment_start_block = fragment_entry.start_block;
@@ -579,90 +564,92 @@
579+} 564+}
580+ 565+
581+ 566+
582+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct 567+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk,
583+ squashfs_fragment_cache *fragment) 568+ struct squashfs_fragment_cache *fragment)
584+{ 569+{
585+ mutex_lock(&msblk->fragment_mutex); 570+ mutex_lock(&msblk->fragment_mutex);
586+ fragment->locked --; 571+ fragment->locked --;
587+ wake_up(&msblk->fragment_wait_queue); 572+ if (fragment->locked == 0) {
573+ msblk->unused_frag_blks ++;
574+ smp_mb();
575+ wake_up(&msblk->fragment_wait_queue);
576+ }
588+ mutex_unlock(&msblk->fragment_mutex); 577+ mutex_unlock(&msblk->fragment_mutex);
589+} 578+}
590+ 579+
591+ 580+
592+SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block 581+SQSH_EXTERN
593+ *s, long long start_block, 582+struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s,
594+ int length) 583+ long long start_block, int length)
595+{ 584+{
596+ int i, n; 585+ int i, n;
597+ struct squashfs_sb_info *msblk = s->s_fs_info; 586+ struct squashfs_sb_info *msblk = s->s_fs_info;
598+ struct squashfs_super_block *sblk = &msblk->sblk; 587+ struct squashfs_super_block *sblk = &msblk->sblk;
599+ 588+
600+ while ( 1 ) { 589+ while (1) {
601+ mutex_lock(&msblk->fragment_mutex); 590+ mutex_lock(&msblk->fragment_mutex);
602+ 591+
603+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && 592+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
604+ msblk->fragment[i].block != start_block; i++); 593+ msblk->fragment[i].block != start_block; i++);
605+ 594+
606+ if (i == SQUASHFS_CACHED_FRAGMENTS) { 595+ if (i == SQUASHFS_CACHED_FRAGMENTS) {
607+ for (i = msblk->next_fragment, n = 596+ if (msblk->unused_frag_blks == 0) {
608+ SQUASHFS_CACHED_FRAGMENTS; n &&
609+ msblk->fragment[i].locked; n--, i = (i + 1) %
610+ SQUASHFS_CACHED_FRAGMENTS);
611+
612+ if (n == 0) {
613+ wait_queue_t wait;
614+
615+ init_waitqueue_entry(&wait, current);
616+ add_wait_queue(&msblk->fragment_wait_queue,
617+ &wait);
618+ set_current_state(TASK_UNINTERRUPTIBLE);
619+ mutex_unlock(&msblk->fragment_mutex); 597+ mutex_unlock(&msblk->fragment_mutex);
620+ schedule(); 598+ wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks);
621+ set_current_state(TASK_RUNNING);
622+ remove_wait_queue(&msblk->fragment_wait_queue,
623+ &wait);
624+ continue; 599+ continue;
625+ } 600+ }
601+
602+ i = msblk->next_fragment;
603+ for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) {
604+ if (msblk->fragment[i].locked == 0)
605+ break;
606+ i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS;
607+ }
608+
626+ msblk->next_fragment = (msblk->next_fragment + 1) % 609+ msblk->next_fragment = (msblk->next_fragment + 1) %
627+ SQUASHFS_CACHED_FRAGMENTS; 610+ SQUASHFS_CACHED_FRAGMENTS;
628+ 611+
629+ if (msblk->fragment[i].data == NULL) 612+ if (msblk->fragment[i].data == NULL) {
630+ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC 613+ msblk->fragment[i].data = vmalloc(sblk->block_size);
631+ (SQUASHFS_FILE_MAX_SIZE))) { 614+ if (msblk->fragment[i].data == NULL) {
632+ ERROR("Failed to allocate fragment " 615+ ERROR("Failed to allocate fragment cache block\n");
633+ "cache block\n");
634+ mutex_unlock(&msblk->fragment_mutex); 616+ mutex_unlock(&msblk->fragment_mutex);
635+ goto out; 617+ goto out;
636+ } 618+ }
619+ }
637+ 620+
621+ msblk->unused_frag_blks --;
638+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; 622+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
639+ msblk->fragment[i].locked = 1; 623+ msblk->fragment[i].locked = 1;
640+ mutex_unlock(&msblk->fragment_mutex); 624+ mutex_unlock(&msblk->fragment_mutex);
641+ 625+
642+ if (!(msblk->fragment[i].length = squashfs_read_data(s, 626+ msblk->fragment[i].length = squashfs_read_data(s,
643+ msblk->fragment[i].data, 627+ msblk->fragment[i].data, start_block, length, NULL,
644+ start_block, length, NULL, sblk->block_size))) { 628+ sblk->block_size);
645+ ERROR("Unable to read fragment cache block " 629+
646+ "[%llx]\n", start_block); 630+ if (msblk->fragment[i].length == 0) {
631+ ERROR("Unable to read fragment cache block [%llx]\n", start_block);
647+ msblk->fragment[i].locked = 0; 632+ msblk->fragment[i].locked = 0;
633+ msblk->unused_frag_blks ++;
648+ smp_mb(); 634+ smp_mb();
635+ wake_up(&msblk->fragment_wait_queue);
649+ goto out; 636+ goto out;
650+ } 637+ }
651+ 638+
652+ mutex_lock(&msblk->fragment_mutex); 639+ mutex_lock(&msblk->fragment_mutex);
653+ msblk->fragment[i].block = start_block; 640+ msblk->fragment[i].block = start_block;
654+ TRACE("New fragment %d, start block %lld, locked %d\n", 641+ TRACE("New fragment %d, start block %lld, locked %d\n",
655+ i, msblk->fragment[i].block, 642+ i, msblk->fragment[i].block, msblk->fragment[i].locked);
656+ msblk->fragment[i].locked);
657+ mutex_unlock(&msblk->fragment_mutex); 643+ mutex_unlock(&msblk->fragment_mutex);
658+ break; 644+ break;
659+ } 645+ }
660+ 646+
647+ if (msblk->fragment[i].locked == 0)
648+ msblk->unused_frag_blks --;
661+ msblk->fragment[i].locked++; 649+ msblk->fragment[i].locked++;
662+ mutex_unlock(&msblk->fragment_mutex); 650+ mutex_unlock(&msblk->fragment_mutex);
663+ TRACE("Got fragment %d, start block %lld, locked %d\n", i, 651+ TRACE("Got fragment %d, start block %lld, locked %d\n", i,
664+ msblk->fragment[i].block, 652+ msblk->fragment[i].block, msblk->fragment[i].locked);
665+ msblk->fragment[i].locked);
666+ break; 653+ break;
667+ } 654+ }
668+ 655+
@@ -674,7 +661,7 @@
674+ 661+
675+ 662+
676+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, 663+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
677+ struct squashfs_base_inode_header *inodeb) 664+ struct squashfs_base_inode_header *inodeb)
678+{ 665+{
679+ i->i_ino = inodeb->inode_number; 666+ i->i_ino = inodeb->inode_number;
680+ i->i_mtime.tv_sec = inodeb->mtime; 667+ i->i_mtime.tv_sec = inodeb->mtime;
@@ -683,6 +670,7 @@
683+ i->i_uid = msblk->uid[inodeb->uid]; 670+ i->i_uid = msblk->uid[inodeb->uid];
684+ i->i_mode = inodeb->mode; 671+ i->i_mode = inodeb->mode;
685+ i->i_size = 0; 672+ i->i_size = 0;
673+
686+ if (inodeb->guid == SQUASHFS_GUIDS) 674+ if (inodeb->guid == SQUASHFS_GUIDS)
687+ i->i_gid = i->i_uid; 675+ i->i_gid = i->i_uid;
688+ else 676+ else
@@ -702,11 +690,11 @@
702+ if (msblk->swap) { 690+ if (msblk->swap) {
703+ squashfs_inode_t sinode; 691+ squashfs_inode_t sinode;
704+ 692+
705+ if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset, 693+ if (!squashfs_get_cached_block(s, &sinode, start, offset,
706+ sizeof(sinode), &start, &offset)) 694+ sizeof(sinode), &start, &offset))
707+ goto out; 695+ goto out;
708+ SQUASHFS_SWAP_INODE_T((&inode), &sinode); 696+ SQUASHFS_SWAP_INODE_T((&inode), &sinode);
709+ } else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset, 697+ } else if (!squashfs_get_cached_block(s, &inode, start, offset,
710+ sizeof(inode), &start, &offset)) 698+ sizeof(inode), &start, &offset))
711+ goto out; 699+ goto out;
712+ 700+
@@ -753,7 +741,8 @@
753+} 741+}
754+ 742+
755+ 743+
756+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number) 744+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s,
745+ squashfs_inode_t inode, unsigned int inode_number)
757+{ 746+{
758+ struct squashfs_sb_info *msblk = s->s_fs_info; 747+ struct squashfs_sb_info *msblk = s->s_fs_info;
759+ struct inode *i = iget_locked(s, inode_number); 748+ struct inode *i = iget_locked(s, inode_number);
@@ -774,28 +763,23 @@
774+ struct super_block *s = i->i_sb; 763+ struct super_block *s = i->i_sb;
775+ struct squashfs_sb_info *msblk = s->s_fs_info; 764+ struct squashfs_sb_info *msblk = s->s_fs_info;
776+ struct squashfs_super_block *sblk = &msblk->sblk; 765+ struct squashfs_super_block *sblk = &msblk->sblk;
777+ long long block = SQUASHFS_INODE_BLK(inode) + 766+ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start;
778+ sblk->inode_table_start;
779+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); 767+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
780+ long long next_block; 768+ long long next_block;
781+ unsigned int next_offset; 769+ unsigned int next_offset;
782+ union squashfs_inode_header id, sid; 770+ union squashfs_inode_header id, sid;
783+ struct squashfs_base_inode_header *inodeb = &id.base, 771+ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base;
784+ *sinodeb = &sid.base;
785+ 772+
786+ TRACE("Entered squashfs_read_inode\n"); 773+ TRACE("Entered squashfs_read_inode\n");
787+ 774+
788+ if (msblk->swap) { 775+ if (msblk->swap) {
789+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, 776+ if (!squashfs_get_cached_block(s, sinodeb, block, offset,
790+ offset, sizeof(*sinodeb), &next_block, 777+ sizeof(*sinodeb), &next_block, &next_offset))
791+ &next_offset))
792+ goto failed_read; 778+ goto failed_read;
793+ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, 779+ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb));
794+ sizeof(*sinodeb));
795+ } else 780+ } else
796+ if (!squashfs_get_cached_block(s, (char *) inodeb, block, 781+ if (!squashfs_get_cached_block(s, inodeb, block, offset,
797+ offset, sizeof(*inodeb), &next_block, 782+ sizeof(*inodeb), &next_block, &next_offset))
798+ &next_offset))
799+ goto failed_read; 783+ goto failed_read;
800+ 784+
801+ squashfs_new_inode(msblk, i, inodeb); 785+ squashfs_new_inode(msblk, i, inodeb);
@@ -808,24 +792,21 @@
808+ struct squashfs_reg_inode_header *sinodep = &sid.reg; 792+ struct squashfs_reg_inode_header *sinodep = &sid.reg;
809+ 793+
810+ if (msblk->swap) { 794+ if (msblk->swap) {
811+ if (!squashfs_get_cached_block(s, (char *) 795+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
812+ sinodep, block, offset, 796+ sizeof(*sinodep), &next_block, &next_offset))
813+ sizeof(*sinodep), &next_block,
814+ &next_offset))
815+ goto failed_read; 797+ goto failed_read;
816+ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); 798+ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
817+ } else 799+ } else
818+ if (!squashfs_get_cached_block(s, (char *) 800+ if (!squashfs_get_cached_block(s, inodep, block, offset,
819+ inodep, block, offset, 801+ sizeof(*inodep), &next_block, &next_offset))
820+ sizeof(*inodep), &next_block,
821+ &next_offset))
822+ goto failed_read; 802+ goto failed_read;
823+ 803+
824+ frag_blk = SQUASHFS_INVALID_BLK; 804+ frag_blk = SQUASHFS_INVALID_BLK;
825+ if (inodep->fragment != SQUASHFS_INVALID_FRAG && 805+
826+ !get_fragment_location(s, 806+ if (inodep->fragment != SQUASHFS_INVALID_FRAG)
827+ inodep->fragment, &frag_blk, &frag_size)) 807+ if(!get_fragment_location(s, inodep->fragment, &frag_blk,
828+ goto failed_read; 808+ &frag_size))
809+ goto failed_read;
829+ 810+
830+ i->i_nlink = 1; 811+ i->i_nlink = 1;
831+ i->i_size = inodep->file_size; 812+ i->i_size = inodep->file_size;
@@ -838,10 +819,7 @@
838+ SQUASHFS_I(i)->start_block = inodep->start_block; 819+ SQUASHFS_I(i)->start_block = inodep->start_block;
839+ SQUASHFS_I(i)->u.s1.block_list_start = next_block; 820+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
840+ SQUASHFS_I(i)->offset = next_offset; 821+ SQUASHFS_I(i)->offset = next_offset;
841+ if (sblk->block_size > 4096) 822+ i->i_data.a_ops = &squashfs_aops;
842+ i->i_data.a_ops = &squashfs_aops;
843+ else
844+ i->i_data.a_ops = &squashfs_aops_4K;
845+ 823+
846+ TRACE("File inode %x:%x, start_block %llx, " 824+ TRACE("File inode %x:%x, start_block %llx, "
847+ "block_list_start %llx, offset %x\n", 825+ "block_list_start %llx, offset %x\n",
@@ -857,24 +835,21 @@
857+ struct squashfs_lreg_inode_header *sinodep = &sid.lreg; 835+ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
858+ 836+
859+ if (msblk->swap) { 837+ if (msblk->swap) {
860+ if (!squashfs_get_cached_block(s, (char *) 838+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
861+ sinodep, block, offset, 839+ sizeof(*sinodep), &next_block, &next_offset))
862+ sizeof(*sinodep), &next_block,
863+ &next_offset))
864+ goto failed_read; 840+ goto failed_read;
865+ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); 841+ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
866+ } else 842+ } else
867+ if (!squashfs_get_cached_block(s, (char *) 843+ if (!squashfs_get_cached_block(s, inodep, block, offset,
868+ inodep, block, offset, 844+ sizeof(*inodep), &next_block, &next_offset))
869+ sizeof(*inodep), &next_block,
870+ &next_offset))
871+ goto failed_read; 845+ goto failed_read;
872+ 846+
873+ frag_blk = SQUASHFS_INVALID_BLK; 847+ frag_blk = SQUASHFS_INVALID_BLK;
874+ if (inodep->fragment != SQUASHFS_INVALID_FRAG && 848+
875+ !get_fragment_location(s, 849+ if (inodep->fragment != SQUASHFS_INVALID_FRAG)
876+ inodep->fragment, &frag_blk, &frag_size)) 850+ if (!get_fragment_location(s, inodep->fragment, &frag_blk,
877+ goto failed_read; 851+ &frag_size))
852+ goto failed_read;
878+ 853+
879+ i->i_nlink = inodep->nlink; 854+ i->i_nlink = inodep->nlink;
880+ i->i_size = inodep->file_size; 855+ i->i_size = inodep->file_size;
@@ -887,10 +862,7 @@
887+ SQUASHFS_I(i)->start_block = inodep->start_block; 862+ SQUASHFS_I(i)->start_block = inodep->start_block;
888+ SQUASHFS_I(i)->u.s1.block_list_start = next_block; 863+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
889+ SQUASHFS_I(i)->offset = next_offset; 864+ SQUASHFS_I(i)->offset = next_offset;
890+ if (sblk->block_size > 4096) 865+ i->i_data.a_ops = &squashfs_aops;
891+ i->i_data.a_ops = &squashfs_aops;
892+ else
893+ i->i_data.a_ops = &squashfs_aops_4K;
894+ 866+
895+ TRACE("File inode %x:%x, start_block %llx, " 867+ TRACE("File inode %x:%x, start_block %llx, "
896+ "block_list_start %llx, offset %x\n", 868+ "block_list_start %llx, offset %x\n",
@@ -904,17 +876,13 @@
904+ struct squashfs_dir_inode_header *sinodep = &sid.dir; 876+ struct squashfs_dir_inode_header *sinodep = &sid.dir;
905+ 877+
906+ if (msblk->swap) { 878+ if (msblk->swap) {
907+ if (!squashfs_get_cached_block(s, (char *) 879+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
908+ sinodep, block, offset, 880+ sizeof(*sinodep), &next_block, &next_offset))
909+ sizeof(*sinodep), &next_block,
910+ &next_offset))
911+ goto failed_read; 881+ goto failed_read;
912+ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); 882+ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
913+ } else 883+ } else
914+ if (!squashfs_get_cached_block(s, (char *) 884+ if (!squashfs_get_cached_block(s, inodep, block, offset,
915+ inodep, block, offset, 885+ sizeof(*inodep), &next_block, &next_offset))
916+ sizeof(*inodep), &next_block,
917+ &next_offset))
918+ goto failed_read; 886+ goto failed_read;
919+ 887+
920+ i->i_nlink = inodep->nlink; 888+ i->i_nlink = inodep->nlink;
@@ -938,18 +906,13 @@
938+ struct squashfs_ldir_inode_header *sinodep = &sid.ldir; 906+ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
939+ 907+
940+ if (msblk->swap) { 908+ if (msblk->swap) {
941+ if (!squashfs_get_cached_block(s, (char *) 909+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
942+ sinodep, block, offset, 910+ sizeof(*sinodep), &next_block, &next_offset))
943+ sizeof(*sinodep), &next_block,
944+ &next_offset))
945+ goto failed_read; 911+ goto failed_read;
946+ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, 912+ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep);
947+ sinodep);
948+ } else 913+ } else
949+ if (!squashfs_get_cached_block(s, (char *) 914+ if (!squashfs_get_cached_block(s, inodep, block, offset,
950+ inodep, block, offset, 915+ sizeof(*inodep), &next_block, &next_offset))
951+ sizeof(*inodep), &next_block,
952+ &next_offset))
953+ goto failed_read; 916+ goto failed_read;
954+ 917+
955+ i->i_nlink = inodep->nlink; 918+ i->i_nlink = inodep->nlink;
@@ -960,37 +923,27 @@
960+ SQUASHFS_I(i)->start_block = inodep->start_block; 923+ SQUASHFS_I(i)->start_block = inodep->start_block;
961+ SQUASHFS_I(i)->offset = inodep->offset; 924+ SQUASHFS_I(i)->offset = inodep->offset;
962+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; 925+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
963+ SQUASHFS_I(i)->u.s2.directory_index_offset = 926+ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset;
964+ next_offset; 927+ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count;
965+ SQUASHFS_I(i)->u.s2.directory_index_count =
966+ inodep->i_count;
967+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; 928+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
968+ 929+
969+ TRACE("Long directory inode %x:%x, start_block %x, " 930+ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n",
970+ "offset %x\n",
971+ SQUASHFS_INODE_BLK(inode), offset, 931+ SQUASHFS_INODE_BLK(inode), offset,
972+ inodep->start_block, inodep->offset); 932+ inodep->start_block, inodep->offset);
973+ break; 933+ break;
974+ } 934+ }
975+ case SQUASHFS_SYMLINK_TYPE: { 935+ case SQUASHFS_SYMLINK_TYPE: {
976+ struct squashfs_symlink_inode_header *inodep = 936+ struct squashfs_symlink_inode_header *inodep = &id.symlink;
977+ &id.symlink; 937+ struct squashfs_symlink_inode_header *sinodep = &sid.symlink;
978+ struct squashfs_symlink_inode_header *sinodep =
979+ &sid.symlink;
980+ 938+
981+ if (msblk->swap) { 939+ if (msblk->swap) {
982+ if (!squashfs_get_cached_block(s, (char *) 940+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
983+ sinodep, block, offset, 941+ sizeof(*sinodep), &next_block, &next_offset))
984+ sizeof(*sinodep), &next_block,
985+ &next_offset))
986+ goto failed_read; 942+ goto failed_read;
987+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, 943+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep);
988+ sinodep);
989+ } else 944+ } else
990+ if (!squashfs_get_cached_block(s, (char *) 945+ if (!squashfs_get_cached_block(s, inodep, block, offset,
991+ inodep, block, offset, 946+ sizeof(*inodep), &next_block, &next_offset))
992+ sizeof(*inodep), &next_block,
993+ &next_offset))
994+ goto failed_read; 947+ goto failed_read;
995+ 948+
996+ i->i_nlink = inodep->nlink; 949+ i->i_nlink = inodep->nlink;
@@ -1001,8 +954,7 @@
1001+ SQUASHFS_I(i)->start_block = next_block; 954+ SQUASHFS_I(i)->start_block = next_block;
1002+ SQUASHFS_I(i)->offset = next_offset; 955+ SQUASHFS_I(i)->offset = next_offset;
1003+ 956+
1004+ TRACE("Symbolic link inode %x:%x, start_block %llx, " 957+ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n",
1005+ "offset %x\n",
1006+ SQUASHFS_INODE_BLK(inode), offset, 958+ SQUASHFS_INODE_BLK(inode), offset,
1007+ next_block, next_offset); 959+ next_block, next_offset);
1008+ break; 960+ break;
@@ -1013,29 +965,22 @@
1013+ struct squashfs_dev_inode_header *sinodep = &sid.dev; 965+ struct squashfs_dev_inode_header *sinodep = &sid.dev;
1014+ 966+
1015+ if (msblk->swap) { 967+ if (msblk->swap) {
1016+ if (!squashfs_get_cached_block(s, (char *) 968+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
1017+ sinodep, block, offset, 969+ sizeof(*sinodep), &next_block, &next_offset))
1018+ sizeof(*sinodep), &next_block,
1019+ &next_offset))
1020+ goto failed_read; 970+ goto failed_read;
1021+ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); 971+ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
1022+ } else 972+ } else
1023+ if (!squashfs_get_cached_block(s, (char *) 973+ if (!squashfs_get_cached_block(s, inodep, block, offset,
1024+ inodep, block, offset, 974+ sizeof(*inodep), &next_block, &next_offset))
1025+ sizeof(*inodep), &next_block,
1026+ &next_offset))
1027+ goto failed_read; 975+ goto failed_read;
1028+ 976+
1029+ i->i_nlink = inodep->nlink; 977+ i->i_nlink = inodep->nlink;
1030+ i->i_mode |= (inodeb->inode_type == 978+ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ?
1031+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : 979+ S_IFCHR : S_IFBLK;
1032+ S_IFBLK; 980+ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev));
1033+ init_special_inode(i, i->i_mode,
1034+ old_decode_dev(inodep->rdev));
1035+ 981+
1036+ TRACE("Device inode %x:%x, rdev %x\n", 982+ TRACE("Device inode %x:%x, rdev %x\n",
1037+ SQUASHFS_INODE_BLK(inode), offset, 983+ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev);
1038+ inodep->rdev);
1039+ break; 984+ break;
1040+ } 985+ }
1041+ case SQUASHFS_FIFO_TYPE: 986+ case SQUASHFS_FIFO_TYPE:
@@ -1044,17 +989,13 @@
1044+ struct squashfs_ipc_inode_header *sinodep = &sid.ipc; 989+ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
1045+ 990+
1046+ if (msblk->swap) { 991+ if (msblk->swap) {
1047+ if (!squashfs_get_cached_block(s, (char *) 992+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
1048+ sinodep, block, offset, 993+ sizeof(*sinodep), &next_block, &next_offset))
1049+ sizeof(*sinodep), &next_block,
1050+ &next_offset))
1051+ goto failed_read; 994+ goto failed_read;
1052+ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); 995+ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
1053+ } else 996+ } else
1054+ if (!squashfs_get_cached_block(s, (char *) 997+ if (!squashfs_get_cached_block(s, inodep, block, offset,
1055+ inodep, block, offset, 998+ sizeof(*inodep), &next_block, &next_offset))
1056+ sizeof(*inodep), &next_block,
1057+ &next_offset))
1058+ goto failed_read; 999+ goto failed_read;
1059+ 1000+
1060+ i->i_nlink = inodep->nlink; 1001+ i->i_nlink = inodep->nlink;
@@ -1089,7 +1030,8 @@
1089+ TRACE("In read_inode_lookup_table, length %d\n", length); 1030+ TRACE("In read_inode_lookup_table, length %d\n", length);
1090+ 1031+
1091+ /* Allocate inode lookup table */ 1032+ /* Allocate inode lookup table */
1092+ if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) { 1033+ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL);
1034+ if (msblk->inode_lookup_table == NULL) {
1093+ ERROR("Failed to allocate inode lookup table\n"); 1035+ ERROR("Failed to allocate inode lookup table\n");
1094+ return 0; 1036+ return 0;
1095+ } 1037+ }
@@ -1106,6 +1048,7 @@
1106+ long long block; 1048+ long long block;
1107+ 1049+
1108+ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { 1050+ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
1051+ /* XXX */
1109+ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), 1052+ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
1110+ &msblk->inode_lookup_table[i], 1); 1053+ &msblk->inode_lookup_table[i], 1);
1111+ msblk->inode_lookup_table[i] = block; 1054+ msblk->inode_lookup_table[i] = block;
@@ -1126,7 +1069,8 @@
1126+ return 1; 1069+ return 1;
1127+ 1070+
1128+ /* Allocate fragment index table */ 1071+ /* Allocate fragment index table */
1129+ if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) { 1072+ msblk->fragment_index = kmalloc(length, GFP_KERNEL);
1073+ if (msblk->fragment_index == NULL) {
1130+ ERROR("Failed to allocate fragment index table\n"); 1074+ ERROR("Failed to allocate fragment index table\n");
1131+ return 0; 1075+ return 0;
1132+ } 1076+ }
@@ -1143,6 +1087,7 @@
1143+ long long fragment; 1087+ long long fragment;
1144+ 1088+
1145+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { 1089+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
1090+ /* XXX */
1146+ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), 1091+ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
1147+ &msblk->fragment_index[i], 1); 1092+ &msblk->fragment_index[i], 1);
1148+ msblk->fragment_index[i] = fragment; 1093+ msblk->fragment_index[i] = fragment;
@@ -1153,6 +1098,34 @@
1153+} 1098+}
1154+ 1099+
1155+ 1100+
1101+static int readahead_metadata(struct super_block *s)
1102+{
1103+ struct squashfs_sb_info *msblk = s->s_fs_info;
1104+ int i;
1105+
1106+ squashfs_cached_blks = SQUASHFS_CACHED_BLKS;
1107+
1108+ /* Init inode_table block pointer array */
1109+ msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
1110+ squashfs_cached_blks, GFP_KERNEL);
1111+ if (msblk->block_cache == NULL) {
1112+ ERROR("Failed to allocate block cache\n");
1113+ goto failed;
1114+ }
1115+
1116+ for (i = 0; i < squashfs_cached_blks; i++)
1117+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
1118+
1119+ msblk->next_cache = 0;
1120+ msblk->unused_cache_blks = squashfs_cached_blks;
1121+
1122+ return 1;
1123+
1124+failed:
1125+ return 0;
1126+}
1127+
1128+
1156+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) 1129+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
1157+{ 1130+{
1158+ struct squashfs_super_block *sblk = &msblk->sblk; 1131+ struct squashfs_super_block *sblk = &msblk->sblk;
@@ -1165,16 +1138,14 @@
1165+ if (!squashfs_1_0_supported(msblk)) { 1138+ if (!squashfs_1_0_supported(msblk)) {
1166+ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " 1139+ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
1167+ "are unsupported\n"); 1140+ "are unsupported\n");
1168+ SERROR("Please recompile with " 1141+ SERROR("Please recompile with Squashfs 1.0 support enabled\n");
1169+ "Squashfs 1.0 support enabled\n");
1170+ return 0; 1142+ return 0;
1171+ } 1143+ }
1172+ } else if (sblk->s_major == 2) { 1144+ } else if (sblk->s_major == 2) {
1173+ if (!squashfs_2_0_supported(msblk)) { 1145+ if (!squashfs_2_0_supported(msblk)) {
1174+ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " 1146+ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
1175+ "are unsupported\n"); 1147+ "are unsupported\n");
1176+ SERROR("Please recompile with " 1148+ SERROR("Please recompile with Squashfs 2.0 support enabled\n");
1177+ "Squashfs 2.0 support enabled\n");
1178+ return 0; 1149+ return 0;
1179+ } 1150+ }
1180+ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > 1151+ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
@@ -1197,16 +1168,17 @@
1197+ char b[BDEVNAME_SIZE]; 1168+ char b[BDEVNAME_SIZE];
1198+ struct inode *root; 1169+ struct inode *root;
1199+ 1170+
1200+ TRACE("Entered squashfs_read_superblock\n"); 1171+ TRACE("Entered squashfs_fill_superblock\n");
1201+ 1172+
1202+ if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info), 1173+ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL);
1203+ GFP_KERNEL))) { 1174+ if (s->s_fs_info == NULL) {
1204+ ERROR("Failed to allocate superblock\n"); 1175+ ERROR("Failed to allocate superblock\n");
1205+ goto failure; 1176+ goto failure;
1206+ } 1177+ }
1207+ memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
1208+ msblk = s->s_fs_info; 1178+ msblk = s->s_fs_info;
1209+ if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) { 1179+
1180+ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize());
1181+ if (msblk->stream.workspace == NULL) {
1210+ ERROR("Failed to allocate zlib workspace\n"); 1182+ ERROR("Failed to allocate zlib workspace\n");
1211+ goto failure; 1183+ goto failure;
1212+ } 1184+ }
@@ -1224,6 +1196,9 @@
1224+ init_waitqueue_head(&msblk->waitq); 1196+ init_waitqueue_head(&msblk->waitq);
1225+ init_waitqueue_head(&msblk->fragment_wait_queue); 1197+ init_waitqueue_head(&msblk->fragment_wait_queue);
1226+ 1198+
1199+ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not
1200+ * beyond filesystem end. As we're using squashfs_read_data to read sblk here,
1201+ * first set sblk->bytes_used to a useful value */
1227+ sblk->bytes_used = sizeof(struct squashfs_super_block); 1202+ sblk->bytes_used = sizeof(struct squashfs_super_block);
1228+ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, 1203+ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
1229+ sizeof(struct squashfs_super_block) | 1204+ sizeof(struct squashfs_super_block) |
@@ -1233,13 +1208,12 @@
1233+ } 1208+ }
1234+ 1209+
1235+ /* Check it is a SQUASHFS superblock */ 1210+ /* Check it is a SQUASHFS superblock */
1236+ msblk->swap = 0;
1237+ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { 1211+ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
1238+ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { 1212+ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
1239+ struct squashfs_super_block ssblk; 1213+ struct squashfs_super_block ssblk;
1240+ 1214+
1241+ WARNING("Mounting a different endian SQUASHFS " 1215+ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n",
1242+ "filesystem on %s\n", bdevname(s->s_bdev, b)); 1216+ bdevname(s->s_bdev, b));
1243+ 1217+
1244+ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); 1218+ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
1245+ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); 1219+ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
@@ -1265,15 +1239,12 @@
1265+ goto failed_mount; 1239+ goto failed_mount;
1266+ 1240+
1267+ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); 1241+ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
1268+ TRACE("Inodes are %scompressed\n", 1242+ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags)
1269+ SQUASHFS_UNCOMPRESSED_INODES 1243+ ? "un" : "");
1270+ (sblk->flags) ? "un" : ""); 1244+ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
1271+ TRACE("Data is %scompressed\n",
1272+ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
1273+ ? "un" : ""); 1245+ ? "un" : "");
1274+ TRACE("Check data is %s present in the filesystem\n", 1246+ TRACE("Check data is %spresent in the filesystem\n",
1275+ SQUASHFS_CHECK_DATA(sblk->flags) ? 1247+ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not ");
1276+ "" : "not");
1277+ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); 1248+ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
1278+ TRACE("Block size %d\n", sblk->block_size); 1249+ TRACE("Block size %d\n", sblk->block_size);
1279+ TRACE("Number of inodes %d\n", sblk->inodes); 1250+ TRACE("Number of inodes %d\n", sblk->inodes);
@@ -1284,34 +1255,27 @@
1284+ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); 1255+ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
1285+ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); 1256+ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
1286+ if (sblk->s_major > 1) 1257+ if (sblk->s_major > 1)
1287+ TRACE("sblk->fragment_table_start %llx\n", 1258+ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start);
1288+ sblk->fragment_table_start);
1289+ TRACE("sblk->uid_start %llx\n", sblk->uid_start); 1259+ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
1290+ 1260+
1261+ s->s_maxbytes = MAX_LFS_FILESIZE;
1291+ s->s_flags |= MS_RDONLY; 1262+ s->s_flags |= MS_RDONLY;
1292+ s->s_op = &squashfs_super_ops; 1263+ s->s_op = &squashfs_super_ops;
1293+ 1264+
1294+ /* Init inode_table block pointer array */ 1265+ if (readahead_metadata(s) == 0)
1295+ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
1296+ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
1297+ ERROR("Failed to allocate block cache\n");
1298+ goto failed_mount; 1266+ goto failed_mount;
1299+ }
1300+
1301+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
1302+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
1303+
1304+ msblk->next_cache = 0;
1305+ 1267+
1306+ /* Allocate read_page block */ 1268+ /* Allocate read_page block */
1307+ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) { 1269+ msblk->read_page = vmalloc(sblk->block_size);
1270+ if (msblk->read_page == NULL) {
1308+ ERROR("Failed to allocate read_page block\n"); 1271+ ERROR("Failed to allocate read_page block\n");
1309+ goto failed_mount; 1272+ goto failed_mount;
1310+ } 1273+ }
1311+ 1274+
1312+ /* Allocate uid and gid tables */ 1275+ /* Allocate uid and gid tables */
1313+ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * 1276+ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
1314+ sizeof(unsigned int), GFP_KERNEL))) { 1277+ sizeof(unsigned int), GFP_KERNEL);
1278+ if (msblk->uid == NULL) {
1315+ ERROR("Failed to allocate uid/gid table\n"); 1279+ ERROR("Failed to allocate uid/gid table\n");
1316+ goto failed_mount; 1280+ goto failed_mount;
1317+ } 1281+ }
@@ -1343,19 +1307,19 @@
1343+ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) 1307+ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
1344+ goto allocate_root; 1308+ goto allocate_root;
1345+ 1309+
1346+ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) * 1310+ msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) *
1347+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { 1311+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL);
1312+ if (msblk->fragment == NULL) {
1348+ ERROR("Failed to allocate fragment block cache\n"); 1313+ ERROR("Failed to allocate fragment block cache\n");
1349+ goto failed_mount; 1314+ goto failed_mount;
1350+ } 1315+ }
1351+ 1316+
1352+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { 1317+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
1353+ msblk->fragment[i].locked = 0;
1354+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; 1318+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
1355+ msblk->fragment[i].data = NULL;
1356+ } 1319+ }
1357+ 1320+
1358+ msblk->next_fragment = 0; 1321+ msblk->next_fragment = 0;
1322+ msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS;
1359+ 1323+
1360+ /* Allocate and read fragment index table */ 1324+ /* Allocate and read fragment index table */
1361+ if (msblk->read_fragment_index_table(s) == 0) 1325+ if (msblk->read_fragment_index_table(s) == 0)
@@ -1377,13 +1341,14 @@
1377+ goto failed_mount; 1341+ goto failed_mount;
1378+ insert_inode_hash(root); 1342+ insert_inode_hash(root);
1379+ 1343+
1380+ if ((s->s_root = d_alloc_root(root)) == NULL) { 1344+ s->s_root = d_alloc_root(root);
1345+ if (s->s_root == NULL) {
1381+ ERROR("Root inode create failed\n"); 1346+ ERROR("Root inode create failed\n");
1382+ iput(root); 1347+ iput(root);
1383+ goto failed_mount; 1348+ goto failed_mount;
1384+ } 1349+ }
1385+ 1350+
1386+ TRACE("Leaving squashfs_read_super\n"); 1351+ TRACE("Leaving squashfs_fill_super\n");
1387+ return 0; 1352+ return 0;
1388+ 1353+
1389+failed_mount: 1354+failed_mount:
@@ -1391,7 +1356,7 @@
1391+ kfree(msblk->fragment_index); 1356+ kfree(msblk->fragment_index);
1392+ kfree(msblk->fragment); 1357+ kfree(msblk->fragment);
1393+ kfree(msblk->uid); 1358+ kfree(msblk->uid);
1394+ kfree(msblk->read_page); 1359+ vfree(msblk->read_page);
1395+ kfree(msblk->block_cache); 1360+ kfree(msblk->block_cache);
1396+ kfree(msblk->fragment_index_2); 1361+ kfree(msblk->fragment_index_2);
1397+ vfree(msblk->stream.workspace); 1362+ vfree(msblk->stream.workspace);
@@ -1426,7 +1391,7 @@
1426+static int squashfs_symlink_readpage(struct file *file, struct page *page) 1391+static int squashfs_symlink_readpage(struct file *file, struct page *page)
1427+{ 1392+{
1428+ struct inode *inode = page->mapping->host; 1393+ struct inode *inode = page->mapping->host;
1429+ int index = page->index << PAGE_CACHE_SHIFT, length, bytes; 1394+ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes;
1430+ long long block = SQUASHFS_I(inode)->start_block; 1395+ long long block = SQUASHFS_I(inode)->start_block;
1431+ int offset = SQUASHFS_I(inode)->offset; 1396+ int offset = SQUASHFS_I(inode)->offset;
1432+ void *pageaddr = kmap(page); 1397+ void *pageaddr = kmap(page);
@@ -1437,11 +1402,10 @@
1437+ SQUASHFS_I(inode)->offset); 1402+ SQUASHFS_I(inode)->offset);
1438+ 1403+
1439+ for (length = 0; length < index; length += bytes) { 1404+ for (length = 0; length < index; length += bytes) {
1440+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, 1405+ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block,
1441+ block, offset, PAGE_CACHE_SIZE, &block, 1406+ offset, PAGE_CACHE_SIZE, &block, &offset);
1442+ &offset))) { 1407+ if (bytes == 0) {
1443+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, 1408+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1444+ offset);
1445+ goto skip_read; 1409+ goto skip_read;
1446+ } 1410+ }
1447+ } 1411+ }
@@ -1452,11 +1416,11 @@
1452+ goto skip_read; 1416+ goto skip_read;
1453+ } 1417+ }
1454+ 1418+
1455+ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : 1419+ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE);
1456+ i_size_read(inode) - length;
1457+ 1420+
1458+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, 1421+ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset,
1459+ offset, bytes, &block, &offset))) 1422+ avail_bytes, &block, &offset);
1423+ if (bytes == 0)
1460+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); 1424+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1461+ 1425+
1462+skip_read: 1426+skip_read:
@@ -1480,10 +1444,10 @@
1480+ 1444+
1481+ TRACE("locate_meta_index: index %d, offset %d\n", index, offset); 1445+ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
1482+ 1446+
1483+ if(msblk->meta_index == NULL) 1447+ if (msblk->meta_index == NULL)
1484+ goto not_allocated; 1448+ goto not_allocated;
1485+ 1449+
1486+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) 1450+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) {
1487+ if (msblk->meta_index[i].inode_number == inode->i_ino && 1451+ if (msblk->meta_index[i].inode_number == inode->i_ino &&
1488+ msblk->meta_index[i].offset >= offset && 1452+ msblk->meta_index[i].offset >= offset &&
1489+ msblk->meta_index[i].offset <= index && 1453+ msblk->meta_index[i].offset <= index &&
@@ -1493,6 +1457,7 @@
1493+ meta = &msblk->meta_index[i]; 1457+ meta = &msblk->meta_index[i];
1494+ offset = meta->offset; 1458+ offset = meta->offset;
1495+ } 1459+ }
1460+ }
1496+ 1461+
1497+ if (meta) 1462+ if (meta)
1498+ meta->locked = 1; 1463+ meta->locked = 1;
@@ -1514,25 +1479,26 @@
1514+ 1479+
1515+ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); 1480+ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
1516+ 1481+
1517+ if(msblk->meta_index == NULL) { 1482+ if (msblk->meta_index == NULL) {
1518+ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) * 1483+ msblk->meta_index = kmalloc(sizeof(struct meta_index) *
1519+ SQUASHFS_META_NUMBER, GFP_KERNEL))) { 1484+ SQUASHFS_META_NUMBER, GFP_KERNEL);
1485+ if (msblk->meta_index == NULL) {
1520+ ERROR("Failed to allocate meta_index\n"); 1486+ ERROR("Failed to allocate meta_index\n");
1521+ goto failed; 1487+ goto failed;
1522+ } 1488+ }
1523+ for(i = 0; i < SQUASHFS_META_NUMBER; i++) { 1489+ for (i = 0; i < SQUASHFS_META_NUMBER; i++) {
1524+ msblk->meta_index[i].inode_number = 0; 1490+ msblk->meta_index[i].inode_number = 0;
1525+ msblk->meta_index[i].locked = 0; 1491+ msblk->meta_index[i].locked = 0;
1526+ } 1492+ }
1527+ msblk->next_meta_index = 0; 1493+ msblk->next_meta_index = 0;
1528+ } 1494+ }
1529+ 1495+
1530+ for(i = SQUASHFS_META_NUMBER; i && 1496+ for (i = SQUASHFS_META_NUMBER; i &&
1531+ msblk->meta_index[msblk->next_meta_index].locked; i --) 1497+ msblk->meta_index[msblk->next_meta_index].locked; i --)
1532+ msblk->next_meta_index = (msblk->next_meta_index + 1) % 1498+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
1533+ SQUASHFS_META_NUMBER; 1499+ SQUASHFS_META_NUMBER;
1534+ 1500+
1535+ if(i == 0) { 1501+ if (i == 0) {
1536+ TRACE("empty_meta_index: failed!\n"); 1502+ TRACE("empty_meta_index: failed!\n");
1537+ goto failed; 1503+ goto failed;
1538+ } 1504+ }
@@ -1565,7 +1531,7 @@
1565+ 1531+
1566+ 1532+
1567+static int read_block_index(struct super_block *s, int blocks, char *block_list, 1533+static int read_block_index(struct super_block *s, int blocks, char *block_list,
1568+ long long *start_block, int *offset) 1534+ long long *start_block, int *offset)
1569+{ 1535+{
1570+ struct squashfs_sb_info *msblk = s->s_fs_info; 1536+ struct squashfs_sb_info *msblk = s->s_fs_info;
1571+ unsigned int *block_listp; 1537+ unsigned int *block_listp;
@@ -1576,19 +1542,18 @@
1576+ 1542+
1577+ if (!squashfs_get_cached_block(s, sblock_list, *start_block, 1543+ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
1578+ *offset, blocks << 2, start_block, offset)) { 1544+ *offset, blocks << 2, start_block, offset)) {
1579+ ERROR("Unable to read block list [%llx:%x]\n", 1545+ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
1580+ *start_block, *offset);
1581+ goto failure; 1546+ goto failure;
1582+ } 1547+ }
1583+ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), 1548+ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
1584+ ((unsigned int *)sblock_list), blocks); 1549+ ((unsigned int *)sblock_list), blocks);
1585+ } else 1550+ } else {
1586+ if (!squashfs_get_cached_block(s, block_list, *start_block, 1551+ if (!squashfs_get_cached_block(s, block_list, *start_block,
1587+ *offset, blocks << 2, start_block, offset)) { 1552+ *offset, blocks << 2, start_block, offset)) {
1588+ ERROR("Unable to read block list [%llx:%x]\n", 1553+ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
1589+ *start_block, *offset);
1590+ goto failure; 1554+ goto failure;
1591+ } 1555+ }
1556+ }
1592+ 1557+
1593+ for (block_listp = (unsigned int *) block_list; blocks; 1558+ for (block_listp = (unsigned int *) block_list; blocks;
1594+ block_listp++, blocks --) 1559+ block_listp++, blocks --)
@@ -1626,25 +1591,26 @@
1626+ 1591+
1627+ index /= SQUASHFS_META_INDEXES * skip; 1592+ index /= SQUASHFS_META_INDEXES * skip;
1628+ 1593+
1629+ while ( offset < index ) { 1594+ while (offset < index) {
1630+ meta = locate_meta_index(inode, index, offset + 1); 1595+ meta = locate_meta_index(inode, index, offset + 1);
1631+ 1596+
1632+ if (meta == NULL) { 1597+ if (meta == NULL) {
1633+ if ((meta = empty_meta_index(inode, offset + 1, 1598+ meta = empty_meta_index(inode, offset + 1, skip);
1634+ skip)) == NULL) 1599+ if (meta == NULL)
1635+ goto all_done; 1600+ goto all_done;
1636+ } else { 1601+ } else {
1637+ if(meta->entries == 0) 1602+ if(meta->entries == 0)
1638+ goto failed; 1603+ goto failed;
1604+ /* XXX */
1639+ offset = index < meta->offset + meta->entries ? index : 1605+ offset = index < meta->offset + meta->entries ? index :
1640+ meta->offset + meta->entries - 1; 1606+ meta->offset + meta->entries - 1;
1607+ /* XXX */
1641+ meta_entry = &meta->meta_entry[offset - meta->offset]; 1608+ meta_entry = &meta->meta_entry[offset - meta->offset];
1642+ cur_index_block = meta_entry->index_block + sblk->inode_table_start; 1609+ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
1643+ cur_offset = meta_entry->offset; 1610+ cur_offset = meta_entry->offset;
1644+ cur_data_block = meta_entry->data_block; 1611+ cur_data_block = meta_entry->data_block;
1645+ TRACE("get_meta_index: offset %d, meta->offset %d, " 1612+ TRACE("get_meta_index: offset %d, meta->offset %d, "
1646+ "meta->entries %d\n", offset, meta->offset, 1613+ "meta->entries %d\n", offset, meta->offset, meta->entries);
1647+ meta->entries);
1648+ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" 1614+ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
1649+ " data_block 0x%llx\n", cur_index_block, 1615+ " data_block 0x%llx\n", cur_index_block,
1650+ cur_offset, cur_data_block); 1616+ cur_offset, cur_data_block);
@@ -1655,11 +1621,9 @@
1655+ int blocks = skip * SQUASHFS_META_INDEXES; 1621+ int blocks = skip * SQUASHFS_META_INDEXES;
1656+ 1622+
1657+ while (blocks) { 1623+ while (blocks) {
1658+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : 1624+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks;
1659+ blocks; 1625+ int res = read_block_index(inode->i_sb, block, block_list,
1660+ int res = read_block_index(inode->i_sb, block, 1626+ &cur_index_block, &cur_offset);
1661+ block_list, &cur_index_block,
1662+ &cur_offset);
1663+ 1627+
1664+ if (res == -1) 1628+ if (res == -1)
1665+ goto failed; 1629+ goto failed;
@@ -1706,15 +1670,14 @@
1706+ block_list); 1670+ block_list);
1707+ 1671+
1708+ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" 1672+ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
1709+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, 1673+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block);
1710+ block);
1711+ 1674+
1712+ if(res == -1) 1675+ if(res == -1)
1713+ goto failure; 1676+ goto failure;
1714+ 1677+
1715+ index -= res; 1678+ index -= res;
1716+ 1679+
1717+ while ( index ) { 1680+ while (index) {
1718+ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; 1681+ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
1719+ int res = read_block_index(inode->i_sb, blocks, block_list, 1682+ int res = read_block_index(inode->i_sb, blocks, block_list,
1720+ &block_ptr, &offset); 1683+ &block_ptr, &offset);
@@ -1724,8 +1687,7 @@
1724+ index -= blocks; 1687+ index -= blocks;
1725+ } 1688+ }
1726+ 1689+
1727+ if (read_block_index(inode->i_sb, 1, block_list, 1690+ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1)
1728+ &block_ptr, &offset) == -1)
1729+ goto failure; 1691+ goto failure;
1730+ *bsize = *((unsigned int *) block_list); 1692+ *bsize = *((unsigned int *) block_list);
1731+ 1693+
@@ -1741,9 +1703,10 @@
1741+ struct inode *inode = page->mapping->host; 1703+ struct inode *inode = page->mapping->host;
1742+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 1704+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1743+ struct squashfs_super_block *sblk = &msblk->sblk; 1705+ struct squashfs_super_block *sblk = &msblk->sblk;
1744+ unsigned char *block_list; 1706+ unsigned char *block_list = NULL;
1745+ long long block; 1707+ long long block;
1746+ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0; 1708+ unsigned int bsize, i;
1709+ int bytes;
1747+ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); 1710+ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
1748+ void *pageaddr; 1711+ void *pageaddr;
1749+ struct squashfs_fragment_cache *fragment = NULL; 1712+ struct squashfs_fragment_cache *fragment = NULL;
@@ -1752,64 +1715,65 @@
1752+ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; 1715+ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
1753+ int start_index = page->index & ~mask; 1716+ int start_index = page->index & ~mask;
1754+ int end_index = start_index | mask; 1717+ int end_index = start_index | mask;
1718+ int file_end = i_size_read(inode) >> sblk->block_log;
1719+ int sparse = 0;
1755+ 1720+
1756+ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", 1721+ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
1757+ page->index, 1722+ page->index, SQUASHFS_I(inode)->start_block);
1758+ SQUASHFS_I(inode)->start_block);
1759+
1760+ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
1761+ ERROR("Failed to allocate block_list\n");
1762+ goto skip_read;
1763+ }
1764+ 1723+
1765+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> 1724+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1766+ PAGE_CACHE_SHIFT)) 1725+ PAGE_CACHE_SHIFT))
1767+ goto skip_read; 1726+ goto out;
1768+ 1727+
1769+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK 1728+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1770+ || index < (i_size_read(inode) >> 1729+ || index < file_end) {
1771+ sblk->block_log)) { 1730+ block_list = kmalloc(SIZE, GFP_KERNEL);
1772+ if ((block = (msblk->read_blocklist)(inode, index, 1, 1731+ if (block_list == NULL) {
1773+ block_list, NULL, &bsize)) == 0) 1732+ ERROR("Failed to allocate block_list\n");
1774+ goto skip_read; 1733+ goto error_out;
1734+ }
1735+
1736+ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize);
1737+ if (block == 0)
1738+ goto error_out;
1775+ 1739+
1776+ mutex_lock(&msblk->read_page_mutex); 1740+ if (bsize == 0) { /* hole */
1741+ bytes = index == file_end ?
1742+ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size;
1743+ sparse = 1;
1744+ } else {
1745+ mutex_lock(&msblk->read_page_mutex);
1777+ 1746+
1778+ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, 1747+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
1779+ block, bsize, NULL, sblk->block_size))) { 1748+ bsize, NULL, sblk->block_size);
1780+ ERROR("Unable to read page, block %llx, size %x\n", block, 1749+
1781+ bsize); 1750+ if (bytes == 0) {
1782+ mutex_unlock(&msblk->read_page_mutex); 1751+ ERROR("Unable to read page, block %llx, size %x\n", block, bsize);
1783+ goto skip_read; 1752+ mutex_unlock(&msblk->read_page_mutex);
1753+ goto error_out;
1754+ }
1784+ } 1755+ }
1785+ } else { 1756+ } else {
1786+ if ((fragment = get_cached_fragment(inode->i_sb, 1757+ fragment = get_cached_fragment(inode->i_sb,
1787+ SQUASHFS_I(inode)-> 1758+ SQUASHFS_I(inode)-> u.s1.fragment_start_block,
1788+ u.s1.fragment_start_block, 1759+ SQUASHFS_I(inode)->u.s1.fragment_size);
1789+ SQUASHFS_I(inode)->u.s1.fragment_size)) 1760+
1790+ == NULL) { 1761+ if (fragment == NULL) {
1791+ ERROR("Unable to read page, block %llx, size %x\n", 1762+ ERROR("Unable to read page, block %llx, size %x\n",
1792+ SQUASHFS_I(inode)-> 1763+ SQUASHFS_I(inode)->u.s1.fragment_start_block,
1793+ u.s1.fragment_start_block, 1764+ (int) SQUASHFS_I(inode)->u.s1.fragment_size);
1794+ (int) SQUASHFS_I(inode)-> 1765+ goto error_out;
1795+ u.s1.fragment_size);
1796+ goto skip_read;
1797+ } 1766+ }
1798+ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset + 1767+ bytes = i_size_read(inode) & (sblk->block_size - 1);
1799+ (i_size_read(inode) & (sblk->block_size 1768+ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset;
1800+ - 1));
1801+ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
1802+ data_ptr = fragment->data;
1803+ } 1769+ }
1804+ 1770+
1805+ for (i = start_index; i <= end_index && byte_offset < bytes; 1771+ for (i = start_index; i <= end_index && bytes > 0; i++,
1806+ i++, byte_offset += PAGE_CACHE_SIZE) { 1772+ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) {
1807+ struct page *push_page; 1773+ struct page *push_page;
1808+ int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ? 1774+ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE);
1809+ PAGE_CACHE_SIZE : bytes - byte_offset;
1810+ 1775+
1811+ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", 1776+ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
1812+ bytes, i, byte_offset, avail);
1813+ 1777+
1814+ push_page = (i == page->index) ? page : 1778+ push_page = (i == page->index) ? page :
1815+ grab_cache_page_nowait(page->mapping, i); 1779+ grab_cache_page_nowait(page->mapping, i);
@@ -1821,7 +1785,7 @@
1821+ goto skip_page; 1785+ goto skip_page;
1822+ 1786+
1823+ pageaddr = kmap_atomic(push_page, KM_USER0); 1787+ pageaddr = kmap_atomic(push_page, KM_USER0);
1824+ memcpy(pageaddr, data_ptr + byte_offset, avail); 1788+ memcpy(pageaddr, data_ptr, avail);
1825+ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); 1789+ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
1826+ kunmap_atomic(pageaddr, KM_USER0); 1790+ kunmap_atomic(pageaddr, KM_USER0);
1827+ flush_dcache_page(push_page); 1791+ flush_dcache_page(push_page);
@@ -1833,98 +1797,24 @@
1833+ } 1797+ }
1834+ 1798+
1835+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK 1799+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1836+ || index < (i_size_read(inode) >> 1800+ || index < file_end) {
1837+ sblk->block_log)) 1801+ if (!sparse)
1838+ mutex_unlock(&msblk->read_page_mutex); 1802+ mutex_unlock(&msblk->read_page_mutex);
1839+ else 1803+ kfree(block_list);
1804+ } else
1840+ release_cached_fragment(msblk, fragment); 1805+ release_cached_fragment(msblk, fragment);
1841+ 1806+
1842+ kfree(block_list);
1843+ return 0;
1844+
1845+skip_read:
1846+ pageaddr = kmap_atomic(page, KM_USER0);
1847+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1848+ kunmap_atomic(pageaddr, KM_USER0);
1849+ flush_dcache_page(page);
1850+ SetPageUptodate(page);
1851+ unlock_page(page);
1852+
1853+ kfree(block_list);
1854+ return 0; 1807+ return 0;
1855+}
1856+
1857+ 1808+
1858+static int squashfs_readpage4K(struct file *file, struct page *page) 1809+error_out:
1859+{ 1810+ SetPageError(page);
1860+ struct inode *inode = page->mapping->host; 1811+out:
1861+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1862+ struct squashfs_super_block *sblk = &msblk->sblk;
1863+ unsigned char *block_list;
1864+ long long block;
1865+ unsigned int bsize, bytes = 0;
1866+ void *pageaddr;
1867+
1868+ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
1869+ page->index,
1870+ SQUASHFS_I(inode)->start_block);
1871+
1872+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1873+ PAGE_CACHE_SHIFT)) {
1874+ block_list = NULL;
1875+ goto skip_read;
1876+ }
1877+
1878+ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
1879+ ERROR("Failed to allocate block_list\n");
1880+ goto skip_read;
1881+ }
1882+
1883+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1884+ || page->index < (i_size_read(inode) >>
1885+ sblk->block_log)) {
1886+ block = (msblk->read_blocklist)(inode, page->index, 1,
1887+ block_list, NULL, &bsize);
1888+ if(block == 0)
1889+ goto skip_read;
1890+
1891+ mutex_lock(&msblk->read_page_mutex);
1892+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
1893+ bsize, NULL, sblk->block_size);
1894+ if (bytes) {
1895+ pageaddr = kmap_atomic(page, KM_USER0);
1896+ memcpy(pageaddr, msblk->read_page, bytes);
1897+ kunmap_atomic(pageaddr, KM_USER0);
1898+ } else
1899+ ERROR("Unable to read page, block %llx, size %x\n",
1900+ block, bsize);
1901+ mutex_unlock(&msblk->read_page_mutex);
1902+ } else {
1903+ struct squashfs_fragment_cache *fragment =
1904+ get_cached_fragment(inode->i_sb,
1905+ SQUASHFS_I(inode)->
1906+ u.s1.fragment_start_block,
1907+ SQUASHFS_I(inode)-> u.s1.fragment_size);
1908+ if (fragment) {
1909+ bytes = i_size_read(inode) & (sblk->block_size - 1);
1910+ pageaddr = kmap_atomic(page, KM_USER0);
1911+ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
1912+ u.s1.fragment_offset, bytes);
1913+ kunmap_atomic(pageaddr, KM_USER0);
1914+ release_cached_fragment(msblk, fragment);
1915+ } else
1916+ ERROR("Unable to read page, block %llx, size %x\n",
1917+ SQUASHFS_I(inode)->
1918+ u.s1.fragment_start_block, (int)
1919+ SQUASHFS_I(inode)-> u.s1.fragment_size);
1920+ }
1921+
1922+skip_read:
1923+ pageaddr = kmap_atomic(page, KM_USER0); 1812+ pageaddr = kmap_atomic(page, KM_USER0);
1924+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); 1813+ memset(pageaddr, 0, PAGE_CACHE_SIZE);
1925+ kunmap_atomic(pageaddr, KM_USER0); 1814+ kunmap_atomic(pageaddr, KM_USER0);
1926+ flush_dcache_page(page); 1815+ flush_dcache_page(page);
1927+ SetPageUptodate(page); 1816+ if (!PageError(page))
1817+ SetPageUptodate(page);
1928+ unlock_page(page); 1818+ unlock_page(page);
1929+ 1819+
1930+ kfree(block_list); 1820+ kfree(block_list);
@@ -1932,10 +1822,9 @@
1932+} 1822+}
1933+ 1823+
1934+ 1824+
1935+static int get_dir_index_using_offset(struct super_block *s, long long 1825+static int get_dir_index_using_offset(struct super_block *s,
1936+ *next_block, unsigned int *next_offset, 1826+ long long *next_block, unsigned int *next_offset,
1937+ long long index_start, 1827+ long long index_start, unsigned int index_offset, int i_count,
1938+ unsigned int index_offset, int i_count,
1939+ long long f_pos) 1828+ long long f_pos)
1940+{ 1829+{
1941+ struct squashfs_sb_info *msblk = s->s_fs_info; 1830+ struct squashfs_sb_info *msblk = s->s_fs_info;
@@ -1953,23 +1842,18 @@
1953+ for (i = 0; i < i_count; i++) { 1842+ for (i = 0; i < i_count; i++) {
1954+ if (msblk->swap) { 1843+ if (msblk->swap) {
1955+ struct squashfs_dir_index sindex; 1844+ struct squashfs_dir_index sindex;
1956+ squashfs_get_cached_block(s, (char *) &sindex, 1845+ squashfs_get_cached_block(s, &sindex, index_start, index_offset,
1957+ index_start, index_offset, 1846+ sizeof(sindex), &index_start, &index_offset);
1958+ sizeof(sindex), &index_start,
1959+ &index_offset);
1960+ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); 1847+ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
1961+ } else 1848+ } else
1962+ squashfs_get_cached_block(s, (char *) &index, 1849+ squashfs_get_cached_block(s, &index, index_start, index_offset,
1963+ index_start, index_offset, 1850+ sizeof(index), &index_start, &index_offset);
1964+ sizeof(index), &index_start,
1965+ &index_offset);
1966+ 1851+
1967+ if (index.index > f_pos) 1852+ if (index.index > f_pos)
1968+ break; 1853+ break;
1969+ 1854+
1970+ squashfs_get_cached_block(s, NULL, index_start, index_offset, 1855+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
1971+ index.size + 1, &index_start, 1856+ index.size + 1, &index_start, &index_offset);
1972+ &index_offset);
1973+ 1857+
1974+ length = index.index; 1858+ length = index.index;
1975+ *next_block = index.start_block + sblk->directory_table_start; 1859+ *next_block = index.start_block + sblk->directory_table_start;
@@ -1982,10 +1866,9 @@
1982+} 1866+}
1983+ 1867+
1984+ 1868+
1985+static int get_dir_index_using_name(struct super_block *s, long long 1869+static int get_dir_index_using_name(struct super_block *s,
1986+ *next_block, unsigned int *next_offset, 1870+ long long *next_block, unsigned int *next_offset,
1987+ long long index_start, 1871+ long long index_start, unsigned int index_offset, int i_count,
1988+ unsigned int index_offset, int i_count,
1989+ const char *name, int size) 1872+ const char *name, int size)
1990+{ 1873+{
1991+ struct squashfs_sb_info *msblk = s->s_fs_info; 1874+ struct squashfs_sb_info *msblk = s->s_fs_info;
@@ -1996,8 +1879,9 @@
1996+ 1879+
1997+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); 1880+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
1998+ 1881+
1999+ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + 1882+ str = kmalloc(sizeof(struct squashfs_dir_index) +
2000+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { 1883+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL);
1884+ if (str == NULL) {
2001+ ERROR("Failed to allocate squashfs_dir_index\n"); 1885+ ERROR("Failed to allocate squashfs_dir_index\n");
2002+ goto failure; 1886+ goto failure;
2003+ } 1887+ }
@@ -2009,20 +1893,15 @@
2009+ for (i = 0; i < i_count; i++) { 1893+ for (i = 0; i < i_count; i++) {
2010+ if (msblk->swap) { 1894+ if (msblk->swap) {
2011+ struct squashfs_dir_index sindex; 1895+ struct squashfs_dir_index sindex;
2012+ squashfs_get_cached_block(s, (char *) &sindex, 1896+ squashfs_get_cached_block(s, &sindex, index_start, index_offset,
2013+ index_start, index_offset, 1897+ sizeof(sindex), &index_start, &index_offset);
2014+ sizeof(sindex), &index_start,
2015+ &index_offset);
2016+ SQUASHFS_SWAP_DIR_INDEX(index, &sindex); 1898+ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
2017+ } else 1899+ } else
2018+ squashfs_get_cached_block(s, (char *) index, 1900+ squashfs_get_cached_block(s, index, index_start, index_offset,
2019+ index_start, index_offset, 1901+ sizeof(struct squashfs_dir_index), &index_start, &index_offset);
2020+ sizeof(struct squashfs_dir_index),
2021+ &index_start, &index_offset);
2022+ 1902+
2023+ squashfs_get_cached_block(s, index->name, index_start, 1903+ squashfs_get_cached_block(s, index->name, index_start, index_offset,
2024+ index_offset, index->size + 1, 1904+ index->size + 1, &index_start, &index_offset);
2025+ &index_start, &index_offset);
2026+ 1905+
2027+ index->name[index->size + 1] = '\0'; 1906+ index->name[index->size + 1] = '\0';
2028+ 1907+
@@ -2035,6 +1914,7 @@
2035+ 1914+
2036+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; 1915+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2037+ kfree(str); 1916+ kfree(str);
1917+
2038+failure: 1918+failure:
2039+ return length + 3; 1919+ return length + 3;
2040+} 1920+}
@@ -2047,15 +1927,15 @@
2047+ struct squashfs_super_block *sblk = &msblk->sblk; 1927+ struct squashfs_super_block *sblk = &msblk->sblk;
2048+ long long next_block = SQUASHFS_I(i)->start_block + 1928+ long long next_block = SQUASHFS_I(i)->start_block +
2049+ sblk->directory_table_start; 1929+ sblk->directory_table_start;
2050+ int next_offset = SQUASHFS_I(i)->offset, length = 0, 1930+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
2051+ dir_count;
2052+ struct squashfs_dir_header dirh; 1931+ struct squashfs_dir_header dirh;
2053+ struct squashfs_dir_entry *dire; 1932+ struct squashfs_dir_entry *dire;
2054+ 1933+
2055+ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); 1934+ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
2056+ 1935+
2057+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + 1936+ dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2058+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { 1937+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
1938+ if (dire == NULL) {
2059+ ERROR("Failed to allocate squashfs_dir_entry\n"); 1939+ ERROR("Failed to allocate squashfs_dir_entry\n");
2060+ goto finish; 1940+ goto finish;
2061+ } 1941+ }
@@ -2075,14 +1955,12 @@
2075+ } 1955+ }
2076+ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", 1956+ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
2077+ (unsigned int) dirent, name, size, (int) 1957+ (unsigned int) dirent, name, size, (int)
2078+ file->f_pos, i_ino, 1958+ file->f_pos, i_ino, squashfs_filetype_table[1]);
2079+ squashfs_filetype_table[1]);
2080+ 1959+
2081+ if (filldir(dirent, name, size, 1960+ if (filldir(dirent, name, size, file->f_pos, i_ino,
2082+ file->f_pos, i_ino,
2083+ squashfs_filetype_table[1]) < 0) { 1961+ squashfs_filetype_table[1]) < 0) {
2084+ TRACE("Filldir returned less than 0\n"); 1962+ TRACE("Filldir returned less than 0\n");
2085+ goto finish; 1963+ goto finish;
2086+ } 1964+ }
2087+ file->f_pos += size; 1965+ file->f_pos += size;
2088+ } 1966+ }
@@ -2090,25 +1968,22 @@
2090+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, 1968+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
2091+ SQUASHFS_I(i)->u.s2.directory_index_start, 1969+ SQUASHFS_I(i)->u.s2.directory_index_start,
2092+ SQUASHFS_I(i)->u.s2.directory_index_offset, 1970+ SQUASHFS_I(i)->u.s2.directory_index_offset,
2093+ SQUASHFS_I(i)->u.s2.directory_index_count, 1971+ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos);
2094+ file->f_pos);
2095+ 1972+
2096+ while (length < i_size_read(i)) { 1973+ while (length < i_size_read(i)) {
2097+ /* read directory header */ 1974+ /* read directory header */
2098+ if (msblk->swap) { 1975+ if (msblk->swap) {
2099+ struct squashfs_dir_header sdirh; 1976+ struct squashfs_dir_header sdirh;
2100+ 1977+
2101+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, 1978+ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
2102+ next_block, next_offset, sizeof(sdirh), 1979+ next_offset, sizeof(sdirh), &next_block, &next_offset))
2103+ &next_block, &next_offset))
2104+ goto failed_read; 1980+ goto failed_read;
2105+ 1981+
2106+ length += sizeof(sdirh); 1982+ length += sizeof(sdirh);
2107+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); 1983+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
2108+ } else { 1984+ } else {
2109+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, 1985+ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
2110+ next_block, next_offset, sizeof(dirh), 1986+ next_offset, sizeof(dirh), &next_block, &next_offset))
2111+ &next_block, &next_offset))
2112+ goto failed_read; 1987+ goto failed_read;
2113+ 1988+
2114+ length += sizeof(dirh); 1989+ length += sizeof(dirh);
@@ -2118,28 +1993,22 @@
2118+ while (dir_count--) { 1993+ while (dir_count--) {
2119+ if (msblk->swap) { 1994+ if (msblk->swap) {
2120+ struct squashfs_dir_entry sdire; 1995+ struct squashfs_dir_entry sdire;
2121+ if (!squashfs_get_cached_block(i->i_sb, (char *) 1996+ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
2122+ &sdire, next_block, next_offset, 1997+ next_offset, sizeof(sdire), &next_block, &next_offset))
2123+ sizeof(sdire), &next_block,
2124+ &next_offset))
2125+ goto failed_read; 1998+ goto failed_read;
2126+ 1999+
2127+ length += sizeof(sdire); 2000+ length += sizeof(sdire);
2128+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); 2001+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2129+ } else { 2002+ } else {
2130+ if (!squashfs_get_cached_block(i->i_sb, (char *) 2003+ if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
2131+ dire, next_block, next_offset, 2004+ next_offset, sizeof(*dire), &next_block, &next_offset))
2132+ sizeof(*dire), &next_block,
2133+ &next_offset))
2134+ goto failed_read; 2005+ goto failed_read;
2135+ 2006+
2136+ length += sizeof(*dire); 2007+ length += sizeof(*dire);
2137+ } 2008+ }
2138+ 2009+
2139+ if (!squashfs_get_cached_block(i->i_sb, dire->name, 2010+ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
2140+ next_block, next_offset, 2011+ next_offset, dire->size + 1, &next_block, &next_offset))
2141+ dire->size + 1, &next_block,
2142+ &next_offset))
2143+ goto failed_read; 2012+ goto failed_read;
2144+ 2013+
2145+ length += dire->size + 1; 2014+ length += dire->size + 1;
@@ -2150,17 +2019,14 @@
2150+ dire->name[dire->size + 1] = '\0'; 2019+ dire->name[dire->size + 1] = '\0';
2151+ 2020+
2152+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", 2021+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
2153+ (unsigned int) dirent, dire->name, 2022+ (unsigned int) dirent, dire->name, dire->size + 1,
2154+ dire->size + 1, (int) file->f_pos, 2023+ (int) file->f_pos, dirh.start_block, dire->offset,
2155+ dirh.start_block, dire->offset,
2156+ dirh.inode_number + dire->inode_number, 2024+ dirh.inode_number + dire->inode_number,
2157+ squashfs_filetype_table[dire->type]); 2025+ squashfs_filetype_table[dire->type]);
2158+ 2026+
2159+ if (filldir(dirent, dire->name, dire->size + 1, 2027+ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos,
2160+ file->f_pos,
2161+ dirh.inode_number + dire->inode_number, 2028+ dirh.inode_number + dire->inode_number,
2162+ squashfs_filetype_table[dire->type]) 2029+ squashfs_filetype_table[dire->type]) < 0) {
2163+ < 0) {
2164+ TRACE("Filldir returned less than 0\n"); 2030+ TRACE("Filldir returned less than 0\n");
2165+ goto finish; 2031+ goto finish;
2166+ } 2032+ }
@@ -2190,15 +2056,15 @@
2190+ struct squashfs_super_block *sblk = &msblk->sblk; 2056+ struct squashfs_super_block *sblk = &msblk->sblk;
2191+ long long next_block = SQUASHFS_I(i)->start_block + 2057+ long long next_block = SQUASHFS_I(i)->start_block +
2192+ sblk->directory_table_start; 2058+ sblk->directory_table_start;
2193+ int next_offset = SQUASHFS_I(i)->offset, length = 0, 2059+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
2194+ dir_count;
2195+ struct squashfs_dir_header dirh; 2060+ struct squashfs_dir_header dirh;
2196+ struct squashfs_dir_entry *dire; 2061+ struct squashfs_dir_entry *dire;
2197+ 2062+
2198+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); 2063+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
2199+ 2064+
2200+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + 2065+ dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2201+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { 2066+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
2067+ if (dire == NULL) {
2202+ ERROR("Failed to allocate squashfs_dir_entry\n"); 2068+ ERROR("Failed to allocate squashfs_dir_entry\n");
2203+ goto exit_lookup; 2069+ goto exit_lookup;
2204+ } 2070+ }
@@ -2209,24 +2075,21 @@
2209+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, 2075+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
2210+ SQUASHFS_I(i)->u.s2.directory_index_start, 2076+ SQUASHFS_I(i)->u.s2.directory_index_start,
2211+ SQUASHFS_I(i)->u.s2.directory_index_offset, 2077+ SQUASHFS_I(i)->u.s2.directory_index_offset,
2212+ SQUASHFS_I(i)->u.s2.directory_index_count, name, 2078+ SQUASHFS_I(i)->u.s2.directory_index_count, name, len);
2213+ len);
2214+ 2079+
2215+ while (length < i_size_read(i)) { 2080+ while (length < i_size_read(i)) {
2216+ /* read directory header */ 2081+ /* read directory header */
2217+ if (msblk->swap) { 2082+ if (msblk->swap) {
2218+ struct squashfs_dir_header sdirh; 2083+ struct squashfs_dir_header sdirh;
2219+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, 2084+ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
2220+ next_block, next_offset, sizeof(sdirh), 2085+ next_offset, sizeof(sdirh), &next_block, &next_offset))
2221+ &next_block, &next_offset))
2222+ goto failed_read; 2086+ goto failed_read;
2223+ 2087+
2224+ length += sizeof(sdirh); 2088+ length += sizeof(sdirh);
2225+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); 2089+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
2226+ } else { 2090+ } else {
2227+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, 2091+ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
2228+ next_block, next_offset, sizeof(dirh), 2092+ next_offset, sizeof(dirh), &next_block, &next_offset))
2229+ &next_block, &next_offset))
2230+ goto failed_read; 2093+ goto failed_read;
2231+ 2094+
2232+ length += sizeof(dirh); 2095+ length += sizeof(dirh);
@@ -2236,27 +2099,22 @@
2236+ while (dir_count--) { 2099+ while (dir_count--) {
2237+ if (msblk->swap) { 2100+ if (msblk->swap) {
2238+ struct squashfs_dir_entry sdire; 2101+ struct squashfs_dir_entry sdire;
2239+ if (!squashfs_get_cached_block(i->i_sb, (char *) 2102+ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
2240+ &sdire, next_block,next_offset, 2103+ next_offset, sizeof(sdire), &next_block, &next_offset))
2241+ sizeof(sdire), &next_block,
2242+ &next_offset))
2243+ goto failed_read; 2104+ goto failed_read;
2244+ 2105+
2245+ length += sizeof(sdire); 2106+ length += sizeof(sdire);
2246+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); 2107+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2247+ } else { 2108+ } else {
2248+ if (!squashfs_get_cached_block(i->i_sb, (char *) 2109+ if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
2249+ dire, next_block,next_offset, 2110+ next_offset, sizeof(*dire), &next_block, &next_offset))
2250+ sizeof(*dire), &next_block,
2251+ &next_offset))
2252+ goto failed_read; 2111+ goto failed_read;
2253+ 2112+
2254+ length += sizeof(*dire); 2113+ length += sizeof(*dire);
2255+ } 2114+ }
2256+ 2115+
2257+ if (!squashfs_get_cached_block(i->i_sb, dire->name, 2116+ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
2258+ next_block, next_offset, dire->size + 1, 2117+ next_offset, dire->size + 1, &next_block, &next_offset))
2259+ &next_block, &next_offset))
2260+ goto failed_read; 2118+ goto failed_read;
2261+ 2119+
2262+ length += dire->size + 1; 2120+ length += dire->size + 1;
@@ -2268,9 +2126,8 @@
2268+ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, 2126+ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
2269+ dire->offset); 2127+ dire->offset);
2270+ 2128+
2271+ TRACE("calling squashfs_iget for directory " 2129+ TRACE("calling squashfs_iget for directory entry %s, inode"
2272+ "entry %s, inode %x:%x, %d\n", name, 2130+ " %x:%x, %d\n", name, dirh.start_block, dire->offset,
2273+ dirh.start_block, dire->offset,
2274+ dirh.inode_number + dire->inode_number); 2131+ dirh.inode_number + dire->inode_number);
2275+ 2132+
2276+ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); 2133+ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
@@ -2308,16 +2165,15 @@
2308+ if (s->s_fs_info) { 2165+ if (s->s_fs_info) {
2309+ struct squashfs_sb_info *sbi = s->s_fs_info; 2166+ struct squashfs_sb_info *sbi = s->s_fs_info;
2310+ if (sbi->block_cache) 2167+ if (sbi->block_cache)
2311+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 2168+ for (i = 0; i < squashfs_cached_blks; i++)
2312+ if (sbi->block_cache[i].block != 2169+ if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK)
2313+ SQUASHFS_INVALID_BLK) 2170+ vfree(sbi->block_cache[i].data);
2314+ kfree(sbi->block_cache[i].data);
2315+ if (sbi->fragment) 2171+ if (sbi->fragment)
2316+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) 2172+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
2317+ SQUASHFS_FREE(sbi->fragment[i].data); 2173+ vfree(sbi->fragment[i].data);
2318+ kfree(sbi->fragment); 2174+ kfree(sbi->fragment);
2319+ kfree(sbi->block_cache); 2175+ kfree(sbi->block_cache);
2320+ kfree(sbi->read_page); 2176+ vfree(sbi->read_page);
2321+ kfree(sbi->uid); 2177+ kfree(sbi->uid);
2322+ kfree(sbi->fragment_index); 2178+ kfree(sbi->fragment_index);
2323+ kfree(sbi->fragment_index_2); 2179+ kfree(sbi->fragment_index_2);
@@ -2330,8 +2186,7 @@
2330+ 2186+
2331+ 2187+
2332+static int squashfs_get_sb(struct file_system_type *fs_type, int flags, 2188+static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
2333+ const char *dev_name, void *data, 2189+ const char *dev_name, void *data, struct vfsmount *mnt)
2334+ struct vfsmount *mnt)
2335+{ 2190+{
2336+ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, 2191+ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
2337+ mnt); 2192+ mnt);
@@ -2344,10 +2199,11 @@
2344+ if (err) 2199+ if (err)
2345+ goto out; 2200+ goto out;
2346+ 2201+
2347+ printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) " 2202+ printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) "
2348+ "Phillip Lougher\n"); 2203+ "Phillip Lougher\n");
2349+ 2204+
2350+ if ((err = register_filesystem(&squashfs_fs_type))) 2205+ err = register_filesystem(&squashfs_fs_type);
2206+ if (err)
2351+ destroy_inodecache(); 2207+ destroy_inodecache();
2352+ 2208+
2353+out: 2209+out:
@@ -2369,9 +2225,7 @@
2369+{ 2225+{
2370+ struct squashfs_inode_info *ei; 2226+ struct squashfs_inode_info *ei;
2371+ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); 2227+ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
2372+ if (!ei) 2228+ return ei ? &ei->vfs_inode : NULL;
2373+ return NULL;
2374+ return &ei->vfs_inode;
2375+} 2229+}
2376+ 2230+
2377+ 2231+
@@ -2381,22 +2235,19 @@
2381+} 2235+}
2382+ 2236+
2383+ 2237+
2384+static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) 2238+static void init_once(struct kmem_cache *cachep, void *foo)
2385+{ 2239+{
2386+ struct squashfs_inode_info *ei = foo; 2240+ struct squashfs_inode_info *ei = foo;
2387+ 2241+
2388+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 2242+ inode_init_once(&ei->vfs_inode);
2389+ SLAB_CTOR_CONSTRUCTOR)
2390+ inode_init_once(&ei->vfs_inode);
2391+} 2243+}
2392+ 2244+
2393+ 2245+
2394+static int __init init_inodecache(void) 2246+static int __init init_inodecache(void)
2395+{ 2247+{
2396+ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", 2248+ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
2397+ sizeof(struct squashfs_inode_info), 2249+ sizeof(struct squashfs_inode_info), 0,
2398+ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, 2250+ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
2399+ init_once, NULL);
2400+ if (squashfs_inode_cachep == NULL) 2251+ if (squashfs_inode_cachep == NULL)
2401+ return -ENOMEM; 2252+ return -ENOMEM;
2402+ return 0; 2253+ return 0;
@@ -2411,11 +2262,12 @@
2411+ 2262+
2412+module_init(init_squashfs_fs); 2263+module_init(init_squashfs_fs);
2413+module_exit(exit_squashfs_fs); 2264+module_exit(exit_squashfs_fs);
2414+MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem"); 2265+MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem");
2415+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>"); 2266+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
2416+MODULE_LICENSE("GPL"); 2267+MODULE_LICENSE("GPL");
2417--- /dev/null 2268diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/Makefile linux-2.6.24-squashfs3.3/fs/squashfs/Makefile
2418+++ linux-2.6.24-rc1/fs/squashfs/Makefile 2269--- linux-2.6.24/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100
2270+++ linux-2.6.24-squashfs3.3/fs/squashfs/Makefile 2005-11-20 14:31:00.000000000 +0000
2419@@ -0,0 +1,7 @@ 2271@@ -0,0 +1,7 @@
2420+# 2272+#
2421+# Makefile for the linux squashfs routines. 2273+# Makefile for the linux squashfs routines.
@@ -2424,14 +2276,15 @@
2424+obj-$(CONFIG_SQUASHFS) += squashfs.o 2276+obj-$(CONFIG_SQUASHFS) += squashfs.o
2425+squashfs-y += inode.o 2277+squashfs-y += inode.o
2426+squashfs-y += squashfs2_0.o 2278+squashfs-y += squashfs2_0.o
2427--- /dev/null 2279diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/squashfs2_0.c linux-2.6.24-squashfs3.3/fs/squashfs/squashfs2_0.c
2428+++ linux-2.6.24-rc1/fs/squashfs/squashfs2_0.c 2280--- linux-2.6.24/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100
2429@@ -0,0 +1,742 @@ 2281+++ linux-2.6.24-squashfs3.3/fs/squashfs/squashfs2_0.c 2007-10-25 00:43:59.000000000 +0100
2282@@ -0,0 +1,740 @@
2430+/* 2283+/*
2431+ * Squashfs - a compressed read only filesystem for Linux 2284+ * Squashfs - a compressed read only filesystem for Linux
2432+ * 2285+ *
2433+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 2286+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
2434+ * Phillip Lougher <phillip@lougher.org.uk> 2287+ * Phillip Lougher <phillip@lougher.demon.co.uk>
2435+ * 2288+ *
2436+ * This program is free software; you can redistribute it and/or 2289+ * This program is free software; you can redistribute it and/or
2437+ * modify it under the terms of the GNU General Public License 2290+ * modify it under the terms of the GNU General Public License
@@ -2577,14 +2430,15 @@
2577+ unsigned int block = SQUASHFS_INODE_BLK(inode) + 2430+ unsigned int block = SQUASHFS_INODE_BLK(inode) +
2578+ sblk->inode_table_start; 2431+ sblk->inode_table_start;
2579+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); 2432+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
2580+ unsigned int ino = i->i_ino; 2433+ unsigned int ino = SQUASHFS_MK_VFS_INODE(block -
2434+ sblk->inode_table_start, offset);
2581+ long long next_block; 2435+ long long next_block;
2582+ unsigned int next_offset; 2436+ unsigned int next_offset;
2583+ union squashfs_inode_header_2 id, sid; 2437+ union squashfs_inode_header_2 id, sid;
2584+ struct squashfs_base_inode_header_2 *inodeb = &id.base, 2438+ struct squashfs_base_inode_header_2 *inodeb = &id.base,
2585+ *sinodeb = &sid.base; 2439+ *sinodeb = &sid.base;
2586+ 2440+
2587+ TRACE("Entered squashfs_iget\n"); 2441+ TRACE("Entered squashfs_read_inode_2\n");
2588+ 2442+
2589+ if (msblk->swap) { 2443+ if (msblk->swap) {
2590+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, 2444+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
@@ -2641,10 +2495,7 @@
2641+ SQUASHFS_I(i)->start_block = inodep->start_block; 2495+ SQUASHFS_I(i)->start_block = inodep->start_block;
2642+ SQUASHFS_I(i)->u.s1.block_list_start = next_block; 2496+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
2643+ SQUASHFS_I(i)->offset = next_offset; 2497+ SQUASHFS_I(i)->offset = next_offset;
2644+ if (sblk->block_size > 4096) 2498+ i->i_data.a_ops = &squashfs_aops;
2645+ i->i_data.a_ops = &squashfs_aops;
2646+ else
2647+ i->i_data.a_ops = &squashfs_aops_4K;
2648+ 2499+
2649+ TRACE("File inode %x:%x, start_block %x, " 2500+ TRACE("File inode %x:%x, start_block %x, "
2650+ "block_list_start %llx, offset %x\n", 2501+ "block_list_start %llx, offset %x\n",
@@ -3169,14 +3020,15 @@
3169+ 3020+
3170+ return 1; 3021+ return 1;
3171+} 3022+}
3172--- /dev/null 3023diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/squashfs.h linux-2.6.24-squashfs3.3/fs/squashfs/squashfs.h
3173+++ linux-2.6.24-rc1/fs/squashfs/squashfs.h 3024--- linux-2.6.24/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100
3174@@ -0,0 +1,87 @@ 3025+++ linux-2.6.24-squashfs3.3/fs/squashfs/squashfs.h 2007-08-19 04:23:16.000000000 +0100
3026@@ -0,0 +1,86 @@
3175+/* 3027+/*
3176+ * Squashfs - a compressed read only filesystem for Linux 3028+ * Squashfs - a compressed read only filesystem for Linux
3177+ * 3029+ *
3178+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 3030+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
3179+ * Phillip Lougher <phillip@lougher.org.uk> 3031+ * Phillip Lougher <phillip@lougher.demon.co.uk>
3180+ * 3032+ *
3181+ * This program is free software; you can redistribute it and/or 3033+ * This program is free software; you can redistribute it and/or
3182+ * modify it under the terms of the GNU General Public License 3034+ * modify it under the terms of the GNU General Public License
@@ -3224,7 +3076,7 @@
3224+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, 3076+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
3225+ long long index, unsigned int length, 3077+ long long index, unsigned int length,
3226+ long long *next_index, int srclength); 3078+ long long *next_index, int srclength);
3227+extern int squashfs_get_cached_block(struct super_block *s, char *buffer, 3079+extern int squashfs_get_cached_block(struct super_block *s, void *buffer,
3228+ long long block, unsigned int offset, 3080+ long long block, unsigned int offset,
3229+ int length, long long *next_block, 3081+ int length, long long *next_block,
3230+ unsigned int *next_offset); 3082+ unsigned int *next_offset);
@@ -3236,7 +3088,6 @@
3236+extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); 3088+extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
3237+extern const struct address_space_operations squashfs_symlink_aops; 3089+extern const struct address_space_operations squashfs_symlink_aops;
3238+extern const struct address_space_operations squashfs_aops; 3090+extern const struct address_space_operations squashfs_aops;
3239+extern const struct address_space_operations squashfs_aops_4K;
3240+extern struct inode_operations squashfs_dir_inode_ops; 3091+extern struct inode_operations squashfs_dir_inode_ops;
3241+#else 3092+#else
3242+#define SQSH_EXTERN static 3093+#define SQSH_EXTERN static
@@ -3259,9 +3110,10 @@
3259+ return 0; 3110+ return 0;
3260+} 3111+}
3261+#endif 3112+#endif
3262--- /dev/null 3113diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs.h
3263+++ linux-2.6.24-rc1/include/linux/squashfs_fs.h 3114--- linux-2.6.24/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100
3264@@ -0,0 +1,934 @@ 3115+++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs.h 2007-11-01 03:50:57.000000000 +0000
3116@@ -0,0 +1,935 @@
3265+#ifndef SQUASHFS_FS 3117+#ifndef SQUASHFS_FS
3266+#define SQUASHFS_FS 3118+#define SQUASHFS_FS
3267+ 3119+
@@ -3269,7 +3121,7 @@
3269+ * Squashfs 3121+ * Squashfs
3270+ * 3122+ *
3271+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 3123+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
3272+ * Phillip Lougher <phillip@lougher.org.uk> 3124+ * Phillip Lougher <phillip@lougher.demon.co.uk>
3273+ * 3125+ *
3274+ * This program is free software; you can redistribute it and/or 3126+ * This program is free software; you can redistribute it and/or
3275+ * modify it under the terms of the GNU General Public License 3127+ * modify it under the terms of the GNU General Public License
@@ -3292,16 +3144,9 @@
3292+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY 3144+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
3293+#endif 3145+#endif
3294+ 3146+
3295+#ifdef CONFIG_SQUASHFS_VMALLOC
3296+#define SQUASHFS_ALLOC(a) vmalloc(a)
3297+#define SQUASHFS_FREE(a) vfree(a)
3298+#else
3299+#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL)
3300+#define SQUASHFS_FREE(a) kfree(a)
3301+#endif
3302+#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE 3147+#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
3303+#define SQUASHFS_MAJOR 3 3148+#define SQUASHFS_MAJOR 3
3304+#define SQUASHFS_MINOR 0 3149+#define SQUASHFS_MINOR 1
3305+#define SQUASHFS_MAGIC 0x73717368 3150+#define SQUASHFS_MAGIC 0x73717368
3306+#define SQUASHFS_MAGIC_SWAP 0x68737173 3151+#define SQUASHFS_MAGIC_SWAP 0x68737173
3307+#define SQUASHFS_START 0 3152+#define SQUASHFS_START 0
@@ -3311,10 +3156,10 @@
3311+#define SQUASHFS_METADATA_LOG 13 3156+#define SQUASHFS_METADATA_LOG 13
3312+ 3157+
3313+/* default size of data blocks */ 3158+/* default size of data blocks */
3314+#define SQUASHFS_FILE_SIZE 65536 3159+#define SQUASHFS_FILE_SIZE 131072
3315+#define SQUASHFS_FILE_LOG 16 3160+#define SQUASHFS_FILE_LOG 17
3316+ 3161+
3317+#define SQUASHFS_FILE_MAX_SIZE 65536 3162+#define SQUASHFS_FILE_MAX_SIZE 1048576
3318+ 3163+
3319+/* Max number of uids and gids */ 3164+/* Max number of uids and gids */
3320+#define SQUASHFS_UIDS 256 3165+#define SQUASHFS_UIDS 256
@@ -3395,9 +3240,8 @@
3395+ 3240+
3396+#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) 3241+#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
3397+ 3242+
3398+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \ 3243+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
3399+ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \ 3244+ ~SQUASHFS_COMPRESSED_BIT_BLOCK)
3400+ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
3401+ 3245+
3402+#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) 3246+#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
3403+ 3247+
@@ -3893,6 +3737,15 @@
3893+ unsigned int start_block:24; 3737+ unsigned int start_block:24;
3894+} __attribute__ ((packed)); 3738+} __attribute__ ((packed));
3895+ 3739+
3740+union squashfs_inode_header_1 {
3741+ struct squashfs_base_inode_header_1 base;
3742+ struct squashfs_dev_inode_header_1 dev;
3743+ struct squashfs_symlink_inode_header_1 symlink;
3744+ struct squashfs_reg_inode_header_1 reg;
3745+ struct squashfs_dir_inode_header_1 dir;
3746+ struct squashfs_ipc_inode_header_1 ipc;
3747+};
3748+
3896+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ 3749+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
3897+ SQUASHFS_MEMSET(s, d, n);\ 3750+ SQUASHFS_MEMSET(s, d, n);\
3898+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ 3751+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
@@ -4196,8 +4049,9 @@
4196+ 4049+
4197+#endif 4050+#endif
4198+#endif 4051+#endif
4199--- /dev/null 4052diff -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
4200+++ linux-2.6.24-rc1/include/linux/squashfs_fs_i.h 4053--- linux-2.6.24/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
4054+++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_i.h 2007-08-19 04:24:08.000000000 +0100
4201@@ -0,0 +1,45 @@ 4055@@ -0,0 +1,45 @@
4202+#ifndef SQUASHFS_FS_I 4056+#ifndef SQUASHFS_FS_I
4203+#define SQUASHFS_FS_I 4057+#define SQUASHFS_FS_I
@@ -4205,7 +4059,7 @@
4205+ * Squashfs 4059+ * Squashfs
4206+ * 4060+ *
4207+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 4061+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4208+ * Phillip Lougher <phillip@lougher.org.uk> 4062+ * Phillip Lougher <phillip@lougher.demon.co.uk>
4209+ * 4063+ *
4210+ * This program is free software; you can redistribute it and/or 4064+ * This program is free software; you can redistribute it and/or
4211+ * modify it under the terms of the GNU General Public License 4065+ * modify it under the terms of the GNU General Public License
@@ -4244,16 +4098,17 @@
4244+ struct inode vfs_inode; 4098+ struct inode vfs_inode;
4245+}; 4099+};
4246+#endif 4100+#endif
4247--- /dev/null 4101diff -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
4248+++ linux-2.6.24-rc1/include/linux/squashfs_fs_sb.h 4102--- linux-2.6.24/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
4249@@ -0,0 +1,74 @@ 4103+++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_sb.h 2007-08-19 04:24:26.000000000 +0100
4104@@ -0,0 +1,76 @@
4250+#ifndef SQUASHFS_FS_SB 4105+#ifndef SQUASHFS_FS_SB
4251+#define SQUASHFS_FS_SB 4106+#define SQUASHFS_FS_SB
4252+/* 4107+/*
4253+ * Squashfs 4108+ * Squashfs
4254+ * 4109+ *
4255+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 4110+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4256+ * Phillip Lougher <phillip@lougher.org.uk> 4111+ * Phillip Lougher <phillip@lougher.demon.co.uk>
4257+ * 4112+ *
4258+ * This program is free software; you can redistribute it and/or 4113+ * This program is free software; you can redistribute it and/or
4259+ * modify it under the terms of the GNU General Public License 4114+ * modify it under the terms of the GNU General Public License
@@ -4313,6 +4168,8 @@
4313+ struct meta_index *meta_index; 4168+ struct meta_index *meta_index;
4314+ z_stream stream; 4169+ z_stream stream;
4315+ long long *inode_lookup_table; 4170+ long long *inode_lookup_table;
4171+ int unused_cache_blks;
4172+ int unused_frag_blks;
4316+ int (*read_inode)(struct inode *i, squashfs_inode_t \ 4173+ int (*read_inode)(struct inode *i, squashfs_inode_t \
4317+ inode); 4174+ inode);
4318+ long long (*read_blocklist)(struct inode *inode, int \ 4175+ long long (*read_blocklist)(struct inode *inode, int \
@@ -4321,8 +4178,9 @@
4321+ int (*read_fragment_index_table)(struct super_block *s); 4178+ int (*read_fragment_index_table)(struct super_block *s);
4322+}; 4179+};
4323+#endif 4180+#endif
4324--- linux-2.6.24-rc1.orig/init/do_mounts_rd.c 4181diff -x .gitignore -Nurp linux-2.6.24/init/do_mounts_rd.c linux-2.6.24-squashfs3.3/init/do_mounts_rd.c
4325+++ linux-2.6.24-rc1/init/do_mounts_rd.c 4182--- linux-2.6.24/init/do_mounts_rd.c 2007-10-25 17:41:49.000000000 +0100
4183+++ linux-2.6.24-squashfs3.3/init/do_mounts_rd.c 2007-11-01 05:06:25.000000000 +0000
4326@@ -5,6 +5,7 @@ 4184@@ -5,6 +5,7 @@
4327 #include <linux/ext2_fs.h> 4185 #include <linux/ext2_fs.h>
4328 #include <linux/romfs_fs.h> 4186 #include <linux/romfs_fs.h>
@@ -4331,7 +4189,7 @@
4331 #include <linux/initrd.h> 4189 #include <linux/initrd.h>
4332 #include <linux/string.h> 4190 #include <linux/string.h>
4333 4191
4334@@ -39,6 +40,7 @@ 4192@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
4335 * numbers could not be found. 4193 * numbers could not be found.
4336 * 4194 *
4337 * We currently check for the following magic numbers: 4195 * We currently check for the following magic numbers:
@@ -4339,7 +4197,7 @@
4339 * minix 4197 * minix
4340 * ext2 4198 * ext2
4341 * romfs 4199 * romfs
4342@@ -53,6 +55,7 @@ 4200@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
4343 struct ext2_super_block *ext2sb; 4201 struct ext2_super_block *ext2sb;
4344 struct romfs_super_block *romfsb; 4202 struct romfs_super_block *romfsb;
4345 struct cramfs_super *cramfsb; 4203 struct cramfs_super *cramfsb;
@@ -4347,7 +4205,7 @@
4347 int nblocks = -1; 4205 int nblocks = -1;
4348 unsigned char *buf; 4206 unsigned char *buf;
4349 4207
4350@@ -64,6 +67,7 @@ 4208@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
4351 ext2sb = (struct ext2_super_block *) buf; 4209 ext2sb = (struct ext2_super_block *) buf;
4352 romfsb = (struct romfs_super_block *) buf; 4210 romfsb = (struct romfs_super_block *) buf;
4353 cramfsb = (struct cramfs_super *) buf; 4211 cramfsb = (struct cramfs_super *) buf;
@@ -4355,7 +4213,7 @@
4355 memset(buf, 0xe5, size); 4213 memset(buf, 0xe5, size);
4356 4214
4357 /* 4215 /*
4358@@ -101,6 +105,18 @@ 4216@@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
4359 goto done; 4217 goto done;
4360 } 4218 }
4361 4219
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 @@
1---
2 Documentation/fb/uvesafb.txt | 188 +++
3 drivers/video/Kconfig | 18
4 drivers/video/Makefile | 1
5 drivers/video/modedb.c | 28
6 drivers/video/uvesafb.c | 2058 +++++++++++++++++++++++++++++++++++++++++++
7 include/linux/connector.h | 7
8 include/video/Kbuild | 2
9 include/video/uvesafb.h | 193 ++++
10 8 files changed, 2479 insertions(+), 16 deletions(-)
11
12Index: linux-2.6.22/Documentation/fb/uvesafb.txt
13===================================================================
14--- /dev/null 1970-01-01 00:00:00.000000000 +0000
15+++ linux-2.6.22/Documentation/fb/uvesafb.txt 2007-08-28 21:56:34.000000000 +0100
16@@ -0,0 +1,188 @@
17+
18+uvesafb - A Generic Driver for VBE2+ compliant video cards
19+==========================================================
20+
21+1. Requirements
22+---------------
23+
24+uvesafb should work with any video card that has a Video BIOS compliant
25+with the VBE 2.0 standard.
26+
27+Unlike other drivers, uvesafb makes use of a userspace helper called
28+v86d. v86d is used to run the x86 Video BIOS code in a simulated and
29+controlled environment. This allows uvesafb to function on arches other
30+than x86. Check the v86d documentation for a list of currently supported
31+arches.
32+
33+v86d source code can be downloaded from the following website:
34+ http://dev.gentoo.org/~spock/projects/uvesafb
35+
36+Please refer to the v86d documentation for detailed configuration and
37+installation instructions.
38+
39+Note that the v86d userspace helper has to be available at all times in
40+order for uvesafb to work properly. If you want to use uvesafb during
41+early boot, you will have to include v86d into an initramfs image, and
42+either compile it into the kernel or use it as an initrd.
43+
44+2. Caveats and limitations
45+--------------------------
46+
47+uvesafb is a _generic_ driver which supports a wide variety of video
48+cards, but which is ultimately limited by the Video BIOS interface.
49+The most important limitations are:
50+
51+- Lack of any type of acceleration.
52+- A strict and limited set of supported video modes. Often the native
53+ or most optimal resolution/refresh rate for your setup will not work
54+ with uvesafb, simply because the Video BIOS doesn't support the
55+ video mode you want to use. This can be especially painful with
56+ widescreen panels, where native video modes don't have the 4:3 aspect
57+ ratio, which is what most BIOS-es are limited to.
58+- Adjusting the refresh rate is only possible with a VBE 3.0 compliant
59+ Video BIOS. Note that many nVidia Video BIOS-es claim to be VBE 3.0
60+ compliant, while they simply ignore any refresh rate settings.
61+
62+3. Configuration
63+----------------
64+
65+uvesafb can be compiled either as a module, or directly into the kernel.
66+In both cases it supports the same set of configuration options, which
67+are either given on the kernel command line or as module parameters, e.g.:
68+
69+ video=uvesafb:1024x768-32,mtrr:3,ywrap (compiled into the kernel)
70+
71+ # modprobe uvesafb mode=1024x768-32 mtrr=3 scroll=ywrap (module)
72+
73+Accepted options:
74+
75+ypan Enable display panning using the VESA protected mode
76+ interface. The visible screen is just a window of the
77+ video memory, console scrolling is done by changing the
78+ start of the window. Available on x86 only.
79+
80+ywrap Same as ypan, but assumes your gfx board can wrap-around
81+ the video memory (i.e. starts reading from top if it
82+ reaches the end of video memory). Faster than ypan.
83+ Available on x86 only.
84+
85+redraw Scroll by redrawing the affected part of the screen, this
86+ is the safe (and slow) default.
87+
88+(If you're using uvesafb as a module, the above three options are
89+ used a parameter of the scroll option, e.g. scroll=ypan.)
90+
91+vgapal Use the standard VGA registers for palette changes.
92+
93+pmipal Use the protected mode interface for palette changes.
94+ This is the default if the protected mode interface is
95+ available. Available on x86 only.
96+
97+mtrr:n Setup memory type range registers for the framebuffer
98+ where n:
99+ 0 - disabled (equivalent to nomtrr) (default)
100+ 1 - uncachable
101+ 2 - write-back
102+ 3 - write-combining
103+ 4 - write-through
104+
105+ If you see the following in dmesg, choose the type that matches
106+ the old one. In this example, use "mtrr:2".
107+...
108+mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining
109+...
110+
111+nomtrr Do not use memory type range registers.
112+
113+vremap:n
114+ Remap 'n' MiB of video RAM. If 0 or not specified, remap memory
115+ according to video mode.
116+
117+vtotal:n
118+ If the video BIOS of your card incorrectly determines the total
119+ amount of video RAM, use this option to override the BIOS (in MiB).
120+
121+<mode> The mode you want to set, in the standard modedb format. Refer to
122+ modedb.txt for a detailed description. When uvesafb is compiled as
123+ a module, the mode string should be provided as a value of the
124+ 'mode' option.
125+
126+vbemode:x
127+ Force the use of VBE mode x. The mode will only be set if it's
128+ found in the VBE-provided list of supported modes.
129+ NOTE: The mode number 'x' should be specified in VESA mode number
130+ notation, not the Linux kernel one (eg. 257 instead of 769).
131+ HINT: If you use this option because normal <mode> parameter does
132+ not work for you and you use a X server, you'll probably want to
133+ set the 'nocrtc' option to ensure that the video mode is properly
134+ restored after console <-> X switches.
135+
136+nocrtc Do not use CRTC timings while setting the video mode. This option
137+ has any effect only if the Video BIOS is VBE 3.0 compliant. Use it
138+ if you have problems with modes set the standard way. Note that
139+ using this option implies that any refresh rate adjustments will
140+ be ignored and the refresh rate will stay at your BIOS default (60 Hz).
141+
142+noedid Do not try to fetch and use EDID-provided modes.
143+
144+noblank Disable hardware blanking.
145+
146+v86d:path
147+ Set path to the v86d executable. This option is only available as
148+ a module parameter, and not as a part of the video= string. If you
149+ need to use it and have uvesafb built into the kernel, use
150+ uvesafb.v86d="path".
151+
152+Additionally, the following parameters may be provided. They all override the
153+EDID-provided values and BIOS defaults. Refer to your monitor's specs to get
154+the correct values for maxhf, maxvf and maxclk for your hardware.
155+
156+maxhf:n Maximum horizontal frequency (in kHz).
157+maxvf:n Maximum vertical frequency (in Hz).
158+maxclk:n Maximum pixel clock (in MHz).
159+
160+4. The sysfs interface
161+----------------------
162+
163+uvesafb provides several sysfs nodes for configurable parameters and
164+additional information.
165+
166+Driver attributes:
167+
168+/sys/bus/platform/drivers/uvesafb
169+ - v86d (default: /sbin/v86d)
170+ Path to the v86d executable. v86d is started by uvesafb
171+ if an instance of the daemon isn't already running.
172+
173+Device attributes:
174+
175+/sys/bus/platform/drivers/uvesafb/uvesafb.0
176+ - nocrtc
177+ Use the default refresh rate (60 Hz) if set to 1.
178+
179+ - oem_product_name
180+ - oem_product_rev
181+ - oem_string
182+ - oem_vendor
183+ Information about the card and its maker.
184+
185+ - vbe_modes
186+ A list of video modes supported by the Video BIOS along with their
187+ VBE mode numbers in hex.
188+
189+ - vbe_version
190+ A BCD value indicating the implemented VBE standard.
191+
192+5. Miscellaneous
193+----------------
194+
195+Uvesafb will set a video mode with the default refresh rate and timings
196+from the Video BIOS if you set pixclock to 0 in fb_var_screeninfo.
197+
198+
199+--
200+ Michal Januszewski <spock@gentoo.org>
201+ Last updated: 2007-06-16
202+
203+ Documentation of the uvesafb options is loosely based on vesafb.txt.
204+
205Index: linux-2.6.22/drivers/video/Kconfig
206===================================================================
207--- linux-2.6.22.orig/drivers/video/Kconfig 2007-08-28 21:56:33.000000000 +0100
208+++ linux-2.6.22/drivers/video/Kconfig 2007-08-28 21:56:34.000000000 +0100
209@@ -592,6 +592,24 @@ config FB_TGA
210
211 Say Y if you have one of those.
212
213+config FB_UVESA
214+ tristate "Userspace VESA VGA graphics support"
215+ depends on FB && CONNECTOR
216+ select FB_CFB_FILLRECT
217+ select FB_CFB_COPYAREA
218+ select FB_CFB_IMAGEBLIT
219+ select FB_MODE_HELPERS
220+ help
221+ This is the frame buffer driver for generic VBE 2.0 compliant
222+ graphic cards. It can also take advantage of VBE 3.0 features,
223+ such as refresh rate adjustment.
224+
225+ This driver generally provides more features than vesafb but
226+ requires a userspace helper application called 'v86d'. See
227+ <file:Documentation/fb/uvesafb.txt> for more information.
228+
229+ If unsure, say N.
230+
231 config FB_VESA
232 bool "VESA VGA graphics support"
233 depends on (FB = y) && X86
234Index: linux-2.6.22/drivers/video/Makefile
235===================================================================
236--- linux-2.6.22.orig/drivers/video/Makefile 2007-08-28 21:56:33.000000000 +0100
237+++ linux-2.6.22/drivers/video/Makefile 2007-08-28 21:56:34.000000000 +0100
238@@ -116,6 +116,7 @@ obj-$(CONFIG_FB_XILINX) += xil
239 obj-$(CONFIG_FB_OMAP) += omap/
240
241 # Platform or fallback drivers go here
242+obj-$(CONFIG_FB_UVESA) += uvesafb.o
243 obj-$(CONFIG_FB_VESA) += vesafb.o
244 obj-$(CONFIG_FB_IMAC) += imacfb.o
245 obj-$(CONFIG_FB_VGA16) += vga16fb.o
246Index: linux-2.6.22/drivers/video/modedb.c
247===================================================================
248--- linux-2.6.22.orig/drivers/video/modedb.c 2007-08-28 21:54:13.000000000 +0100
249+++ linux-2.6.22/drivers/video/modedb.c 2007-08-28 21:56:34.000000000 +0100
250@@ -606,26 +606,29 @@ done:
251 DPRINTK("Trying specified video mode%s %ix%i\n",
252 refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
253
254- diff = refresh;
255+ if (!refresh_specified)
256+ diff = 0;
257+ else
258+ diff = refresh;
259+
260 best = -1;
261 for (i = 0; i < dbsize; i++) {
262- if (name_matches(db[i], name, namelen) ||
263- (res_specified && res_matches(db[i], xres, yres))) {
264- if(!fb_try_mode(var, info, &db[i], bpp)) {
265- if(!refresh_specified || db[i].refresh == refresh)
266- return 1;
267- else {
268- if(diff > abs(db[i].refresh - refresh)) {
269- diff = abs(db[i].refresh - refresh);
270- best = i;
271- }
272+ if ((name_matches(db[i], name, namelen) ||
273+ (res_specified && res_matches(db[i], xres, yres))) &&
274+ !fb_try_mode(var, info, &db[i], bpp)) {
275+ if (refresh_specified && db[i].refresh == refresh) {
276+ return 1;
277+ } else {
278+ if (diff < db[i].refresh) {
279+ diff = db[i].refresh;
280+ best = i;
281 }
282 }
283 }
284 }
285 if (best != -1) {
286 fb_try_mode(var, info, &db[best], bpp);
287- return 2;
288+ return (refresh_specified) ? 2 : 1;
289 }
290
291 diff = xres + yres;
292@@ -938,6 +941,7 @@ void fb_destroy_modelist(struct list_hea
293 kfree(pos);
294 }
295 }
296+EXPORT_SYMBOL_GPL(fb_destroy_modelist);
297
298 /**
299 * fb_videomode_to_modelist: convert mode array to mode list
300Index: linux-2.6.22/drivers/video/uvesafb.c
301===================================================================
302--- /dev/null 1970-01-01 00:00:00.000000000 +0000
303+++ linux-2.6.22/drivers/video/uvesafb.c 2007-08-28 21:56:34.000000000 +0100
304@@ -0,0 +1,2058 @@
305+/*
306+ * A framebuffer driver for VBE 2.0+ compliant video cards
307+ *
308+ * (c) 2007 Michal Januszewski <spock@gentoo.org>
309+ * Loosely based upon the vesafb driver.
310+ *
311+ */
312+#include <linux/init.h>
313+#include <linux/module.h>
314+#include <linux/moduleparam.h>
315+#include <linux/skbuff.h>
316+#include <linux/timer.h>
317+#include <linux/completion.h>
318+#include <linux/connector.h>
319+#include <linux/random.h>
320+#include <linux/platform_device.h>
321+#include <linux/limits.h>
322+#include <linux/fb.h>
323+#include <linux/io.h>
324+#include <linux/mutex.h>
325+#include <video/edid.h>
326+#include <video/vga.h>
327+#include <video/uvesafb.h>
328+#ifdef CONFIG_MTRR
329+#include <asm/mtrr.h>
330+#endif
331+#include "edid.h"
332+
333+static struct cb_id uvesafb_cn_id = {
334+ .idx = CN_IDX_V86D,
335+ .val = CN_VAL_V86D_UVESAFB
336+};
337+static char v86d_path[PATH_MAX] = "/sbin/v86d";
338+static char v86d_started; /* has v86d been started by uvesafb? */
339+
340+static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
341+ .id = "VESA VGA",
342+ .type = FB_TYPE_PACKED_PIXELS,
343+ .accel = FB_ACCEL_NONE,
344+ .visual = FB_VISUAL_TRUECOLOR,
345+};
346+
347+static int mtrr __devinitdata = 3; /* enable mtrr by default */
348+static int blank __devinitdata = 1; /* enable blanking by default */
349+static int ypan __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */
350+static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */
351+static int nocrtc __devinitdata; /* ignore CRTC settings */
352+static int noedid __devinitdata; /* don't try DDC transfers */
353+static int vram_remap __devinitdata; /* set amt. of memory to be used */
354+static int vram_total __devinitdata; /* set total amount of memory */
355+static u16 maxclk __devinitdata; /* maximum pixel clock */
356+static u16 maxvf __devinitdata; /* maximum vertical frequency */
357+static u16 maxhf __devinitdata; /* maximum horizontal frequency */
358+static u16 vbemode __devinitdata; /* force use of a specific VBE mode */
359+static char *mode_option __devinitdata;
360+
361+static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX];
362+static DEFINE_MUTEX(uvfb_lock);
363+
364+/*
365+ * A handler for replies from userspace.
366+ *
367+ * Make sure each message passes consistency checks and if it does,
368+ * find the kernel part of the task struct, copy the registers and
369+ * the buffer contents and then complete the task.
370+ */
371+static void uvesafb_cn_callback(void *data)
372+{
373+ struct cn_msg *msg = data;
374+ struct uvesafb_task *utask;
375+ struct uvesafb_ktask *task;
376+
377+ if (msg->seq >= UVESAFB_TASKS_MAX)
378+ return;
379+
380+ mutex_lock(&uvfb_lock);
381+ task = uvfb_tasks[msg->seq];
382+
383+ if (!task || msg->ack != task->ack) {
384+ mutex_unlock(&uvfb_lock);
385+ return;
386+ }
387+
388+ utask = (struct uvesafb_task *)msg->data;
389+
390+ /* Sanity checks for the buffer length. */
391+ if (task->t.buf_len < utask->buf_len ||
392+ utask->buf_len > msg->len - sizeof(*utask)) {
393+ mutex_unlock(&uvfb_lock);
394+ return;
395+ }
396+
397+ uvfb_tasks[msg->seq] = NULL;
398+ mutex_unlock(&uvfb_lock);
399+
400+ memcpy(&task->t, utask, sizeof(*utask));
401+
402+ if (task->t.buf_len && task->buf)
403+ memcpy(task->buf, utask + 1, task->t.buf_len);
404+
405+ complete(task->done);
406+ return;
407+}
408+
409+static int uvesafb_helper_start(void)
410+{
411+ char *envp[] = {
412+ "HOME=/",
413+ "PATH=/sbin:/bin",
414+ NULL,
415+ };
416+
417+ char *argv[] = {
418+ v86d_path,
419+ NULL,
420+ };
421+
422+ return call_usermodehelper(v86d_path, argv, envp, 1);
423+}
424+
425+/*
426+ * Execute a uvesafb task.
427+ *
428+ * Returns 0 if the task is executed successfully.
429+ *
430+ * A message sent to the userspace consists of the uvesafb_task
431+ * struct and (optionally) a buffer. The uvesafb_task struct is
432+ * a simplified version of uvesafb_ktask (its kernel counterpart)
433+ * containing only the register values, flags and the length of
434+ * the buffer.
435+ *
436+ * Each message is assigned a sequence number (increased linearly)
437+ * and a random ack number. The sequence number is used as a key
438+ * for the uvfb_tasks array which holds pointers to uvesafb_ktask
439+ * structs for all requests.
440+ */
441+static int uvesafb_exec(struct uvesafb_ktask *task)
442+{
443+ static int seq;
444+ struct cn_msg *m;
445+ int err;
446+ int len = sizeof(task->t) + task->t.buf_len;
447+
448+ /*
449+ * Check whether the message isn't longer than the maximum
450+ * allowed by connector.
451+ */
452+ if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) {
453+ printk(KERN_WARNING "uvesafb: message too long (%d), "
454+ "can't execute task\n", (int)(sizeof(*m) + len));
455+ return -E2BIG;
456+ }
457+
458+ m = kzalloc(sizeof(*m) + len, GFP_KERNEL);
459+ if (!m)
460+ return -ENOMEM;
461+
462+ init_completion(task->done);
463+
464+ memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id));
465+ m->seq = seq;
466+ m->len = len;
467+ m->ack = random32();
468+
469+ /* uvesafb_task structure */
470+ memcpy(m + 1, &task->t, sizeof(task->t));
471+
472+ /* Buffer */
473+ memcpy((u8 *)(m + 1) + sizeof(task->t), task->buf, task->t.buf_len);
474+
475+ /*
476+ * Save the message ack number so that we can find the kernel
477+ * part of this task when a reply is received from userspace.
478+ */
479+ task->ack = m->ack;
480+
481+ mutex_lock(&uvfb_lock);
482+
483+ /* If all slots are taken -- bail out. */
484+ if (uvfb_tasks[seq]) {
485+ mutex_unlock(&uvfb_lock);
486+ return -EBUSY;
487+ }
488+
489+ /* Save a pointer to the kernel part of the task struct. */
490+ uvfb_tasks[seq] = task;
491+ mutex_unlock(&uvfb_lock);
492+
493+ err = cn_netlink_send(m, 0, gfp_any());
494+ if (err == -ESRCH) {
495+ /*
496+ * Try to start the userspace helper if sending
497+ * the request failed the first time.
498+ */
499+ err = uvesafb_helper_start();
500+ if (err) {
501+ printk(KERN_ERR "uvesafb: failed to execute %s\n",
502+ v86d_path);
503+ printk(KERN_ERR "uvesafb: make sure that the v86d "
504+ "helper is installed and executable\n");
505+ } else {
506+ v86d_started = 1;
507+ err = cn_netlink_send(m, 0, gfp_any());
508+ }
509+ }
510+ kfree(m);
511+
512+ if (!err && !(task->t.flags & TF_EXIT))
513+ err = !wait_for_completion_timeout(task->done,
514+ msecs_to_jiffies(UVESAFB_TIMEOUT));
515+
516+ mutex_lock(&uvfb_lock);
517+ uvfb_tasks[seq] = NULL;
518+ mutex_unlock(&uvfb_lock);
519+
520+ seq++;
521+ if (seq >= UVESAFB_TASKS_MAX)
522+ seq = 0;
523+
524+ return err;
525+}
526+
527+/*
528+ * Free a uvesafb_ktask struct.
529+ */
530+static void uvesafb_free(struct uvesafb_ktask *task)
531+{
532+ if (task) {
533+ if (task->done)
534+ kfree(task->done);
535+ kfree(task);
536+ }
537+}
538+
539+/*
540+ * Prepare a uvesafb_ktask struct to be used again.
541+ */
542+static void uvesafb_reset(struct uvesafb_ktask *task)
543+{
544+ struct completion *cpl = task->done;
545+
546+ memset(task, 0, sizeof(*task));
547+ task->done = cpl;
548+}
549+
550+/*
551+ * Allocate and prepare a uvesafb_ktask struct.
552+ */
553+static struct uvesafb_ktask *uvesafb_prep(void)
554+{
555+ struct uvesafb_ktask *task;
556+
557+ task = kzalloc(sizeof(*task), GFP_KERNEL);
558+ if (task) {
559+ task->done = kzalloc(sizeof(*task->done), GFP_KERNEL);
560+ if (!task->done) {
561+ kfree(task);
562+ task = NULL;
563+ }
564+ }
565+ return task;
566+}
567+
568+static void uvesafb_setup_var(struct fb_var_screeninfo *var,
569+ struct fb_info *info, struct vbe_mode_ib *mode)
570+{
571+ struct uvesafb_par *par = info->par;
572+
573+ var->vmode = FB_VMODE_NONINTERLACED;
574+ var->sync = FB_SYNC_VERT_HIGH_ACT;
575+
576+ var->xres = mode->x_res;
577+ var->yres = mode->y_res;
578+ var->xres_virtual = mode->x_res;
579+ var->yres_virtual = (par->ypan) ?
580+ info->fix.smem_len / mode->bytes_per_scan_line :
581+ mode->y_res;
582+ var->xoffset = 0;
583+ var->yoffset = 0;
584+ var->bits_per_pixel = mode->bits_per_pixel;
585+
586+ if (var->bits_per_pixel == 15)
587+ var->bits_per_pixel = 16;
588+
589+ if (var->bits_per_pixel > 8) {
590+ var->red.offset = mode->red_off;
591+ var->red.length = mode->red_len;
592+ var->green.offset = mode->green_off;
593+ var->green.length = mode->green_len;
594+ var->blue.offset = mode->blue_off;
595+ var->blue.length = mode->blue_len;
596+ var->transp.offset = mode->rsvd_off;
597+ var->transp.length = mode->rsvd_len;
598+ } else {
599+ var->red.offset = 0;
600+ var->green.offset = 0;
601+ var->blue.offset = 0;
602+ var->transp.offset = 0;
603+
604+ /*
605+ * We're assuming that we can switch the DAC to 8 bits. If
606+ * this proves to be incorrect, we'll update the fields
607+ * later in set_par().
608+ */
609+ if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) {
610+ var->red.length = 8;
611+ var->green.length = 8;
612+ var->blue.length = 8;
613+ var->transp.length = 0;
614+ } else {
615+ var->red.length = 6;
616+ var->green.length = 6;
617+ var->blue.length = 6;
618+ var->transp.length = 0;
619+ }
620+ }
621+}
622+
623+static int uvesafb_vbe_find_mode(struct uvesafb_par *par,
624+ int xres, int yres, int depth, unsigned char flags)
625+{
626+ int i, match = -1, h = 0, d = 0x7fffffff;
627+
628+ for (i = 0; i < par->vbe_modes_cnt; i++) {
629+ h = abs(par->vbe_modes[i].x_res - xres) +
630+ abs(par->vbe_modes[i].y_res - yres) +
631+ abs(depth - par->vbe_modes[i].depth);
632+
633+ /*
634+ * We have an exact match in terms of resolution
635+ * and depth.
636+ */
637+ if (h == 0)
638+ return i;
639+
640+ if (h < d || (h == d && par->vbe_modes[i].depth > depth)) {
641+ d = h;
642+ match = i;
643+ }
644+ }
645+ i = 1;
646+
647+ if (flags & UVESAFB_EXACT_DEPTH &&
648+ par->vbe_modes[match].depth != depth)
649+ i = 0;
650+
651+ if (flags & UVESAFB_EXACT_RES && d > 24)
652+ i = 0;
653+
654+ if (i != 0)
655+ return match;
656+ else
657+ return -1;
658+}
659+
660+static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par)
661+{
662+ struct uvesafb_ktask *task;
663+ u8 *state;
664+ int err;
665+
666+ if (!par->vbe_state_size)
667+ return NULL;
668+
669+ state = kmalloc(par->vbe_state_size, GFP_KERNEL);
670+ if (!state)
671+ return NULL;
672+
673+ task = uvesafb_prep();
674+ if (!task) {
675+ kfree(state);
676+ return NULL;
677+ }
678+
679+ task->t.regs.eax = 0x4f04;
680+ task->t.regs.ecx = 0x000f;
681+ task->t.regs.edx = 0x0001;
682+ task->t.flags = TF_BUF_RET | TF_BUF_ESBX;
683+ task->t.buf_len = par->vbe_state_size;
684+ task->buf = state;
685+ err = uvesafb_exec(task);
686+
687+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
688+ printk(KERN_WARNING "uvesafb: VBE get state call "
689+ "failed (eax=0x%x, err=%d)\n",
690+ task->t.regs.eax, err);
691+ kfree(state);
692+ state = NULL;
693+ }
694+
695+ uvesafb_free(task);
696+ return state;
697+}
698+
699+static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf)
700+{
701+ struct uvesafb_ktask *task;
702+ int err;
703+
704+ if (!state_buf)
705+ return;
706+
707+ task = uvesafb_prep();
708+ if (!task)
709+ return;
710+
711+ task->t.regs.eax = 0x4f04;
712+ task->t.regs.ecx = 0x000f;
713+ task->t.regs.edx = 0x0002;
714+ task->t.buf_len = par->vbe_state_size;
715+ task->t.flags = TF_BUF_ESBX;
716+ task->buf = state_buf;
717+
718+ err = uvesafb_exec(task);
719+ if (err || (task->t.regs.eax & 0xffff) != 0x004f)
720+ printk(KERN_WARNING "uvesafb: VBE state restore call "
721+ "failed (eax=0x%x, err=%d)\n",
722+ task->t.regs.eax, err);
723+
724+ uvesafb_free(task);
725+}
726+
727+static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
728+ struct uvesafb_par *par)
729+{
730+ int err;
731+
732+ task->t.regs.eax = 0x4f00;
733+ task->t.flags = TF_VBEIB;
734+ task->t.buf_len = sizeof(struct vbe_ib);
735+ task->buf = &par->vbe_ib;
736+ strncpy(par->vbe_ib.vbe_signature, "VBE2", 4);
737+
738+ err = uvesafb_exec(task);
739+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
740+ printk(KERN_ERR "uvesafb: Getting VBE info block failed "
741+ "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax,
742+ err);
743+ return -EINVAL;
744+ }
745+
746+ if (par->vbe_ib.vbe_version < 0x0200) {
747+ printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are "
748+ "not supported.\n");
749+ return -EINVAL;
750+ }
751+
752+ if (!par->vbe_ib.mode_list_ptr) {
753+ printk(KERN_ERR "uvesafb: Missing mode list!\n");
754+ return -EINVAL;
755+ }
756+
757+ printk(KERN_INFO "uvesafb: ");
758+
759+ /*
760+ * Convert string pointers and the mode list pointer into
761+ * usable addresses. Print informational messages about the
762+ * video adapter and its vendor.
763+ */
764+ if (par->vbe_ib.oem_vendor_name_ptr)
765+ printk("%s, ",
766+ ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr);
767+
768+ if (par->vbe_ib.oem_product_name_ptr)
769+ printk("%s, ",
770+ ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr);
771+
772+ if (par->vbe_ib.oem_product_rev_ptr)
773+ printk("%s, ",
774+ ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr);
775+
776+ if (par->vbe_ib.oem_string_ptr)
777+ printk("OEM: %s, ",
778+ ((char *)task->buf) + par->vbe_ib.oem_string_ptr);
779+
780+ printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8),
781+ par->vbe_ib.vbe_version & 0xff);
782+
783+ return 0;
784+}
785+
786+static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
787+ struct uvesafb_par *par)
788+{
789+ int off = 0, err;
790+ u16 *mode;
791+
792+ par->vbe_modes_cnt = 0;
793+
794+ /* Count available modes. */
795+ mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr);
796+ while (*mode != 0xffff) {
797+ par->vbe_modes_cnt++;
798+ mode++;
799+ }
800+
801+ par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) *
802+ par->vbe_modes_cnt, GFP_KERNEL);
803+ if (!par->vbe_modes)
804+ return -ENOMEM;
805+
806+ /* Get info about all available modes. */
807+ mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr);
808+ while (*mode != 0xffff) {
809+ struct vbe_mode_ib *mib;
810+
811+ uvesafb_reset(task);
812+ task->t.regs.eax = 0x4f01;
813+ task->t.regs.ecx = (u32) *mode;
814+ task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
815+ task->t.buf_len = sizeof(struct vbe_mode_ib);
816+ task->buf = par->vbe_modes + off;
817+
818+ err = uvesafb_exec(task);
819+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
820+ printk(KERN_ERR "uvesafb: Getting mode info block "
821+ "for mode 0x%x failed (eax=0x%x, err=%d)\n",
822+ *mode, (u32)task->t.regs.eax, err);
823+ return -EINVAL;
824+ }
825+
826+ mib = task->buf;
827+ mib->mode_id = *mode;
828+
829+ /*
830+ * We only want modes that are supported with the current
831+ * hardware configuration, color, graphics and that have
832+ * support for the LFB.
833+ */
834+ if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK &&
835+ mib->bits_per_pixel >= 8)
836+ off++;
837+ else
838+ par->vbe_modes_cnt--;
839+
840+ mode++;
841+ mib->depth = mib->red_len + mib->green_len + mib->blue_len;
842+
843+ /*
844+ * Handle 8bpp modes and modes with broken color component
845+ * lengths.
846+ */
847+ if (mib->depth == 0 || (mib->depth == 24 &&
848+ mib->bits_per_pixel == 32))
849+ mib->depth = mib->bits_per_pixel;
850+ }
851+
852+ return 0;
853+}
854+
855+/*
856+ * The Protected Mode Interface is 32-bit x86 code, so we only run it on
857+ * x86 and not x86_64.
858+ */
859+#ifdef CONFIG_X86_32
860+static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
861+ struct uvesafb_par *par)
862+{
863+ int i, err;
864+
865+ uvesafb_reset(task);
866+ task->t.regs.eax = 0x4f0a;
867+ task->t.regs.ebx = 0x0;
868+ err = uvesafb_exec(task);
869+
870+ if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) {
871+ par->pmi_setpal = par->ypan = 0;
872+ } else {
873+ par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4)
874+ + task->t.regs.edi);
875+ par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1];
876+ par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2];
877+ printk(KERN_INFO "uvesafb: protected mode interface info at "
878+ "%04x:%04x\n",
879+ (u16)task->t.regs.es, (u16)task->t.regs.edi);
880+ printk(KERN_INFO "uvesafb: pmi: set display start = %p, "
881+ "set palette = %p\n", par->pmi_start,
882+ par->pmi_pal);
883+
884+ if (par->pmi_base[3]) {
885+ printk(KERN_INFO "uvesafb: pmi: ports = ");
886+ for (i = par->pmi_base[3]/2;
887+ par->pmi_base[i] != 0xffff; i++)
888+ printk("%x ", par->pmi_base[i]);
889+ printk("\n");
890+
891+ if (par->pmi_base[i] != 0xffff) {
892+ printk(KERN_INFO "uvesafb: can't handle memory"
893+ " requests, pmi disabled\n");
894+ par->ypan = par->pmi_setpal = 0;
895+ }
896+ }
897+ }
898+ return 0;
899+}
900+#endif /* CONFIG_X86_32 */
901+
902+/*
903+ * Check whether a video mode is supported by the Video BIOS and is
904+ * compatible with the monitor limits.
905+ */
906+static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode,
907+ struct fb_info *info)
908+{
909+ if (info->monspecs.gtf) {
910+ fb_videomode_to_var(&info->var, mode);
911+ if (fb_validate_mode(&info->var, info))
912+ return 0;
913+ }
914+
915+ if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8,
916+ UVESAFB_EXACT_RES) == -1)
917+ return 0;
918+
919+ return 1;
920+}
921+
922+static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
923+ struct fb_info *info)
924+{
925+ struct uvesafb_par *par = info->par;
926+ int err = 0;
927+
928+ if (noedid || par->vbe_ib.vbe_version < 0x0300)
929+ return -EINVAL;
930+
931+ task->t.regs.eax = 0x4f15;
932+ task->t.regs.ebx = 0;
933+ task->t.regs.ecx = 0;
934+ task->t.buf_len = 0;
935+ task->t.flags = 0;
936+
937+ err = uvesafb_exec(task);
938+
939+ if ((task->t.regs.eax & 0xffff) != 0x004f || err)
940+ return -EINVAL;
941+
942+ if ((task->t.regs.ebx & 0x3) == 3) {
943+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports both "
944+ "DDC1 and DDC2 transfers\n");
945+ } else if ((task->t.regs.ebx & 0x3) == 2) {
946+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 "
947+ "transfers\n");
948+ } else if ((task->t.regs.ebx & 0x3) == 1) {
949+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 "
950+ "transfers\n");
951+ } else {
952+ printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support "
953+ "DDC transfers\n");
954+ return -EINVAL;
955+ }
956+
957+ task->t.regs.eax = 0x4f15;
958+ task->t.regs.ebx = 1;
959+ task->t.regs.ecx = task->t.regs.edx = 0;
960+ task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
961+ task->t.buf_len = EDID_LENGTH;
962+ task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL);
963+
964+ err = uvesafb_exec(task);
965+
966+ if ((task->t.regs.eax & 0xffff) == 0x004f && !err) {
967+ fb_edid_to_monspecs(task->buf, &info->monspecs);
968+
969+ if (info->monspecs.vfmax && info->monspecs.hfmax) {
970+ /*
971+ * If the maximum pixel clock wasn't specified in
972+ * the EDID block, set it to 300 MHz.
973+ */
974+ if (info->monspecs.dclkmax == 0)
975+ info->monspecs.dclkmax = 300 * 1000000;
976+ info->monspecs.gtf = 1;
977+ }
978+ } else {
979+ err = -EINVAL;
980+ }
981+
982+ kfree(task->buf);
983+ return err;
984+}
985+
986+static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
987+ struct fb_info *info)
988+{
989+ struct uvesafb_par *par = info->par;
990+ int i;
991+
992+ memset(&info->monspecs, 0, sizeof(info->monspecs));
993+
994+ /*
995+ * If we don't get all necessary data from the EDID block,
996+ * mark it as incompatible with the GTF and set nocrtc so
997+ * that we always use the default BIOS refresh rate.
998+ */
999+ if (uvesafb_vbe_getedid(task, info)) {
1000+ info->monspecs.gtf = 0;
1001+ par->nocrtc = 1;
1002+ }
1003+
1004+ /* Kernel command line overrides. */
1005+ if (maxclk)
1006+ info->monspecs.dclkmax = maxclk * 1000000;
1007+ if (maxvf)
1008+ info->monspecs.vfmax = maxvf;
1009+ if (maxhf)
1010+ info->monspecs.hfmax = maxhf * 1000;
1011+
1012+ /*
1013+ * In case DDC transfers are not supported, the user can provide
1014+ * monitor limits manually. Lower limits are set to "safe" values.
1015+ */
1016+ if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) {
1017+ info->monspecs.dclkmin = 0;
1018+ info->monspecs.vfmin = 60;
1019+ info->monspecs.hfmin = 29000;
1020+ info->monspecs.gtf = 1;
1021+ par->nocrtc = 0;
1022+ }
1023+
1024+ if (info->monspecs.gtf)
1025+ printk(KERN_INFO
1026+ "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, "
1027+ "clk = %d MHz\n", info->monspecs.vfmax,
1028+ (int)(info->monspecs.hfmax / 1000),
1029+ (int)(info->monspecs.dclkmax / 1000000));
1030+ else
1031+ printk(KERN_INFO "uvesafb: no monitor limits have been set, "
1032+ "default refresh rate will be used\n");
1033+
1034+ /* Add VBE modes to the modelist. */
1035+ for (i = 0; i < par->vbe_modes_cnt; i++) {
1036+ struct fb_var_screeninfo var;
1037+ struct vbe_mode_ib *mode;
1038+ struct fb_videomode vmode;
1039+
1040+ mode = &par->vbe_modes[i];
1041+ memset(&var, 0, sizeof(var));
1042+
1043+ var.xres = mode->x_res;
1044+ var.yres = mode->y_res;
1045+
1046+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info);
1047+ fb_var_to_videomode(&vmode, &var);
1048+ fb_add_videomode(&vmode, &info->modelist);
1049+ }
1050+
1051+ /* Add valid VESA modes to our modelist. */
1052+ for (i = 0; i < VESA_MODEDB_SIZE; i++) {
1053+ if (uvesafb_is_valid_mode((struct fb_videomode *)
1054+ &vesa_modes[i], info))
1055+ fb_add_videomode(&vesa_modes[i], &info->modelist);
1056+ }
1057+
1058+ for (i = 0; i < info->monspecs.modedb_len; i++) {
1059+ if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info))
1060+ fb_add_videomode(&info->monspecs.modedb[i],
1061+ &info->modelist);
1062+ }
1063+
1064+ return;
1065+}
1066+
1067+static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
1068+ struct uvesafb_par *par)
1069+{
1070+ int err;
1071+
1072+ uvesafb_reset(task);
1073+
1074+ /*
1075+ * Get the VBE state buffer size. We want all available
1076+ * hardware state data (CL = 0x0f).
1077+ */
1078+ task->t.regs.eax = 0x4f04;
1079+ task->t.regs.ecx = 0x000f;
1080+ task->t.regs.edx = 0x0000;
1081+ task->t.flags = 0;
1082+
1083+ err = uvesafb_exec(task);
1084+
1085+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
1086+ printk(KERN_WARNING "uvesafb: VBE state buffer size "
1087+ "cannot be determined (eax=0x%x, err=%d)\n",
1088+ task->t.regs.eax, err);
1089+ par->vbe_state_size = 0;
1090+ return;
1091+ }
1092+
1093+ par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff);
1094+}
1095+
1096+static int __devinit uvesafb_vbe_init(struct fb_info *info)
1097+{
1098+ struct uvesafb_ktask *task = NULL;
1099+ struct uvesafb_par *par = info->par;
1100+ int err;
1101+
1102+ task = uvesafb_prep();
1103+ if (!task)
1104+ return -ENOMEM;
1105+
1106+ err = uvesafb_vbe_getinfo(task, par);
1107+ if (err)
1108+ goto out;
1109+
1110+ err = uvesafb_vbe_getmodes(task, par);
1111+ if (err)
1112+ goto out;
1113+
1114+ par->nocrtc = nocrtc;
1115+#ifdef CONFIG_X86_32
1116+ par->pmi_setpal = pmi_setpal;
1117+ par->ypan = ypan;
1118+
1119+ if (par->pmi_setpal || par->ypan)
1120+ uvesafb_vbe_getpmi(task, par);
1121+#else
1122+ /* The protected mode interface is not available on non-x86. */
1123+ par->pmi_setpal = par->ypan = 0;
1124+#endif
1125+
1126+ INIT_LIST_HEAD(&info->modelist);
1127+ uvesafb_vbe_getmonspecs(task, info);
1128+ uvesafb_vbe_getstatesize(task, par);
1129+
1130+out: uvesafb_free(task);
1131+ return err;
1132+}
1133+
1134+static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
1135+{
1136+ struct list_head *pos;
1137+ struct fb_modelist *modelist;
1138+ struct fb_videomode *mode;
1139+ struct uvesafb_par *par = info->par;
1140+ int i, modeid;
1141+
1142+ /* Has the user requested a specific VESA mode? */
1143+ if (vbemode) {
1144+ for (i = 0; i < par->vbe_modes_cnt; i++) {
1145+ if (par->vbe_modes[i].mode_id == vbemode) {
1146+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
1147+ &info->var, info);
1148+ /*
1149+ * With pixclock set to 0, the default BIOS
1150+ * timings will be used in set_par().
1151+ */
1152+ info->var.pixclock = 0;
1153+ modeid = i;
1154+ goto gotmode;
1155+ }
1156+ }
1157+ printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is "
1158+ "unavailable\n", vbemode);
1159+ vbemode = 0;
1160+ }
1161+
1162+ /* Count the modes in the modelist */
1163+ i = 0;
1164+ list_for_each(pos, &info->modelist)
1165+ i++;
1166+
1167+ /*
1168+ * Convert the modelist into a modedb so that we can use it with
1169+ * fb_find_mode().
1170+ */
1171+ mode = kzalloc(i * sizeof(*mode), GFP_KERNEL);
1172+ if (mode) {
1173+ i = 0;
1174+ list_for_each(pos, &info->modelist) {
1175+ modelist = list_entry(pos, struct fb_modelist, list);
1176+ mode[i] = modelist->mode;
1177+ i++;
1178+ }
1179+
1180+ if (!mode_option)
1181+ mode_option = UVESAFB_DEFAULT_MODE;
1182+
1183+ i = fb_find_mode(&info->var, info, mode_option, mode, i,
1184+ NULL, 8);
1185+
1186+ kfree(mode);
1187+ }
1188+
1189+ /* fb_find_mode() failed */
1190+ if (i == 0 || i >= 3) {
1191+ info->var.xres = 640;
1192+ info->var.yres = 480;
1193+ mode = (struct fb_videomode *)
1194+ fb_find_best_mode(&info->var, &info->modelist);
1195+
1196+ if (mode) {
1197+ fb_videomode_to_var(&info->var, mode);
1198+ } else {
1199+ modeid = par->vbe_modes[0].mode_id;
1200+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
1201+ &info->var, info);
1202+ goto gotmode;
1203+ }
1204+ }
1205+
1206+ /* Look for a matching VBE mode. */
1207+ modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres,
1208+ info->var.bits_per_pixel, UVESAFB_EXACT_RES);
1209+
1210+ if (modeid == -1)
1211+ return -EINVAL;
1212+
1213+gotmode:
1214+ uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]);
1215+
1216+ /*
1217+ * If we are not VBE3.0+ compliant, we're done -- the BIOS will
1218+ * ignore our timings anyway.
1219+ */
1220+ if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc)
1221+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
1222+ &info->var, info);
1223+
1224+ return modeid;
1225+}
1226+
1227+static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count,
1228+ int start, struct fb_info *info)
1229+{
1230+ struct uvesafb_ktask *task;
1231+ struct uvesafb_par *par = info->par;
1232+ int i = par->mode_idx;
1233+ int err = 0;
1234+
1235+ /*
1236+ * We support palette modifications for 8 bpp modes only, so
1237+ * there can never be more than 256 entries.
1238+ */
1239+ if (start + count > 256)
1240+ return -EINVAL;
1241+
1242+ /* Use VGA registers if mode is VGA-compatible. */
1243+ if (i >= 0 && i < par->vbe_modes_cnt &&
1244+ par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) {
1245+ for (i = 0; i < count; i++) {
1246+ outb_p(start + i, dac_reg);
1247+ outb_p(entries[i].red, dac_val);
1248+ outb_p(entries[i].green, dac_val);
1249+ outb_p(entries[i].blue, dac_val);
1250+ }
1251+ }
1252+#ifdef CONFIG_X86_32
1253+ else if (par->pmi_setpal) {
1254+ __asm__ __volatile__(
1255+ "call *(%%esi)"
1256+ : /* no return value */
1257+ : "a" (0x4f09), /* EAX */
1258+ "b" (0), /* EBX */
1259+ "c" (count), /* ECX */
1260+ "d" (start), /* EDX */
1261+ "D" (entries), /* EDI */
1262+ "S" (&par->pmi_pal)); /* ESI */
1263+ }
1264+#endif
1265+ else {
1266+ task = uvesafb_prep();
1267+ if (!task)
1268+ return -ENOMEM;
1269+
1270+ task->t.regs.eax = 0x4f09;
1271+ task->t.regs.ebx = 0x0;
1272+ task->t.regs.ecx = count;
1273+ task->t.regs.edx = start;
1274+ task->t.flags = TF_BUF_ESDI;
1275+ task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count;
1276+ task->buf = entries;
1277+
1278+ err = uvesafb_exec(task);
1279+ if ((task->t.regs.eax & 0xffff) != 0x004f)
1280+ err = 1;
1281+
1282+ uvesafb_free(task);
1283+ }
1284+ return err;
1285+}
1286+
1287+static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
1288+ unsigned blue, unsigned transp,
1289+ struct fb_info *info)
1290+{
1291+ struct uvesafb_pal_entry entry;
1292+ int shift = 16 - info->var.green.length;
1293+ int err = 0;
1294+
1295+ if (regno >= info->cmap.len)
1296+ return -EINVAL;
1297+
1298+ if (info->var.bits_per_pixel == 8) {
1299+ entry.red = red >> shift;
1300+ entry.green = green >> shift;
1301+ entry.blue = blue >> shift;
1302+ entry.pad = 0;
1303+
1304+ err = uvesafb_setpalette(&entry, 1, regno, info);
1305+ } else if (regno < 16) {
1306+ switch (info->var.bits_per_pixel) {
1307+ case 16:
1308+ if (info->var.red.offset == 10) {
1309+ /* 1:5:5:5 */
1310+ ((u32 *) (info->pseudo_palette))[regno] =
1311+ ((red & 0xf800) >> 1) |
1312+ ((green & 0xf800) >> 6) |
1313+ ((blue & 0xf800) >> 11);
1314+ } else {
1315+ /* 0:5:6:5 */
1316+ ((u32 *) (info->pseudo_palette))[regno] =
1317+ ((red & 0xf800) ) |
1318+ ((green & 0xfc00) >> 5) |
1319+ ((blue & 0xf800) >> 11);
1320+ }
1321+ break;
1322+
1323+ case 24:
1324+ case 32:
1325+ red >>= 8;
1326+ green >>= 8;
1327+ blue >>= 8;
1328+ ((u32 *)(info->pseudo_palette))[regno] =
1329+ (red << info->var.red.offset) |
1330+ (green << info->var.green.offset) |
1331+ (blue << info->var.blue.offset);
1332+ break;
1333+ }
1334+ }
1335+ return err;
1336+}
1337+
1338+static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1339+{
1340+ struct uvesafb_pal_entry *entries;
1341+ int shift = 16 - info->var.green.length;
1342+ int i, err = 0;
1343+
1344+ if (info->var.bits_per_pixel == 8) {
1345+ if (cmap->start + cmap->len > info->cmap.start +
1346+ info->cmap.len || cmap->start < info->cmap.start)
1347+ return -EINVAL;
1348+
1349+ entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL);
1350+ if (!entries)
1351+ return -ENOMEM;
1352+
1353+ for (i = 0; i < cmap->len; i++) {
1354+ entries[i].red = cmap->red[i] >> shift;
1355+ entries[i].green = cmap->green[i] >> shift;
1356+ entries[i].blue = cmap->blue[i] >> shift;
1357+ entries[i].pad = 0;
1358+ }
1359+ err = uvesafb_setpalette(entries, cmap->len, cmap->start, info);
1360+ kfree(entries);
1361+ } else {
1362+ /*
1363+ * For modes with bpp > 8, we only set the pseudo palette in
1364+ * the fb_info struct. We rely on uvesafb_setcolreg to do all
1365+ * sanity checking.
1366+ */
1367+ for (i = 0; i < cmap->len; i++) {
1368+ err |= uvesafb_setcolreg(cmap->start + i, cmap->red[i],
1369+ cmap->green[i], cmap->blue[i],
1370+ 0, info);
1371+ }
1372+ }
1373+ return err;
1374+}
1375+
1376+static int uvesafb_pan_display(struct fb_var_screeninfo *var,
1377+ struct fb_info *info)
1378+{
1379+#ifdef CONFIG_X86_32
1380+ int offset;
1381+ struct uvesafb_par *par = info->par;
1382+
1383+ offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
1384+
1385+ /*
1386+ * It turns out it's not the best idea to do panning via vm86,
1387+ * so we only allow it if we have a PMI.
1388+ */
1389+ if (par->pmi_start) {
1390+ __asm__ __volatile__(
1391+ "call *(%%edi)"
1392+ : /* no return value */
1393+ : "a" (0x4f07), /* EAX */
1394+ "b" (0), /* EBX */
1395+ "c" (offset), /* ECX */
1396+ "d" (offset >> 16), /* EDX */
1397+ "D" (&par->pmi_start)); /* EDI */
1398+ }
1399+#endif
1400+ return 0;
1401+}
1402+
1403+static int uvesafb_blank(int blank, struct fb_info *info)
1404+{
1405+ struct uvesafb_par *par = info->par;
1406+ struct uvesafb_ktask *task;
1407+ int err = 1;
1408+
1409+ if (par->vbe_ib.capabilities & VBE_CAP_VGACOMPAT) {
1410+ int loop = 10000;
1411+ u8 seq = 0, crtc17 = 0;
1412+
1413+ if (blank == FB_BLANK_POWERDOWN) {
1414+ seq = 0x20;
1415+ crtc17 = 0x00;
1416+ err = 0;
1417+ } else {
1418+ seq = 0x00;
1419+ crtc17 = 0x80;
1420+ err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL;
1421+ }
1422+
1423+ vga_wseq(NULL, 0x00, 0x01);
1424+ seq |= vga_rseq(NULL, 0x01) & ~0x20;
1425+ vga_wseq(NULL, 0x00, seq);
1426+
1427+ crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80;
1428+ while (loop--);
1429+ vga_wcrt(NULL, 0x17, crtc17);
1430+ vga_wseq(NULL, 0x00, 0x03);
1431+ } else {
1432+ task = uvesafb_prep();
1433+ if (!task)
1434+ return -ENOMEM;
1435+
1436+ task->t.regs.eax = 0x4f10;
1437+ switch (blank) {
1438+ case FB_BLANK_UNBLANK:
1439+ task->t.regs.ebx = 0x0001;
1440+ break;
1441+ case FB_BLANK_NORMAL:
1442+ task->t.regs.ebx = 0x0101; /* standby */
1443+ break;
1444+ case FB_BLANK_POWERDOWN:
1445+ task->t.regs.ebx = 0x0401; /* powerdown */
1446+ break;
1447+ default:
1448+ goto out;
1449+ }
1450+
1451+ err = uvesafb_exec(task);
1452+ if (err || (task->t.regs.eax & 0xffff) != 0x004f)
1453+ err = 1;
1454+out: uvesafb_free(task);
1455+ }
1456+ return err;
1457+}
1458+
1459+static int uvesafb_open(struct fb_info *info, int user)
1460+{
1461+ struct uvesafb_par *par = info->par;
1462+ int cnt = atomic_read(&par->ref_count);
1463+
1464+ if (!cnt && par->vbe_state_size)
1465+ par->vbe_state_orig = uvesafb_vbe_state_save(par);
1466+
1467+ atomic_inc(&par->ref_count);
1468+ return 0;
1469+}
1470+
1471+static int uvesafb_release(struct fb_info *info, int user)
1472+{
1473+ struct uvesafb_ktask *task = NULL;
1474+ struct uvesafb_par *par = info->par;
1475+ int cnt = atomic_read(&par->ref_count);
1476+
1477+ if (!cnt)
1478+ return -EINVAL;
1479+
1480+ if (cnt != 1)
1481+ goto out;
1482+
1483+ task = uvesafb_prep();
1484+ if (!task)
1485+ goto out;
1486+
1487+ /* First, try to set the standard 80x25 text mode. */
1488+ task->t.regs.eax = 0x0003;
1489+ uvesafb_exec(task);
1490+
1491+ /*
1492+ * Now try to restore whatever hardware state we might have
1493+ * saved when the fb device was first opened.
1494+ */
1495+ uvesafb_vbe_state_restore(par, par->vbe_state_orig);
1496+out:
1497+ atomic_dec(&par->ref_count);
1498+ if (task)
1499+ uvesafb_free(task);
1500+ return 0;
1501+}
1502+
1503+static int uvesafb_set_par(struct fb_info *info)
1504+{
1505+ struct uvesafb_par *par = info->par;
1506+ struct uvesafb_ktask *task = NULL;
1507+ struct vbe_crtc_ib *crtc = NULL;
1508+ struct vbe_mode_ib *mode = NULL;
1509+ int i, err = 0, depth = info->var.bits_per_pixel;
1510+
1511+ if (depth > 8 && depth != 32)
1512+ depth = info->var.red.length + info->var.green.length +
1513+ info->var.blue.length;
1514+
1515+ i = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, depth,
1516+ UVESAFB_EXACT_RES | UVESAFB_EXACT_DEPTH);
1517+ if (i >= 0)
1518+ mode = &par->vbe_modes[i];
1519+ else
1520+ return -EINVAL;
1521+
1522+ task = uvesafb_prep();
1523+ if (!task)
1524+ return -ENOMEM;
1525+setmode:
1526+ task->t.regs.eax = 0x4f02;
1527+ task->t.regs.ebx = mode->mode_id | 0x4000; /* use LFB */
1528+
1529+ if (par->vbe_ib.vbe_version >= 0x0300 && !par->nocrtc &&
1530+ info->var.pixclock != 0) {
1531+ task->t.regs.ebx |= 0x0800; /* use CRTC data */
1532+ task->t.flags = TF_BUF_ESDI;
1533+ crtc = kzalloc(sizeof(struct vbe_crtc_ib), GFP_KERNEL);
1534+ if (!crtc) {
1535+ err = -ENOMEM;
1536+ goto out;
1537+ }
1538+ crtc->horiz_start = info->var.xres + info->var.right_margin;
1539+ crtc->horiz_end = crtc->horiz_start + info->var.hsync_len;
1540+ crtc->horiz_total = crtc->horiz_end + info->var.left_margin;
1541+
1542+ crtc->vert_start = info->var.yres + info->var.lower_margin;
1543+ crtc->vert_end = crtc->vert_start + info->var.vsync_len;
1544+ crtc->vert_total = crtc->vert_end + info->var.upper_margin;
1545+
1546+ crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000;
1547+ crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock /
1548+ (crtc->vert_total * crtc->horiz_total)));
1549+
1550+ if (info->var.vmode & FB_VMODE_DOUBLE)
1551+ crtc->flags |= 0x1;
1552+ if (info->var.vmode & FB_VMODE_INTERLACED)
1553+ crtc->flags |= 0x2;
1554+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
1555+ crtc->flags |= 0x4;
1556+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
1557+ crtc->flags |= 0x8;
1558+ memcpy(&par->crtc, crtc, sizeof(*crtc));
1559+ } else {
1560+ memset(&par->crtc, 0, sizeof(*crtc));
1561+ }
1562+
1563+ task->t.buf_len = sizeof(struct vbe_crtc_ib);
1564+ task->buf = &par->crtc;
1565+
1566+ err = uvesafb_exec(task);
1567+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
1568+ /*
1569+ * The mode switch might have failed because we tried to
1570+ * use our own timings. Try again with the default timings.
1571+ */
1572+ if (crtc != NULL) {
1573+ printk(KERN_WARNING "uvesafb: mode switch failed "
1574+ "(eax=0x%x, err=%d). Trying again with "
1575+ "default timings.\n", task->t.regs.eax, err);
1576+ uvesafb_reset(task);
1577+ kfree(crtc);
1578+ crtc = NULL;
1579+ info->var.pixclock = 0;
1580+ goto setmode;
1581+ } else {
1582+ printk(KERN_ERR "uvesafb: mode switch failed (eax="
1583+ "0x%x, err=%d)\n", task->t.regs.eax, err);
1584+ err = -EINVAL;
1585+ goto out;
1586+ }
1587+ }
1588+ par->mode_idx = i;
1589+
1590+ /* For 8bpp modes, always try to set the DAC to 8 bits. */
1591+ if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC &&
1592+ mode->bits_per_pixel <= 8) {
1593+ uvesafb_reset(task);
1594+ task->t.regs.eax = 0x4f08;
1595+ task->t.regs.ebx = 0x0800;
1596+
1597+ err = uvesafb_exec(task);
1598+ if (err || (task->t.regs.eax & 0xffff) != 0x004f ||
1599+ ((task->t.regs.ebx & 0xff00) >> 8) != 8) {
1600+ /*
1601+ * We've failed to set the DAC palette format -
1602+ * time to correct var.
1603+ */
1604+ info->var.red.length = 6;
1605+ info->var.green.length = 6;
1606+ info->var.blue.length = 6;
1607+ }
1608+ }
1609+
1610+ info->fix.visual = (info->var.bits_per_pixel == 8) ?
1611+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1612+ info->fix.line_length = mode->bytes_per_scan_line;
1613+
1614+out: if (crtc != NULL)
1615+ kfree(crtc);
1616+ uvesafb_free(task);
1617+
1618+ return err;
1619+}
1620+
1621+static void uvesafb_check_limits(struct fb_var_screeninfo *var,
1622+ struct fb_info *info)
1623+{
1624+ const struct fb_videomode *mode;
1625+ struct uvesafb_par *par = info->par;
1626+
1627+ /*
1628+ * If pixclock is set to 0, then we're using default BIOS timings
1629+ * and thus don't have to perform any checks here.
1630+ */
1631+ if (!var->pixclock)
1632+ return;
1633+
1634+ if (par->vbe_ib.vbe_version < 0x0300) {
1635+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info);
1636+ return;
1637+ }
1638+
1639+ if (!fb_validate_mode(var, info))
1640+ return;
1641+
1642+ mode = fb_find_best_mode(var, &info->modelist);
1643+ if (mode) {
1644+ if (mode->xres == var->xres && mode->yres == var->yres &&
1645+ !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) {
1646+ fb_videomode_to_var(var, mode);
1647+ return;
1648+ }
1649+ }
1650+
1651+ if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
1652+ return;
1653+ /* Use default refresh rate */
1654+ var->pixclock = 0;
1655+}
1656+
1657+static int uvesafb_check_var(struct fb_var_screeninfo *var,
1658+ struct fb_info *info)
1659+{
1660+ struct uvesafb_par *par = info->par;
1661+ struct vbe_mode_ib *mode = NULL;
1662+ int match = -1;
1663+ int depth = var->red.length + var->green.length + var->blue.length;
1664+
1665+ /*
1666+ * Various apps will use bits_per_pixel to set the color depth,
1667+ * which is theoretically incorrect, but which we'll try to handle
1668+ * here.
1669+ */
1670+ if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8)
1671+ depth = var->bits_per_pixel;
1672+
1673+ match = uvesafb_vbe_find_mode(par, var->xres, var->yres, depth,
1674+ UVESAFB_EXACT_RES);
1675+ if (match == -1)
1676+ return -EINVAL;
1677+
1678+ mode = &par->vbe_modes[match];
1679+ uvesafb_setup_var(var, info, mode);
1680+
1681+ /*
1682+ * Check whether we have remapped enough memory for this mode.
1683+ * We might be called at an early stage, when we haven't remapped
1684+ * any memory yet, in which case we simply skip the check.
1685+ */
1686+ if (var->yres * mode->bytes_per_scan_line > info->fix.smem_len
1687+ && info->fix.smem_len)
1688+ return -EINVAL;
1689+
1690+ if ((var->vmode & FB_VMODE_DOUBLE) &&
1691+ !(par->vbe_modes[match].mode_attr & 0x100))
1692+ var->vmode &= ~FB_VMODE_DOUBLE;
1693+
1694+ if ((var->vmode & FB_VMODE_INTERLACED) &&
1695+ !(par->vbe_modes[match].mode_attr & 0x200))
1696+ var->vmode &= ~FB_VMODE_INTERLACED;
1697+
1698+ uvesafb_check_limits(var, info);
1699+
1700+ var->xres_virtual = var->xres;
1701+ var->yres_virtual = (par->ypan) ?
1702+ info->fix.smem_len / mode->bytes_per_scan_line :
1703+ var->yres;
1704+ return 0;
1705+}
1706+
1707+static void uvesafb_save_state(struct fb_info *info)
1708+{
1709+ struct uvesafb_par *par = info->par;
1710+
1711+ if (par->vbe_state_saved)
1712+ kfree(par->vbe_state_saved);
1713+
1714+ par->vbe_state_saved = uvesafb_vbe_state_save(par);
1715+}
1716+
1717+static void uvesafb_restore_state(struct fb_info *info)
1718+{
1719+ struct uvesafb_par *par = info->par;
1720+
1721+ uvesafb_vbe_state_restore(par, par->vbe_state_saved);
1722+}
1723+
1724+static struct fb_ops uvesafb_ops = {
1725+ .owner = THIS_MODULE,
1726+ .fb_open = uvesafb_open,
1727+ .fb_release = uvesafb_release,
1728+ .fb_setcolreg = uvesafb_setcolreg,
1729+ .fb_setcmap = uvesafb_setcmap,
1730+ .fb_pan_display = uvesafb_pan_display,
1731+ .fb_blank = uvesafb_blank,
1732+ .fb_fillrect = cfb_fillrect,
1733+ .fb_copyarea = cfb_copyarea,
1734+ .fb_imageblit = cfb_imageblit,
1735+ .fb_check_var = uvesafb_check_var,
1736+ .fb_set_par = uvesafb_set_par,
1737+ .fb_save_state = uvesafb_save_state,
1738+ .fb_restore_state = uvesafb_restore_state,
1739+};
1740+
1741+static void __devinit uvesafb_init_info(struct fb_info *info,
1742+ struct vbe_mode_ib *mode)
1743+{
1744+ unsigned int size_vmode;
1745+ unsigned int size_remap;
1746+ unsigned int size_total;
1747+ struct uvesafb_par *par = info->par;
1748+ int i, h;
1749+
1750+ info->pseudo_palette = ((u8 *)info->par + sizeof(struct uvesafb_par));
1751+ info->fix = uvesafb_fix;
1752+ info->fix.ypanstep = par->ypan ? 1 : 0;
1753+ info->fix.ywrapstep = (par->ypan > 1) ? 1 : 0;
1754+
1755+ /*
1756+ * If we were unable to get the state buffer size, disable
1757+ * functions for saving and restoring the hardware state.
1758+ */
1759+ if (par->vbe_state_size == 0) {
1760+ info->fbops->fb_save_state = NULL;
1761+ info->fbops->fb_restore_state = NULL;
1762+ }
1763+
1764+ /* Disable blanking if the user requested so. */
1765+ if (!blank)
1766+ info->fbops->fb_blank = NULL;
1767+
1768+ /*
1769+ * Find out how much IO memory is required for the mode with
1770+ * the highest resolution.
1771+ */
1772+ size_remap = 0;
1773+ for (i = 0; i < par->vbe_modes_cnt; i++) {
1774+ h = par->vbe_modes[i].bytes_per_scan_line *
1775+ par->vbe_modes[i].y_res;
1776+ if (h > size_remap)
1777+ size_remap = h;
1778+ }
1779+ size_remap *= 2;
1780+
1781+ /*
1782+ * size_vmode -- that is the amount of memory needed for the
1783+ * used video mode, i.e. the minimum amount of
1784+ * memory we need.
1785+ */
1786+ if (mode != NULL) {
1787+ size_vmode = info->var.yres * mode->bytes_per_scan_line;
1788+ } else {
1789+ size_vmode = info->var.yres * info->var.xres *
1790+ ((info->var.bits_per_pixel + 7) >> 3);
1791+ }
1792+
1793+ /*
1794+ * size_total -- all video memory we have. Used for mtrr
1795+ * entries, resource allocation and bounds
1796+ * checking.
1797+ */
1798+ size_total = par->vbe_ib.total_memory * 65536;
1799+ if (vram_total)
1800+ size_total = vram_total * 1024 * 1024;
1801+ if (size_total < size_vmode)
1802+ size_total = size_vmode;
1803+
1804+ /*
1805+ * size_remap -- the amount of video memory we are going to
1806+ * use for vesafb. With modern cards it is no
1807+ * option to simply use size_total as th
1808+ * wastes plenty of kernel address space.
1809+ */
1810+ if (vram_remap)
1811+ size_remap = vram_remap * 1024 * 1024;
1812+ if (size_remap < size_vmode)
1813+ size_remap = size_vmode;
1814+ if (size_remap > size_total)
1815+ size_remap = size_total;
1816+
1817+ info->fix.smem_len = size_remap;
1818+ info->fix.smem_start = mode->phys_base_ptr;
1819+
1820+ /*
1821+ * We have to set yres_virtual here because when setup_var() was
1822+ * called, smem_len wasn't defined yet.
1823+ */
1824+ info->var.yres_virtual = info->fix.smem_len /
1825+ mode->bytes_per_scan_line;
1826+
1827+ if (par->ypan && info->var.yres_virtual > info->var.yres) {
1828+ printk(KERN_INFO "uvesafb: scrolling: %s "
1829+ "using protected mode interface, "
1830+ "yres_virtual=%d\n",
1831+ (par->ypan > 1) ? "ywrap" : "ypan",
1832+ info->var.yres_virtual);
1833+ } else {
1834+ printk(KERN_INFO "uvesafb: scrolling: redraw\n");
1835+ info->var.yres_virtual = info->var.yres;
1836+ par->ypan = 0;
1837+ }
1838+
1839+ info->flags = FBINFO_FLAG_DEFAULT |
1840+ (par->ypan) ? FBINFO_HWACCEL_YPAN : 0;
1841+
1842+ if (!par->ypan)
1843+ info->fbops->fb_pan_display = NULL;
1844+}
1845+
1846+static void uvesafb_init_mtrr(struct fb_info *info)
1847+{
1848+#ifdef CONFIG_MTRR
1849+ if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) {
1850+ int temp_size = info->fix.smem_len;
1851+ unsigned int type = 0;
1852+
1853+ switch (mtrr) {
1854+ case 1:
1855+ type = MTRR_TYPE_UNCACHABLE;
1856+ break;
1857+ case 2:
1858+ type = MTRR_TYPE_WRBACK;
1859+ break;
1860+ case 3:
1861+ type = MTRR_TYPE_WRCOMB;
1862+ break;
1863+ case 4:
1864+ type = MTRR_TYPE_WRTHROUGH;
1865+ break;
1866+ default:
1867+ type = 0;
1868+ break;
1869+ }
1870+
1871+ if (type) {
1872+ int rc;
1873+
1874+ /* Find the largest power-of-two */
1875+ while (temp_size & (temp_size - 1))
1876+ temp_size &= (temp_size - 1);
1877+
1878+ /* Try and find a power of two to add */
1879+ do {
1880+ rc = mtrr_add(info->fix.smem_start,
1881+ temp_size, type, 1);
1882+ temp_size >>= 1;
1883+ } while (temp_size >= PAGE_SIZE && rc == -EINVAL);
1884+ }
1885+ }
1886+#endif /* CONFIG_MTRR */
1887+}
1888+
1889+
1890+static ssize_t uvesafb_show_vbe_ver(struct device *dev,
1891+ struct device_attribute *attr, char *buf)
1892+{
1893+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1894+ struct uvesafb_par *par = info->par;
1895+
1896+ return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version);
1897+}
1898+
1899+static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL);
1900+
1901+static ssize_t uvesafb_show_vbe_modes(struct device *dev,
1902+ struct device_attribute *attr, char *buf)
1903+{
1904+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1905+ struct uvesafb_par *par = info->par;
1906+ int ret = 0, i;
1907+
1908+ for (i = 0; i < par->vbe_modes_cnt && ret < PAGE_SIZE; i++) {
1909+ ret += snprintf(buf + ret, PAGE_SIZE - ret,
1910+ "%dx%d-%d, 0x%.4x\n",
1911+ par->vbe_modes[i].x_res, par->vbe_modes[i].y_res,
1912+ par->vbe_modes[i].depth, par->vbe_modes[i].mode_id);
1913+ }
1914+
1915+ return ret;
1916+}
1917+
1918+static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL);
1919+
1920+static ssize_t uvesafb_show_vendor(struct device *dev,
1921+ struct device_attribute *attr, char *buf)
1922+{
1923+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1924+ struct uvesafb_par *par = info->par;
1925+
1926+ if (par->vbe_ib.oem_vendor_name_ptr)
1927+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
1928+ (&par->vbe_ib) + par->vbe_ib.oem_vendor_name_ptr);
1929+ else
1930+ return 0;
1931+}
1932+
1933+static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL);
1934+
1935+static ssize_t uvesafb_show_product_name(struct device *dev,
1936+ struct device_attribute *attr, char *buf)
1937+{
1938+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1939+ struct uvesafb_par *par = info->par;
1940+
1941+ if (par->vbe_ib.oem_product_name_ptr)
1942+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
1943+ (&par->vbe_ib) + par->vbe_ib.oem_product_name_ptr);
1944+ else
1945+ return 0;
1946+}
1947+
1948+static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL);
1949+
1950+static ssize_t uvesafb_show_product_rev(struct device *dev,
1951+ struct device_attribute *attr, char *buf)
1952+{
1953+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1954+ struct uvesafb_par *par = info->par;
1955+
1956+ if (par->vbe_ib.oem_product_rev_ptr)
1957+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
1958+ (&par->vbe_ib) + par->vbe_ib.oem_product_rev_ptr);
1959+ else
1960+ return 0;
1961+}
1962+
1963+static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL);
1964+
1965+static ssize_t uvesafb_show_oem_string(struct device *dev,
1966+ struct device_attribute *attr, char *buf)
1967+{
1968+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1969+ struct uvesafb_par *par = info->par;
1970+
1971+ if (par->vbe_ib.oem_string_ptr)
1972+ return snprintf(buf, PAGE_SIZE, "%s\n",
1973+ (char *)(&par->vbe_ib) + par->vbe_ib.oem_string_ptr);
1974+ else
1975+ return 0;
1976+}
1977+
1978+static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL);
1979+
1980+static ssize_t uvesafb_show_nocrtc(struct device *dev,
1981+ struct device_attribute *attr, char *buf)
1982+{
1983+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1984+ struct uvesafb_par *par = info->par;
1985+
1986+ return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc);
1987+}
1988+
1989+static ssize_t uvesafb_store_nocrtc(struct device *dev,
1990+ struct device_attribute *attr, const char *buf, size_t count)
1991+{
1992+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
1993+ struct uvesafb_par *par = info->par;
1994+
1995+ if (count > 0) {
1996+ if (buf[0] == '0')
1997+ par->nocrtc = 0;
1998+ else
1999+ par->nocrtc = 1;
2000+ }
2001+ return count;
2002+}
2003+
2004+static DEVICE_ATTR(nocrtc, S_IRUGO | S_IWUSR, uvesafb_show_nocrtc,
2005+ uvesafb_store_nocrtc);
2006+
2007+static struct attribute *uvesafb_dev_attrs[] = {
2008+ &dev_attr_vbe_version.attr,
2009+ &dev_attr_vbe_modes.attr,
2010+ &dev_attr_oem_vendor.attr,
2011+ &dev_attr_oem_product_name.attr,
2012+ &dev_attr_oem_product_rev.attr,
2013+ &dev_attr_oem_string.attr,
2014+ &dev_attr_nocrtc.attr,
2015+ NULL,
2016+};
2017+
2018+static struct attribute_group uvesafb_dev_attgrp = {
2019+ .name = NULL,
2020+ .attrs = uvesafb_dev_attrs,
2021+};
2022+
2023+static int __devinit uvesafb_probe(struct platform_device *dev)
2024+{
2025+ struct fb_info *info;
2026+ struct vbe_mode_ib *mode = NULL;
2027+ struct uvesafb_par *par;
2028+ int err = 0, i;
2029+
2030+ info = framebuffer_alloc(sizeof(*par) + sizeof(u32) * 256, &dev->dev);
2031+ if (!info)
2032+ return -ENOMEM;
2033+
2034+ par = info->par;
2035+
2036+ err = uvesafb_vbe_init(info);
2037+ if (err) {
2038+ printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err);
2039+ goto out;
2040+ }
2041+
2042+ info->fbops = &uvesafb_ops;
2043+
2044+ i = uvesafb_vbe_init_mode(info);
2045+ if (i < 0) {
2046+ err = -EINVAL;
2047+ goto out;
2048+ } else {
2049+ mode = &par->vbe_modes[i];
2050+ }
2051+
2052+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
2053+ err = -ENXIO;
2054+ goto out;
2055+ }
2056+
2057+ uvesafb_init_info(info, mode);
2058+
2059+ if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
2060+ "uvesafb")) {
2061+ printk(KERN_ERR "uvesafb: cannot reserve video memory at "
2062+ "0x%lx\n", info->fix.smem_start);
2063+ err = -EIO;
2064+ goto out_mode;
2065+ }
2066+
2067+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
2068+
2069+ if (!info->screen_base) {
2070+ printk(KERN_ERR
2071+ "uvesafb: abort, cannot ioremap 0x%x bytes of video "
2072+ "memory at 0x%lx\n",
2073+ info->fix.smem_len, info->fix.smem_start);
2074+ err = -EIO;
2075+ goto out_mem;
2076+ }
2077+
2078+ if (!request_region(0x3c0, 32, "uvesafb")) {
2079+ printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
2080+ err = -EIO;
2081+ goto out_unmap;
2082+ }
2083+
2084+ uvesafb_init_mtrr(info);
2085+ platform_set_drvdata(dev, info);
2086+
2087+ if (register_framebuffer(info) < 0) {
2088+ printk(KERN_ERR
2089+ "uvesafb: failed to register framebuffer device\n");
2090+ err = -EINVAL;
2091+ goto out_reg;
2092+ }
2093+
2094+ printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
2095+ "using %dk, total %dk\n", info->fix.smem_start,
2096+ info->screen_base, info->fix.smem_len/1024,
2097+ par->vbe_ib.total_memory * 64);
2098+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
2099+ info->fix.id);
2100+
2101+ err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
2102+ if (err != 0)
2103+ printk(KERN_WARNING "fb%d: failed to register attributes\n",
2104+ info->node);
2105+
2106+ return 0;
2107+
2108+out_reg:
2109+ release_region(0x3c0, 32);
2110+out_unmap:
2111+ iounmap(info->screen_base);
2112+out_mem:
2113+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
2114+out_mode:
2115+ if (!list_empty(&info->modelist))
2116+ fb_destroy_modelist(&info->modelist);
2117+ fb_destroy_modedb(info->monspecs.modedb);
2118+ fb_dealloc_cmap(&info->cmap);
2119+out:
2120+ if (par->vbe_modes)
2121+ kfree(par->vbe_modes);
2122+
2123+ framebuffer_release(info);
2124+ return err;
2125+}
2126+
2127+static int uvesafb_remove(struct platform_device *dev)
2128+{
2129+ struct fb_info *info = platform_get_drvdata(dev);
2130+
2131+ if (info) {
2132+ struct uvesafb_par *par = info->par;
2133+
2134+ sysfs_remove_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
2135+ unregister_framebuffer(info);
2136+ release_region(0x3c0, 32);
2137+ iounmap(info->screen_base);
2138+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
2139+ fb_destroy_modedb(info->monspecs.modedb);
2140+ fb_dealloc_cmap(&info->cmap);
2141+
2142+ if (par) {
2143+ if (par->vbe_modes)
2144+ kfree(par->vbe_modes);
2145+ if (par->vbe_state_orig)
2146+ kfree(par->vbe_state_orig);
2147+ if (par->vbe_state_saved)
2148+ kfree(par->vbe_state_saved);
2149+ }
2150+
2151+ framebuffer_release(info);
2152+ }
2153+ return 0;
2154+}
2155+
2156+static struct platform_driver uvesafb_driver = {
2157+ .probe = uvesafb_probe,
2158+ .remove = uvesafb_remove,
2159+ .driver = {
2160+ .name = "uvesafb",
2161+ },
2162+};
2163+
2164+static struct platform_device *uvesafb_device;
2165+
2166+#ifndef MODULE
2167+static int __devinit uvesafb_setup(char *options)
2168+{
2169+ char *this_opt;
2170+
2171+ if (!options || !*options)
2172+ return 0;
2173+
2174+ while ((this_opt = strsep(&options, ",")) != NULL) {
2175+ if (!*this_opt) continue;
2176+
2177+ if (!strcmp(this_opt, "redraw"))
2178+ ypan = 0;
2179+ else if (!strcmp(this_opt, "ypan"))
2180+ ypan = 1;
2181+ else if (!strcmp(this_opt, "ywrap"))
2182+ ypan = 2;
2183+ else if (!strcmp(this_opt, "vgapal"))
2184+ pmi_setpal = 0;
2185+ else if (!strcmp(this_opt, "pmipal"))
2186+ pmi_setpal = 1;
2187+ else if (!strncmp(this_opt, "mtrr:", 5))
2188+ mtrr = simple_strtoul(this_opt+5, NULL, 0);
2189+ else if (!strcmp(this_opt, "nomtrr"))
2190+ mtrr = 0;
2191+ else if (!strcmp(this_opt, "nocrtc"))
2192+ nocrtc = 1;
2193+ else if (!strcmp(this_opt, "noedid"))
2194+ noedid = 1;
2195+ else if (!strcmp(this_opt, "noblank"))
2196+ blank = 0;
2197+ else if (!strncmp(this_opt, "vtotal:", 7))
2198+ vram_total = simple_strtoul(this_opt + 7, NULL, 0);
2199+ else if (!strncmp(this_opt, "vremap:", 7))
2200+ vram_remap = simple_strtoul(this_opt + 7, NULL, 0);
2201+ else if (!strncmp(this_opt, "maxhf:", 6))
2202+ maxhf = simple_strtoul(this_opt + 6, NULL, 0);
2203+ else if (!strncmp(this_opt, "maxvf:", 6))
2204+ maxvf = simple_strtoul(this_opt + 6, NULL, 0);
2205+ else if (!strncmp(this_opt, "maxclk:", 7))
2206+ maxclk = simple_strtoul(this_opt + 7, NULL, 0);
2207+ else if (!strncmp(this_opt, "vbemode:", 8))
2208+ vbemode = simple_strtoul(this_opt + 8, NULL, 0);
2209+ else if (this_opt[0] >= '0' && this_opt[0] <= '9') {
2210+ mode_option = this_opt;
2211+ } else {
2212+ printk(KERN_WARNING
2213+ "uvesafb: unrecognized option %s\n", this_opt);
2214+ }
2215+ }
2216+
2217+ return 0;
2218+}
2219+#endif /* !MODULE */
2220+
2221+static ssize_t show_v86d(struct device_driver *dev, char *buf)
2222+{
2223+ return snprintf(buf, PAGE_SIZE, "%s\n", v86d_path);
2224+}
2225+
2226+static ssize_t store_v86d(struct device_driver *dev, const char *buf,
2227+ size_t count)
2228+{
2229+ strncpy(v86d_path, buf, PATH_MAX);
2230+ return count;
2231+}
2232+
2233+static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d);
2234+
2235+static int __devinit uvesafb_init(void)
2236+{
2237+ int err;
2238+
2239+#ifndef MODULE
2240+ char *option = NULL;
2241+
2242+ if (fb_get_options("uvesafb", &option))
2243+ return -ENODEV;
2244+ uvesafb_setup(option);
2245+#endif
2246+ err = cn_add_callback(&uvesafb_cn_id, "uvesafb", uvesafb_cn_callback);
2247+ if (err)
2248+ return err;
2249+
2250+ err = platform_driver_register(&uvesafb_driver);
2251+
2252+ if (!err) {
2253+ uvesafb_device = platform_device_alloc("uvesafb", 0);
2254+ if (uvesafb_device)
2255+ err = platform_device_add(uvesafb_device);
2256+ else
2257+ err = -ENOMEM;
2258+
2259+ if (err) {
2260+ platform_device_put(uvesafb_device);
2261+ platform_driver_unregister(&uvesafb_driver);
2262+ cn_del_callback(&uvesafb_cn_id);
2263+ return err;
2264+ }
2265+
2266+ err = driver_create_file(&uvesafb_driver.driver,
2267+ &driver_attr_v86d);
2268+ if (err) {
2269+ printk(KERN_WARNING "uvesafb: failed to register "
2270+ "attributes\n");
2271+ err = 0;
2272+ }
2273+ }
2274+ return err;
2275+}
2276+
2277+module_init(uvesafb_init);
2278+
2279+static void __devexit uvesafb_exit(void)
2280+{
2281+ struct uvesafb_ktask *task;
2282+
2283+ if (v86d_started) {
2284+ task = uvesafb_prep();
2285+ if (task) {
2286+ task->t.flags = TF_EXIT;
2287+ uvesafb_exec(task);
2288+ uvesafb_free(task);
2289+ }
2290+ }
2291+
2292+ cn_del_callback(&uvesafb_cn_id);
2293+ driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d);
2294+ platform_device_unregister(uvesafb_device);
2295+ platform_driver_unregister(&uvesafb_driver);
2296+}
2297+
2298+module_exit(uvesafb_exit);
2299+
2300+static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
2301+{
2302+ return 0;
2303+}
2304+
2305+static inline int param_set_scroll(const char *val, struct kernel_param *kp)
2306+{
2307+ ypan = 0;
2308+
2309+ if (!strcmp(val, "redraw"))
2310+ ypan = 0;
2311+ else if (!strcmp(val, "ypan"))
2312+ ypan = 1;
2313+ else if (!strcmp(val, "ywrap"))
2314+ ypan = 2;
2315+
2316+ return 0;
2317+}
2318+
2319+#define param_check_scroll(name, p) __param_check(name, p, void);
2320+
2321+module_param_named(scroll, ypan, scroll, 0);
2322+MODULE_PARM_DESC(scroll,
2323+ "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
2324+module_param_named(vgapal, pmi_setpal, invbool, 0);
2325+MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
2326+module_param_named(pmipal, pmi_setpal, bool, 0);
2327+MODULE_PARM_DESC(pmipal, "Set palette using PMI calls");
2328+module_param(mtrr, uint, 0);
2329+MODULE_PARM_DESC(mtrr,
2330+ "Memory Type Range Registers setting. Use 0 to disable.");
2331+module_param(blank, bool, 0);
2332+MODULE_PARM_DESC(blank, "Enable hardware blanking");
2333+module_param(nocrtc, bool, 0);
2334+MODULE_PARM_DESC(nocrtc, "Ignore CRTC timings when setting modes");
2335+module_param(noedid, bool, 0);
2336+MODULE_PARM_DESC(noedid,
2337+ "Ignore EDID-provided monitor limits when setting modes");
2338+module_param(vram_remap, uint, 0);
2339+MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]");
2340+module_param(vram_total, uint, 0);
2341+MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]");
2342+module_param(maxclk, ushort, 0);
2343+MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data");
2344+module_param(maxhf, ushort, 0);
2345+MODULE_PARM_DESC(maxhf,
2346+ "Maximum horizontal frequency [kHz], overrides EDID data");
2347+module_param(maxvf, ushort, 0);
2348+MODULE_PARM_DESC(maxvf,
2349+ "Maximum vertical frequency [Hz], overrides EDID data");
2350+module_param_named(mode, mode_option, charp, 0);
2351+MODULE_PARM_DESC(mode,
2352+ "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
2353+module_param(vbemode, ushort, 0);
2354+MODULE_PARM_DESC(vbemode,
2355+ "VBE mode number to set, overrides the 'mode' option");
2356+module_param_string(v86d, v86d_path, PATH_MAX, 0660);
2357+MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper.");
2358+
2359+MODULE_LICENSE("GPL");
2360+MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>");
2361+MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards");
2362+
2363Index: linux-2.6.22/include/linux/connector.h
2364===================================================================
2365--- linux-2.6.22.orig/include/linux/connector.h 2007-08-28 21:54:13.000000000 +0100
2366+++ linux-2.6.22/include/linux/connector.h 2007-08-28 21:56:34.000000000 +0100
2367@@ -36,14 +36,15 @@
2368 #define CN_VAL_CIFS 0x1
2369 #define CN_W1_IDX 0x3 /* w1 communication */
2370 #define CN_W1_VAL 0x1
2371+#define CN_IDX_V86D 0x4
2372+#define CN_VAL_V86D_UVESAFB 0x1
2373
2374-
2375-#define CN_NETLINK_USERS 4
2376+#define CN_NETLINK_USERS 5
2377
2378 /*
2379 * Maximum connector's message size.
2380 */
2381-#define CONNECTOR_MAX_MSG_SIZE 1024
2382+#define CONNECTOR_MAX_MSG_SIZE 16384
2383
2384 /*
2385 * idx and val are unique identifiers which
2386Index: linux-2.6.22/include/video/Kbuild
2387===================================================================
2388--- linux-2.6.22.orig/include/video/Kbuild 2007-08-28 21:54:13.000000000 +0100
2389+++ linux-2.6.22/include/video/Kbuild 2007-08-28 21:56:34.000000000 +0100
2390@@ -1 +1 @@
2391-unifdef-y += sisfb.h
2392+unifdef-y += sisfb.h uvesafb.h
2393Index: linux-2.6.22/include/video/uvesafb.h
2394===================================================================
2395--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2396+++ linux-2.6.22/include/video/uvesafb.h 2007-08-28 21:56:34.000000000 +0100
2397@@ -0,0 +1,193 @@
2398+#ifndef _UVESAFB_H
2399+#define _UVESAFB_H
2400+
2401+struct v86_regs {
2402+ __u32 ebx;
2403+ __u32 ecx;
2404+ __u32 edx;
2405+ __u32 esi;
2406+ __u32 edi;
2407+ __u32 ebp;
2408+ __u32 eax;
2409+ __u32 eip;
2410+ __u32 eflags;
2411+ __u32 esp;
2412+ __u16 cs;
2413+ __u16 ss;
2414+ __u16 es;
2415+ __u16 ds;
2416+ __u16 fs;
2417+ __u16 gs;
2418+};
2419+
2420+/* Task flags */
2421+#define TF_VBEIB 0x01
2422+#define TF_BUF_ESDI 0x02
2423+#define TF_BUF_ESBX 0x04
2424+#define TF_BUF_RET 0x08
2425+#define TF_EXIT 0x10
2426+
2427+struct uvesafb_task {
2428+ __u8 flags;
2429+ int buf_len;
2430+ struct v86_regs regs;
2431+};
2432+
2433+/* Constants for the capabilities field
2434+ * in vbe_ib */
2435+#define VBE_CAP_CAN_SWITCH_DAC 0x01
2436+#define VBE_CAP_VGACOMPAT 0x02
2437+
2438+/* The VBE Info Block */
2439+struct vbe_ib {
2440+ char vbe_signature[4];
2441+ __u16 vbe_version;
2442+ __u32 oem_string_ptr;
2443+ __u32 capabilities;
2444+ __u32 mode_list_ptr;
2445+ __u16 total_memory;
2446+ __u16 oem_software_rev;
2447+ __u32 oem_vendor_name_ptr;
2448+ __u32 oem_product_name_ptr;
2449+ __u32 oem_product_rev_ptr;
2450+ __u8 reserved[222];
2451+ char oem_data[256];
2452+ char misc_data[512];
2453+} __attribute__ ((packed));
2454+
2455+#ifdef __KERNEL__
2456+
2457+/* VBE CRTC Info Block */
2458+struct vbe_crtc_ib {
2459+ u16 horiz_total;
2460+ u16 horiz_start;
2461+ u16 horiz_end;
2462+ u16 vert_total;
2463+ u16 vert_start;
2464+ u16 vert_end;
2465+ u8 flags;
2466+ u32 pixel_clock;
2467+ u16 refresh_rate;
2468+ u8 reserved[40];
2469+} __attribute__ ((packed));
2470+
2471+#define VBE_MODE_VGACOMPAT 0x20
2472+#define VBE_MODE_COLOR 0x08
2473+#define VBE_MODE_SUPPORTEDHW 0x01
2474+#define VBE_MODE_GRAPHICS 0x10
2475+#define VBE_MODE_LFB 0x80
2476+
2477+#define VBE_MODE_MASK (VBE_MODE_COLOR | VBE_MODE_SUPPORTEDHW | \
2478+ VBE_MODE_GRAPHICS | VBE_MODE_LFB)
2479+
2480+/* VBE Mode Info Block */
2481+struct vbe_mode_ib {
2482+ /* for all VBE revisions */
2483+ u16 mode_attr;
2484+ u8 winA_attr;
2485+ u8 winB_attr;
2486+ u16 win_granularity;
2487+ u16 win_size;
2488+ u16 winA_seg;
2489+ u16 winB_seg;
2490+ u32 win_func_ptr;
2491+ u16 bytes_per_scan_line;
2492+
2493+ /* for VBE 1.2+ */
2494+ u16 x_res;
2495+ u16 y_res;
2496+ u8 x_char_size;
2497+ u8 y_char_size;
2498+ u8 planes;
2499+ u8 bits_per_pixel;
2500+ u8 banks;
2501+ u8 memory_model;
2502+ u8 bank_size;
2503+ u8 image_pages;
2504+ u8 reserved1;
2505+
2506+ /* Direct color fields for direct/6 and YUV/7 memory models. */
2507+ /* Offsets are bit positions of lsb in the mask. */
2508+ u8 red_len;
2509+ u8 red_off;
2510+ u8 green_len;
2511+ u8 green_off;
2512+ u8 blue_len;
2513+ u8 blue_off;
2514+ u8 rsvd_len;
2515+ u8 rsvd_off;
2516+ u8 direct_color_info; /* direct color mode attributes */
2517+
2518+ /* for VBE 2.0+ */
2519+ u32 phys_base_ptr;
2520+ u8 reserved2[6];
2521+
2522+ /* for VBE 3.0+ */
2523+ u16 lin_bytes_per_scan_line;
2524+ u8 bnk_image_pages;
2525+ u8 lin_image_pages;
2526+ u8 lin_red_len;
2527+ u8 lin_red_off;
2528+ u8 lin_green_len;
2529+ u8 lin_green_off;
2530+ u8 lin_blue_len;
2531+ u8 lin_blue_off;
2532+ u8 lin_rsvd_len;
2533+ u8 lin_rsvd_off;
2534+ u32 max_pixel_clock;
2535+ u16 mode_id;
2536+ u8 depth;
2537+} __attribute__ ((packed));
2538+
2539+#define UVESAFB_DEFAULT_MODE "640x480-16"
2540+
2541+/* How long to wait for a reply from userspace [ms] */
2542+#define UVESAFB_TIMEOUT 5000
2543+
2544+/* Max number of concurrent tasks */
2545+#define UVESAFB_TASKS_MAX 16
2546+
2547+#define dac_reg (0x3c8)
2548+#define dac_val (0x3c9)
2549+
2550+struct uvesafb_pal_entry {
2551+ u_char blue, green, red, pad;
2552+} __attribute__ ((packed));
2553+
2554+struct uvesafb_ktask {
2555+ struct uvesafb_task t;
2556+ void *buf;
2557+ struct completion *done;
2558+ u32 ack;
2559+};
2560+
2561+static int uvesafb_exec(struct uvesafb_ktask *tsk);
2562+
2563+#define UVESAFB_EXACT_RES 1
2564+#define UVESAFB_EXACT_DEPTH 2
2565+
2566+struct uvesafb_par {
2567+ struct vbe_ib vbe_ib; /* VBE Info Block */
2568+ struct vbe_mode_ib *vbe_modes; /* list of supported VBE modes */
2569+ int vbe_modes_cnt;
2570+
2571+ u8 nocrtc;
2572+ u8 ypan; /* 0 - nothing, 1 - ypan, 2 - ywrap */
2573+ u8 pmi_setpal; /* PMI for palette changes */
2574+ u16 *pmi_base; /* protected mode interface location */
2575+ void *pmi_start;
2576+ void *pmi_pal;
2577+ u8 *vbe_state_orig; /*
2578+ * original hardware state, before the
2579+ * driver was loaded
2580+ */
2581+ u8 *vbe_state_saved; /* state saved by fb_save_state */
2582+ int vbe_state_size;
2583+ atomic_t ref_count;
2584+
2585+ int mode_idx;
2586+ struct vbe_crtc_ib crtc;
2587+};
2588+
2589+#endif /* __KERNEL__ */
2590+#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 @@
1---
2 drivers/char/vt_ioctl.c | 8 +++++---
3 1 file changed, 5 insertions(+), 3 deletions(-)
4
5Index: linux-2.6.22/drivers/char/vt_ioctl.c
6===================================================================
7--- linux-2.6.22.orig/drivers/char/vt_ioctl.c 2007-07-09 01:32:17.000000000 +0200
8+++ linux-2.6.22/drivers/char/vt_ioctl.c 2007-09-27 11:58:42.000000000 +0200
9@@ -770,6 +770,7 @@
10 /*
11 * Switching-from response
12 */
13+ acquire_console_sem();
14 if (vc->vt_newvt >= 0) {
15 if (arg == 0)
16 /*
17@@ -784,7 +785,6 @@
18 * complete the switch.
19 */
20 int newvt;
21- acquire_console_sem();
22 newvt = vc->vt_newvt;
23 vc->vt_newvt = -1;
24 i = vc_allocate(newvt);
25@@ -798,7 +798,6 @@
26 * other console switches..
27 */
28 complete_change_console(vc_cons[newvt].d);
29- release_console_sem();
30 }
31 }
32
33@@ -810,9 +809,12 @@
34 /*
35 * If it's just an ACK, ignore it
36 */
37- if (arg != VT_ACKACQ)
38+ if (arg != VT_ACKACQ) {
39+ release_console_sem();
40 return -EINVAL;
41+ }
42 }
43+ release_console_sem();
44
45 return 0;
46
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 @@
1From: Marcin Juszkiewicz <openembedded@haerwu.biz>
2
3drivers/video/w100fb.c: In function ‘w100fb_imageblit’:
4drivers/video/w100fb.c:507: warning: unused variable ‘par’
5
6Signed-off-by: Marcin Juszkiewicz <openembedded@haerwu.biz>
7
8--- linux-2.6.23/drivers/video/w100fb.c 2007-10-11 16:52:30.000000000 +0200
9+++ linux-2.6.23/drivers/video/w100fb.c 2007-10-15 12:56:01.000000000 +0200
10@@ -504,7 +504,6 @@ static void w100_hostdata(u32 width, u32
11 static void w100fb_imageblit(struct fb_info *info,
12 const struct fb_image *image)
13 {
14- struct w100fb_par *par = info->par;
15 union dp_gui_master_cntl_u gmc;
16 u32 fgcolor, bgcolor;
17
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 @@
1Index: linux-tosa/drivers/input/touchscreen/wm9712.c
2===================================================================
3--- linux-tosa.orig/drivers/input/touchscreen/wm9712.c 2006-08-29 16:52:36.008543280 +0100
4+++ linux-tosa/drivers/input/touchscreen/wm9712.c 2006-08-29 16:52:50.923275896 +0100
5@@ -1,7 +1,7 @@
6 /*
7 * wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
8 *
9- * Copyright 2003, 2004, 2005 Wolfson Microelectronics PLC.
10+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
11 * Author: Liam Girdwood
12 * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
13 * Parts Copyright : Ian Molton <spyro@f2s.com>
14@@ -13,6 +13,12 @@
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18+ * Revision history
19+ * 4th Jul 2005 Initial version.
20+ * 29th Aug 2006 Mike Arthur <mike@mikearthur.co.uk>
21+ * Added fixes for Sharp SL-6000 (Tosa) LCD noise causing
22+ * touchscreen interference.
23+ *
24 */
25
26 #include <linux/module.h>
27@@ -28,6 +34,10 @@
28 #define WM9705_VERSION "0.60"
29 #define DEFAULT_PRESSURE 0xb0c0
30
31+#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a))
32+#define CCNT_ON() asm("mcr p14, 0, %0, C0, C0, 0" : : "r"(1))
33+#define CCNT_OFF() asm("mcr p14, 0, %0, C0, C0, 0" : : "r"(1))
34+
35 /*
36 * Debug
37 */
38@@ -243,6 +253,36 @@
39 return wm->dig[2] & WM9712_PDEN;
40 }
41
42+
43+#ifdef CONFIG_MACH_TOSA
44+/* On the Sharp SL-6000 (Tosa), due to a noisy LCD, we need to perform a wait
45+ * before sampling the Y axis of the touchscreen */
46+static inline void wm9712_lcd_sync_on(struct wm97xx* wm, int adcsel) {
47+ unsigned long timer1 = 0, timer2 = 0, wait_time = 0;
48+ if (adcsel == WM97XX_ADCSEL_Y) {
49+ wait_time = wm97xx_calc_lcd_waittime(wm);
50+
51+ CCNT_ON();
52+
53+ if (wait_time) {
54+ /* wait for LCD rising edge */
55+ wm_machinfo->wait_hsync();
56+ /* get clock */
57+ CCNT(timer1);
58+ CCNT(timer2);
59+
60+ while ((timer2 - timer1) < wait_time) {
61+ CCNT(timer2);
62+ }
63+ }
64+ }
65+}
66+
67+static inline void wm9712_lcd_sync_off(void) {
68+ CCNT_OFF();
69+}
70+#endif
71+
72 /*
73 * Read a sample from the WM9712 adc in polling mode.
74 */
75@@ -260,6 +300,9 @@
76 /* set up digitiser */
77 if (adcsel & 0x8000)
78 adcsel = ((adcsel & 0x7fff) + 3) << 12;
79+ #ifdef CONFIG_MACH_TOSA
80+ wm9712_lcd_sync_on(wm, adcsel);
81+ #endif
82 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
83
84 /* wait 3 AC97 time slots + delay for conversion */
85@@ -282,6 +325,10 @@
86
87 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
88
89+ #ifdef CONFIG_MACH_TOSA
90+ wm9712_lcd_sync_off();
91+ #endif
92+
93 /* check we have correct sample */
94 if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
95 dbg ("adc wrong sample, read %x got %x", adcsel,
96@@ -303,11 +350,12 @@
97 static int wm9712_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
98 {
99 int rc;
100-
101 if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID)
102 return rc;
103+
104 if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID)
105 return rc;
106+
107 if (pil && !five_wire) {
108 if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID)
109 return rc;
110Index: linux-tosa/drivers/input/touchscreen/wm97xx-core.c
111===================================================================
112--- linux-tosa.orig/drivers/input/touchscreen/wm97xx-core.c 2006-08-29 16:52:36.008543280 +0100
113+++ linux-tosa/drivers/input/touchscreen/wm97xx-core.c 2006-08-29 16:52:50.924275744 +0100
114@@ -2,7 +2,7 @@
115 * wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712
116 * and WM9713 AC97 Codecs.
117 *
118- * Copyright 2003, 2004, 2005 Wolfson Microelectronics PLC.
119+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
120 * Author: Liam Girdwood
121 * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
122 * Parts Copyright : Ian Molton <spyro@f2s.com>
123@@ -67,6 +67,9 @@
124 * GPIOs) and 2.6 power management.
125 * 29th Nov 2004 Added WM9713 support.
126 * 4th Jul 2005 Moved codec specific code out to seperate files.
127+ * 29th Aug 2006 Mike Arthur <mike@mikearthur.co.uk>
128+ * Added fixes for Sharp SL-6000 (Tosa) LCD noise causing
129+ * touchscreen interference.
130 */
131
132 #include <linux/module.h>
133@@ -94,6 +97,7 @@
134 static DECLARE_MUTEX(gpio_sem);
135 static LIST_HEAD(wm97xx_misc_list);
136 static struct wm97xx* wm_codec = NULL;
137+struct wm97xx_machinfo *wm_machinfo;
138
139 /*
140 * WM97xx - enable/disable AUX ADC sysfs
141@@ -832,6 +836,23 @@
142 mdev->remove(wm_codec);
143 }
144
145+#ifdef CONFIG_MACH_TOSA
146+/* On the Sharp SL-6000 (Tosa), due to a noisy LCD, we need to perform a wait
147+ * before sampling the Y axis of the touchscreen */
148+unsigned long wm97xx_calc_lcd_waittime(struct wm97xx *wm) {
149+ unsigned long hsync_time = wm_machinfo->get_hsync_time();
150+ return hsync_time;
151+}
152+
153+void wm97xx_set_machinfo(struct wm97xx_machinfo *machinfo) {
154+ wm_machinfo = machinfo;
155+}
156+
157+void wm97xx_unset_machinfo() {
158+ wm_machinfo = NULL;
159+}
160+#endif
161+
162 static struct device_driver wm97xx_driver = {
163 .name = "ac97",
164 .bus = &ac97_bus_type,
165@@ -861,6 +882,9 @@
166 EXPORT_SYMBOL_GPL(wm97xx_reg_write);
167 EXPORT_SYMBOL_GPL(wm97xx_register_misc_dev);
168 EXPORT_SYMBOL_GPL(wm97xx_unregister_misc_dev);
169+EXPORT_SYMBOL_GPL(wm97xx_calc_lcd_waittime);
170+EXPORT_SYMBOL_GPL(wm97xx_set_machinfo);
171+EXPORT_SYMBOL_GPL(wm97xx_unset_machinfo);
172
173 module_init(wm97xx_init);
174 module_exit(wm97xx_exit);
175Index: linux-tosa/include/linux/wm97xx.h
176===================================================================
177--- linux-tosa.orig/include/linux/wm97xx.h 2006-08-29 16:52:36.008543280 +0100
178+++ linux-tosa/include/linux/wm97xx.h 2006-08-29 16:52:50.924275744 +0100
179@@ -207,6 +207,7 @@
180
181 struct wm97xx;
182 extern struct wm97xx_codec_drv wm97xx_codec;
183+extern struct wm97xx_machinfo *wm_machinfo;
184
185 /*
186 * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
187@@ -253,6 +254,11 @@
188 struct list_head list;
189 };
190
191+struct wm97xx_machinfo {
192+ unsigned long (*get_hsync_time)(void);
193+ void (*wait_hsync)(void);
194+};
195+
196 int wm97xx_register_misc_dev(struct wm97xx_misc_dev* mdev);
197 void wm97xx_unregister_misc_dev(struct wm97xx_misc_dev* mdev);
198
199@@ -281,4 +287,9 @@
200 int wm97xx_acc_startup(struct wm97xx* wm);
201 void wm97xx_acc_shutdown(struct wm97xx* wm);
202
203+
204+unsigned long wm97xx_calc_lcd_waittime(struct wm97xx *wm);
205+void wm97xx_set_machinfo(struct wm97xx_machinfo *machinfo);
206+void wm97xx_unset_machinfo(void);
207+
208 #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 @@
1---
2 drivers/mmc/core/sd.c | 11 ++++++-----
3 1 file changed, 6 insertions(+), 5 deletions(-)
4
5Index: linux-2.6.23/drivers/mmc/core/sd.c
6===================================================================
7--- linux-2.6.23.orig/drivers/mmc/core/sd.c 2007-10-17 11:33:26.000000000 +0200
8+++ linux-2.6.23/drivers/mmc/core/sd.c 2007-10-17 11:33:49.000000000 +0200
9@@ -173,14 +173,15 @@
10
11 scr_struct = UNSTUFF_BITS(resp, 60, 4);
12 if (scr_struct != 0) {
13- printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
14+ printk(KERN_WARNING "%s: unrecognised SCR structure version %d\n",
15 mmc_hostname(card->host), scr_struct);
16- return -EINVAL;
17+ scr->sda_vsn = 0;
18+ scr->bus_widths = 0;
19+ } else {
20+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
21+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
22 }
23
24- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
25- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
26-
27 return 0;
28 }
29
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 @@
1---
2 arch/arm/Kconfig | 2
3 drivers/Kconfig | 2
4 drivers/Makefile | 1
5 drivers/power/Kconfig | 70 +++++
6 drivers/power/Makefile | 28 ++
7 drivers/power/adc_battery.c | 278 +++++++++++++++++++++
8 drivers/power/apm_power.c | 247 +++++++++++++++++++
9 drivers/power/ds2760_battery.c | 475 +++++++++++++++++++++++++++++++++++++
10 drivers/power/micro_battery.c | 257 ++++++++++++++++++++
11 drivers/power/olpc_battery.c | 302 +++++++++++++++++++++++
12 drivers/power/pda_power.c | 263 ++++++++++++++++++++
13 drivers/power/pmu_battery.c | 215 ++++++++++++++++
14 drivers/power/power_supply.h | 42 +++
15 drivers/power/power_supply_core.c | 168 +++++++++++++
16 drivers/power/power_supply_leds.c | 188 ++++++++++++++
17 drivers/power/power_supply_sysfs.c | 289 ++++++++++++++++++++++
18 drivers/power/simpad-battery.c | 242 ++++++++++++++++++
19 include/linux/power_supply.h | 175 +++++++++++++
20 18 files changed, 3244 insertions(+)
21
22Index: linux-2.6.22/drivers/power/adc_battery.c
23===================================================================
24--- /dev/null 1970-01-01 00:00:00.000000000 +0000
25+++ linux-2.6.22/drivers/power/adc_battery.c 2007-08-23 12:26:28.000000000 +0200
26@@ -0,0 +1,278 @@
27+/*
28+ * Copyright (c) 2007 Paul Sokolovsky
29+ *
30+ * This program is free software; you can redistribute it and/or modify
31+ * it under the terms of the GNU General Public License as published by
32+ * the Free Software Foundation; either version 2 of the License, or
33+ * (at your option) any later version.
34+ *
35+ */
36+
37+//#define DEBUG
38+
39+#include <linux/module.h>
40+#include <linux/interrupt.h>
41+#include <linux/pm.h>
42+#include <linux/delay.h>
43+#include <linux/workqueue.h>
44+#include <linux/platform_device.h>
45+#include <linux/power_supply.h>
46+#include <linux/adc.h>
47+#include <linux/adc_battery.h>
48+
49+#include <asm/irq.h>
50+
51+#define PIN_NO_VOLT 0
52+#define PIN_NO_CURR 1
53+#define PIN_NO_TEMP 2
54+
55+struct battery_adc_priv {
56+ struct power_supply batt_cdev;
57+
58+ struct battery_adc_platform_data *pdata;
59+
60+ struct adc_request req;
61+ struct adc_sense pins[3];
62+ struct adc_sense last_good_pins[3];
63+
64+ struct workqueue_struct *wq;
65+ struct delayed_work work;
66+};
67+
68+/*
69+ * Battery properties
70+ */
71+
72+static int adc_battery_get_property(struct power_supply *psy,
73+ enum power_supply_property psp,
74+ union power_supply_propval *val)
75+{
76+ struct battery_adc_priv* drvdata = (struct battery_adc_priv*)psy;
77+ int voltage;
78+
79+ switch (psp) {
80+ case POWER_SUPPLY_PROP_STATUS:
81+ val->intval = drvdata->pdata->charge_status;
82+ break;
83+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
84+ val->intval = drvdata->pdata->battery_info.voltage_max_design;
85+ break;
86+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
87+ val->intval = drvdata->pdata->battery_info.voltage_min_design;
88+ break;
89+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
90+ val->intval = drvdata->pdata->battery_info.charge_full_design;
91+ break;
92+ case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
93+ val->intval = drvdata->pdata->battery_info.charge_empty_design;
94+ break;
95+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
96+ val->intval = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
97+ break;
98+ case POWER_SUPPLY_PROP_CURRENT_NOW:
99+ val->intval = drvdata->last_good_pins[PIN_NO_CURR].value * drvdata->pdata->current_mult;
100+ break;
101+ case POWER_SUPPLY_PROP_CHARGE_NOW:
102+ /* We do calculations in mX, not uX, because todo it in uX we should use "long long"s,
103+ * which is a mess (need to use do_div) when you need divide operation). */
104+ voltage = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult;
105+ val->intval = ((voltage/1000 - drvdata->pdata->battery_info.voltage_min_design/1000) *
106+ (drvdata->pdata->battery_info.charge_full_design/1000 -
107+ drvdata->pdata->battery_info.charge_empty_design/1000)) /
108+ (drvdata->pdata->battery_info.voltage_max_design/1000 -
109+ drvdata->pdata->battery_info.voltage_min_design/1000);
110+ val->intval *= 1000; /* convert final result to uX */
111+ break;
112+ case POWER_SUPPLY_PROP_TEMP:
113+ val->intval = drvdata->last_good_pins[PIN_NO_TEMP].value * drvdata->pdata->temperature_mult / 1000;
114+ break;
115+ default:
116+ return -EINVAL;
117+ };
118+ return 0;
119+}
120+
121+/*
122+ * Driver body
123+ */
124+
125+static void adc_battery_query(struct battery_adc_priv *drvdata)
126+{
127+ struct battery_adc_platform_data *pdata = drvdata->pdata;
128+ int powered, charging;
129+
130+ adc_request_sample(&drvdata->req);
131+
132+ powered = power_supply_am_i_supplied(&drvdata->batt_cdev);
133+ charging = pdata->is_charging ? pdata->is_charging() : -1;
134+
135+ if (powered && charging)
136+ pdata->charge_status = POWER_SUPPLY_STATUS_CHARGING;
137+ else if (powered && !charging && charging != -1)
138+ pdata->charge_status = POWER_SUPPLY_STATUS_FULL;
139+ else
140+ pdata->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
141+
142+ /* Throw away invalid samples, this may happen soon after resume for example. */
143+ if (drvdata->pins[PIN_NO_VOLT].value > 0) {
144+ memcpy(drvdata->last_good_pins, drvdata->pins, sizeof(drvdata->pins));
145+#ifdef DEBUG
146+ printk("%d %d %d\n", drvdata->pins[PIN_NO_VOLT].value,
147+ drvdata->pins[PIN_NO_CURR].value,
148+ drvdata->pins[PIN_NO_TEMP].value);
149+#endif
150+ }
151+}
152+
153+static void adc_battery_charge_power_changed(struct power_supply *bat)
154+{
155+ struct battery_adc_priv *drvdata = (struct battery_adc_priv*)bat;
156+ cancel_delayed_work(&drvdata->work);
157+ queue_delayed_work(drvdata->wq, &drvdata->work, 0);
158+}
159+
160+static void adc_battery_work_func(struct work_struct *work)
161+{
162+ struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);
163+ struct battery_adc_priv *drvdata = container_of(delayed_work, struct battery_adc_priv, work);
164+
165+ adc_battery_query(drvdata);
166+ power_supply_changed(&drvdata->batt_cdev);
167+
168+ queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
169+}
170+
171+static int adc_battery_probe(struct platform_device *pdev)
172+{
173+ int retval;
174+ struct battery_adc_platform_data *pdata = pdev->dev.platform_data;
175+ struct battery_adc_priv *drvdata;
176+ int i, j;
177+ enum power_supply_property props[] = {
178+ POWER_SUPPLY_PROP_STATUS,
179+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
180+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
181+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
182+ POWER_SUPPLY_PROP_CURRENT_NOW,
183+ POWER_SUPPLY_PROP_CHARGE_NOW,
184+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
185+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
186+ POWER_SUPPLY_PROP_TEMP,
187+ };
188+
189+ // Initialize ts data structure.
190+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
191+ if (!drvdata)
192+ return -ENOMEM;
193+
194+ drvdata->batt_cdev.name = pdata->battery_info.name;
195+ drvdata->batt_cdev.use_for_apm = pdata->battery_info.use_for_apm;
196+ drvdata->batt_cdev.num_properties = ARRAY_SIZE(props);
197+ drvdata->batt_cdev.get_property = adc_battery_get_property;
198+ drvdata->batt_cdev.external_power_changed =
199+ adc_battery_charge_power_changed;
200+
201+ if (!pdata->voltage_pin) {
202+ drvdata->batt_cdev.num_properties--;
203+ props[3] = -1;
204+ }
205+ if (!pdata->current_pin) {
206+ drvdata->batt_cdev.num_properties--;
207+ props[4] = -1;
208+ }
209+ if (!pdata->temperature_pin) {
210+ drvdata->batt_cdev.num_properties--;
211+ props[8] = -1;
212+ }
213+
214+ drvdata->batt_cdev.properties = kmalloc(
215+ sizeof(*drvdata->batt_cdev.properties) *
216+ drvdata->batt_cdev.num_properties, GFP_KERNEL);
217+ if (!drvdata->batt_cdev.properties)
218+ return -ENOMEM;
219+
220+ j = 0;
221+ for (i = 0; i < ARRAY_SIZE(props); i++) {
222+ if (props[i] == -1)
223+ continue;
224+ drvdata->batt_cdev.properties[j++] = props[i];
225+ }
226+
227+ retval = power_supply_register(&pdev->dev, &drvdata->batt_cdev);
228+ if (retval) {
229+ printk("adc-battery: Error registering battery classdev");
230+ return retval;
231+ }
232+
233+ drvdata->req.senses = drvdata->pins;
234+ drvdata->req.num_senses = ARRAY_SIZE(drvdata->pins);
235+ drvdata->pins[PIN_NO_VOLT].name = pdata->voltage_pin;
236+ drvdata->pins[PIN_NO_CURR].name = pdata->current_pin;
237+ drvdata->pins[PIN_NO_TEMP].name = pdata->temperature_pin;
238+
239+ adc_request_register(&drvdata->req);
240+
241+ /* Here we assume raw values in mV */
242+ if (!pdata->voltage_mult)
243+ pdata->voltage_mult = 1000;
244+ /* Here we assume raw values in mA */
245+ if (!pdata->current_mult)
246+ pdata->current_mult = 1000;
247+ /* Here we assume raw values in 1/10 C */
248+ if (!pdata->temperature_mult)
249+ pdata->temperature_mult = 1000;
250+
251+ drvdata->pdata = pdata;
252+ pdata->drvdata = drvdata; /* Seems ugly, we need better solution */
253+
254+ platform_set_drvdata(pdev, drvdata);
255+
256+ // Load initial values ASAP
257+ adc_battery_query(drvdata);
258+
259+ // Still schedule next sampling soon
260+ INIT_DELAYED_WORK(&drvdata->work, adc_battery_work_func);
261+ drvdata->wq = create_workqueue(pdev->dev.bus_id);
262+ if (!drvdata->wq)
263+ return -ESRCH;
264+
265+ queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000);
266+
267+ return retval;
268+}
269+
270+static int adc_battery_remove(struct platform_device *pdev)
271+{
272+ struct battery_adc_priv *drvdata = platform_get_drvdata(pdev);
273+ cancel_delayed_work(&drvdata->work);
274+ destroy_workqueue(drvdata->wq);
275+ power_supply_unregister(&drvdata->batt_cdev);
276+ adc_request_unregister(&drvdata->req);
277+ kfree(drvdata->batt_cdev.properties);
278+ return 0;
279+}
280+
281+static struct platform_driver adc_battery_driver = {
282+ .driver = {
283+ .name = "adc-battery",
284+ },
285+ .probe = adc_battery_probe,
286+ .remove = adc_battery_remove,
287+};
288+
289+static int __init adc_battery_init(void)
290+{
291+ return platform_driver_register(&adc_battery_driver);
292+}
293+
294+static void __exit adc_battery_exit(void)
295+{
296+ platform_driver_unregister(&adc_battery_driver);
297+}
298+
299+module_init(adc_battery_init)
300+module_exit(adc_battery_exit)
301+
302+MODULE_AUTHOR("Paul Sokolovsky");
303+MODULE_DESCRIPTION("Battery driver for ADC device");
304+MODULE_LICENSE("GPL");
305Index: linux-2.6.22/drivers/power/apm_power.c
306===================================================================
307--- /dev/null 1970-01-01 00:00:00.000000000 +0000
308+++ linux-2.6.22/drivers/power/apm_power.c 2007-08-23 12:13:52.000000000 +0200
309@@ -0,0 +1,247 @@
310+/*
311+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
312+ * Copyright (c) 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
313+ *
314+ * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
315+ *
316+ * Use consistent with the GNU GPL is permitted,
317+ * provided that this copyright notice is
318+ * preserved in its entirety in all copies and derived works.
319+ */
320+
321+#include <linux/module.h>
322+#include <linux/power_supply.h>
323+#include <linux/apm-emulation.h>
324+
325+#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
326+ POWER_SUPPLY_PROP_##prop, val)
327+
328+#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
329+ prop, val)
330+
331+#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
332+
333+static struct power_supply *main_battery;
334+
335+static void find_main_battery(void)
336+{
337+ struct device *dev;
338+ struct power_supply *bat, *batm;
339+ union power_supply_propval full;
340+ int max_charge = 0;
341+
342+ main_battery = NULL;
343+ batm = NULL;
344+ list_for_each_entry(dev, &power_supply_class->devices, node) {
345+ bat = dev_get_drvdata(dev);
346+ /* If none of battery devices cantains 'use_for_apm' flag,
347+ choice one with maximum design charge */
348+ if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
349+ if (full.intval > max_charge) {
350+ batm = bat;
351+ max_charge = full.intval;
352+ }
353+ }
354+
355+ if (bat->use_for_apm)
356+ main_battery = bat;
357+ }
358+ if (!main_battery)
359+ main_battery = batm;
360+
361+ return;
362+}
363+
364+static int calculate_time(int status)
365+{
366+ union power_supply_propval charge_full, charge_empty;
367+ union power_supply_propval charge, I;
368+
369+ if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
370+ /* if battery can't report this property, use design value */
371+ if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
372+ return -1;
373+ }
374+
375+ if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
376+ /* if battery can't report this property, use design value */
377+ if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
378+ charge_empty.intval = 0;
379+ }
380+
381+ if (MPSY_PROP(CHARGE_AVG, &charge)) {
382+ /* if battery can't report average value, use momentary */
383+ if (MPSY_PROP(CHARGE_NOW, &charge))
384+ return -1;
385+ }
386+
387+ if (MPSY_PROP(CURRENT_AVG, &I)) {
388+ /* if battery can't report average value, use momentary */
389+ if (MPSY_PROP(CURRENT_NOW, &I))
390+ return -1;
391+ }
392+
393+ if (I.intval == 0)
394+ return 0;
395+ else if (status == POWER_SUPPLY_STATUS_CHARGING)
396+ return ((charge.intval - charge_full.intval) * 60L) /
397+ I.intval;
398+ else
399+ return -((charge.intval - charge_empty.intval) * 60L) /
400+ I.intval;
401+}
402+
403+static int calculate_capacity(int using_charge)
404+{
405+ enum power_supply_property full_prop, empty_prop;
406+ enum power_supply_property full_design_prop, empty_design_prop;
407+ enum power_supply_property now_prop, avg_prop;
408+ union power_supply_propval empty, full, cur;
409+ int ret;
410+
411+ if (using_charge) {
412+ full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
413+ empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
414+ full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
415+ empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
416+ now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
417+ avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
418+ }
419+ else {
420+ full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
421+ empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
422+ full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
423+ empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
424+ now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
425+ avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
426+ }
427+
428+ if (_MPSY_PROP(full_prop, &full)) {
429+ /* if battery can't report this property, use design value */
430+ if (_MPSY_PROP(full_design_prop, &full))
431+ return -1;
432+ }
433+
434+ if (_MPSY_PROP(avg_prop, &cur)) {
435+ /* if battery can't report average value, use momentary */
436+ if (_MPSY_PROP(now_prop, &cur))
437+ return -1;
438+ }
439+
440+ if (_MPSY_PROP(empty_prop, &empty)) {
441+ /* if battery can't report this property, use design value */
442+ if (_MPSY_PROP(empty_design_prop, &empty))
443+ empty.intval = 0;
444+ }
445+
446+ if (full.intval - empty.intval)
447+ ret = ((cur.intval - empty.intval) * 100L) /
448+ (full.intval - empty.intval);
449+ else
450+ return -1;
451+
452+ if (ret > 100)
453+ return 100;
454+ else if (ret < 0)
455+ return 0;
456+
457+ return ret;
458+}
459+
460+static void apm_battery_apm_get_power_status(struct apm_power_info *info)
461+{
462+ union power_supply_propval status;
463+ union power_supply_propval capacity, time_to_full, time_to_empty;
464+
465+ down(&power_supply_class->sem);
466+ find_main_battery();
467+ if (!main_battery) {
468+ up(&power_supply_class->sem);
469+ return;
470+ }
471+
472+ /* status */
473+
474+ if (MPSY_PROP(STATUS, &status))
475+ status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
476+
477+ /* ac line status */
478+
479+ if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
480+ (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
481+ (status.intval == POWER_SUPPLY_STATUS_FULL))
482+ info->ac_line_status = APM_AC_ONLINE;
483+ else
484+ info->ac_line_status = APM_AC_OFFLINE;
485+
486+ /* battery life (i.e. capacity, in percents) */
487+
488+ if (MPSY_PROP(CAPACITY, &capacity) == 0)
489+ info->battery_life = capacity.intval;
490+ else {
491+ /* try calculate using energy */
492+ info->battery_life = calculate_capacity(0);
493+ /* if failed try calculate using charge instead */
494+ if (info->battery_life == -1)
495+ info->battery_life = calculate_capacity(1);
496+ }
497+
498+ /* charging status */
499+
500+ if (status.intval == POWER_SUPPLY_STATUS_CHARGING)
501+ info->battery_status = APM_BATTERY_STATUS_CHARGING;
502+ else {
503+ if (info->battery_life > 50)
504+ info->battery_status = APM_BATTERY_STATUS_HIGH;
505+ else if (info->battery_life > 5)
506+ info->battery_status = APM_BATTERY_STATUS_LOW;
507+ else
508+ info->battery_status = APM_BATTERY_STATUS_CRITICAL;
509+ }
510+ info->battery_flag = info->battery_status;
511+
512+ /* time */
513+
514+ info->units = APM_UNITS_MINS;
515+
516+ if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
517+ if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
518+ if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
519+ info->time = calculate_time(status.intval);
520+ else
521+ info->time = time_to_full.intval / 60;
522+ }
523+ }
524+ else {
525+ if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
526+ if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
527+ info->time = calculate_time(status.intval);
528+ else
529+ info->time = time_to_empty.intval / 60;
530+ }
531+ }
532+
533+ up(&power_supply_class->sem);
534+ return;
535+}
536+
537+static int __init apm_battery_init(void)
538+{
539+ printk(KERN_INFO "APM Battery Driver\n");
540+
541+ apm_get_power_status = apm_battery_apm_get_power_status;
542+ return 0;
543+}
544+
545+static void __exit apm_battery_exit(void)
546+{
547+ apm_get_power_status = NULL;
548+ return;
549+}
550+
551+module_init(apm_battery_init);
552+module_exit(apm_battery_exit);
553+
554+MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
555+MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
556+MODULE_LICENSE("GPL");
557Index: linux-2.6.22/drivers/power/ds2760_battery.c
558===================================================================
559--- /dev/null 1970-01-01 00:00:00.000000000 +0000
560+++ linux-2.6.22/drivers/power/ds2760_battery.c 2007-08-23 12:13:52.000000000 +0200
561@@ -0,0 +1,475 @@
562+/*
563+ * Driver for batteries with DS2760 chips inside.
564+ *
565+ * Copyright (c) 2007 Anton Vorontsov
566+ * 2004-2007 Matt Reimer
567+ * 2004 Szabolcs Gyurko
568+ *
569+ * Use consistent with the GNU GPL is permitted,
570+ * provided that this copyright notice is
571+ * preserved in its entirety in all copies and derived works.
572+ *
573+ * Author: Anton Vorontsov <cbou@mail.ru>
574+ * February 2007
575+ *
576+ * Matt Reimer <mreimer@vpop.net>
577+ * April 2004, 2005, 2007
578+ *
579+ * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
580+ * September 2004
581+ */
582+
583+#include <linux/module.h>
584+#include <linux/param.h>
585+#include <linux/jiffies.h>
586+#include <linux/workqueue.h>
587+#include <linux/pm.h>
588+#include <linux/platform_device.h>
589+#include <linux/power_supply.h>
590+
591+#include "../w1/w1.h"
592+#include "../w1/slaves/w1_ds2760.h"
593+
594+struct ds2760_device_info {
595+ struct device *dev;
596+
597+ /* DS2760 data, valid after calling ds2760_battery_read_status() */
598+ unsigned long update_time; /* jiffies when data read */
599+ char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */
600+ int voltage_raw; /* units of 4.88 mV */
601+ int voltage_uV; /* units of uV */
602+ int current_raw; /* units of 0.625 mA */
603+ int current_uA; /* units of uA */
604+ int accum_current_raw; /* units of 0.25 mAh */
605+ int accum_current_uAh; /* units of uAh */
606+ int temp_raw; /* units of 0.125 C */
607+ int temp_C; /* units of 0.1 C */
608+ int rated_capacity; /* units of uAh */
609+ int rem_capacity; /* percentage */
610+ int full_active_uAh; /* units of uAh */
611+ int empty_uAh; /* units of uAh */
612+ int life_sec; /* units of seconds */
613+ int charge_status; /* POWER_SUPPLY_STATUS_* */
614+
615+ int full_counter;
616+ struct power_supply bat;
617+ struct device *w1_dev;
618+ struct workqueue_struct *monitor_wqueue;
619+ struct delayed_work monitor_work;
620+};
621+
622+static unsigned int cache_time = 1000;
623+module_param(cache_time, uint, 0644);
624+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
625+
626+/* Some batteries have their rated capacity stored a N * 10 mAh, while
627+ * others use an index into this table. */
628+static int rated_capacities[] = {
629+ 0,
630+ 920, /* Samsung */
631+ 920, /* BYD */
632+ 920, /* Lishen */
633+ 920, /* NEC */
634+ 1440, /* Samsung */
635+ 1440, /* BYD */
636+ 1440, /* Lishen */
637+ 1440, /* NEC */
638+ 2880, /* Samsung */
639+ 2880, /* BYD */
640+ 2880, /* Lishen */
641+ 2880 /* NEC */
642+};
643+
644+/* array is level at temps 0C, 10C, 20C, 30C, 40C
645+ * temp is in Celsius */
646+static int battery_interpolate(int array[], int temp)
647+{
648+ int index, dt;
649+
650+ if (temp <= 0)
651+ return array[0];
652+ if (temp >= 40)
653+ return array[4];
654+
655+ index = temp / 10;
656+ dt = temp % 10;
657+
658+ return array[index] + (((array[index + 1] - array[index]) * dt) / 10);
659+}
660+
661+static int ds2760_battery_read_status(struct ds2760_device_info *di)
662+{
663+ int ret, i, start, count, scale[5];
664+
665+ if (di->update_time && time_before(jiffies, di->update_time +
666+ msecs_to_jiffies(cache_time)))
667+ return 0;
668+
669+ /* The first time we read the entire contents of SRAM/EEPROM,
670+ * but after that we just read the interesting bits that change. */
671+ if (di->update_time == 0) {
672+ start = 0;
673+ count = DS2760_DATA_SIZE;
674+ }
675+ else {
676+ start = DS2760_VOLTAGE_MSB;
677+ count = DS2760_TEMP_LSB - start + 1;
678+ }
679+
680+ ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count);
681+ if (ret != count) {
682+ dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n",
683+ di->w1_dev);
684+ return 1;
685+ }
686+
687+ di->update_time = jiffies;
688+
689+ /* DS2760 reports voltage in units of 4.88mV, but the battery class
690+ * reports in units of uV, so convert by multiplying by 4880. */
691+ di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) |
692+ (di->raw[DS2760_VOLTAGE_LSB] >> 5);
693+ di->voltage_uV = di->voltage_raw * 4880;
694+
695+ /* DS2760 reports current in signed units of 0.625mA, but the battery
696+ * class reports in units of uA, so convert by multiplying by 625. */
697+ di->current_raw =
698+ (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) |
699+ (di->raw[DS2760_CURRENT_LSB] >> 3);
700+ di->current_uA = di->current_raw * 625;
701+
702+ /* DS2760 reports accumulated current in signed units of 0.25mAh. */
703+ di->accum_current_raw =
704+ (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) |
705+ di->raw[DS2760_CURRENT_ACCUM_LSB];
706+ di->accum_current_uAh = di->accum_current_raw * 250;
707+
708+ /* DS2760 reports temperature in signed units of 0.125C, but the
709+ * battery class reports in units of 1/10 C, so we convert by
710+ * multiplying by .125 * 10 = 1.25. */
711+ di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) |
712+ (di->raw[DS2760_TEMP_LSB] >> 5);
713+ di->temp_C = di->temp_raw + (di->temp_raw / 4);
714+
715+ /* At least some battery monitors (e.g. HP iPAQ) store the battery's
716+ * maximum rated capacity. */
717+ if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities))
718+ di->rated_capacity = rated_capacities[
719+ (unsigned int)di->raw[DS2760_RATED_CAPACITY]];
720+ else
721+ di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10;
722+
723+ di->rated_capacity *= 1000; /* convert to uAh */
724+
725+ /* Calculate the full level at the present temperature. */
726+ di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
727+ di->raw[DS2760_ACTIVE_FULL + 1];
728+
729+ scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 |
730+ di->raw[DS2760_ACTIVE_FULL + 1];
731+ for (i = 1; i < 5; i++)
732+ scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
733+
734+ di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
735+ di->full_active_uAh *= 1000; /* convert to uAh */
736+
737+ /* Calculate the empty level at the present temperature. */
738+ scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4];
739+ for (i = 3; i >= 0; i--)
740+ scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i];
741+
742+ di->empty_uAh = battery_interpolate(scale, di->temp_C / 10);
743+ di->empty_uAh *= 1000; /* convert to uAh */
744+
745+ /* From Maxim Application Note 131: remaining capacity =
746+ * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */
747+ di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) /
748+ (di->full_active_uAh - di->empty_uAh);
749+
750+ if (di->rem_capacity < 0)
751+ di->rem_capacity = 0;
752+ if (di->rem_capacity > 100)
753+ di->rem_capacity = 100;
754+
755+ if (di->current_uA)
756+ di->life_sec = -((di->accum_current_uAh - di->empty_uAh) *
757+ 3600L) / di->current_uA;
758+ else
759+ di->life_sec = 0;
760+
761+ return 0;
762+}
763+
764+static void ds2760_battery_update_status(struct ds2760_device_info *di)
765+{
766+ int old_charge_status = di->charge_status;
767+
768+ ds2760_battery_read_status(di);
769+
770+ if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN)
771+ di->full_counter = 0;
772+
773+ if (power_supply_am_i_supplied(&di->bat)) {
774+ if (di->current_uA > 10000) {
775+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
776+ di->full_counter = 0;
777+ }
778+ else if (di->current_uA < -5000) {
779+ if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING)
780+ dev_notice(di->dev, "not enough power to "
781+ "charge\n");
782+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
783+ di->full_counter = 0;
784+ }
785+ else if (di->current_uA < 10000 &&
786+ di->charge_status != POWER_SUPPLY_STATUS_FULL) {
787+
788+ /* Don't consider the battery to be full unless
789+ * we've seen the current < 10 mA at least two
790+ * consecutive times. */
791+
792+ di->full_counter++;
793+
794+ if (di->full_counter < 2)
795+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
796+ else {
797+ unsigned char acr[2];
798+ int acr_val;
799+
800+ /* acr is in units of 0.25 mAh */
801+ acr_val = di->full_active_uAh * 4L / 1000;
802+
803+ acr[0] = acr_val >> 8;
804+ acr[1] = acr_val & 0xff;
805+
806+ if (w1_ds2760_write(di->w1_dev, acr,
807+ DS2760_CURRENT_ACCUM_MSB, 2) < 2)
808+ dev_warn(di->dev,
809+ "ACR reset failed\n");
810+
811+ di->charge_status = POWER_SUPPLY_STATUS_FULL;
812+ }
813+ }
814+ }
815+ else {
816+ di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
817+ di->full_counter = 0;
818+ }
819+
820+ if (di->charge_status != old_charge_status)
821+ power_supply_changed(&di->bat);
822+
823+ return;
824+}
825+
826+static void ds2760_battery_work(struct work_struct *work)
827+{
828+ struct ds2760_device_info *di = container_of(work,
829+ struct ds2760_device_info, monitor_work.work);
830+ const int interval = HZ * 60;
831+
832+ dev_dbg(di->dev, "%s\n", __FUNCTION__);
833+
834+ ds2760_battery_update_status(di);
835+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
836+
837+ return;
838+}
839+
840+#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \
841+ bat);
842+
843+static void ds2760_battery_external_power_changed(struct power_supply *psy)
844+{
845+ struct ds2760_device_info *di = to_ds2760_device_info(psy);
846+
847+ dev_dbg(di->dev, "%s\n", __FUNCTION__);
848+
849+ cancel_delayed_work(&di->monitor_work);
850+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
851+
852+ return;
853+}
854+
855+static int ds2760_battery_get_property(struct power_supply *psy,
856+ enum power_supply_property psp,
857+ union power_supply_propval *val)
858+{
859+ struct ds2760_device_info *di = to_ds2760_device_info(psy);
860+
861+ switch (psp) {
862+ case POWER_SUPPLY_PROP_STATUS:
863+ val->intval = di->charge_status;
864+ return 0;
865+ default:
866+ break;
867+ }
868+
869+ ds2760_battery_read_status(di);
870+
871+ switch (psp) {
872+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
873+ val->intval = di->voltage_uV;
874+ break;
875+ case POWER_SUPPLY_PROP_CURRENT_NOW:
876+ val->intval = di->current_uA;
877+ break;
878+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
879+ val->intval = di->rated_capacity;
880+ break;
881+ case POWER_SUPPLY_PROP_CHARGE_FULL:
882+ val->intval = di->full_active_uAh;
883+ break;
884+ case POWER_SUPPLY_PROP_CHARGE_EMPTY:
885+ val->intval = di->empty_uAh;
886+ break;
887+ case POWER_SUPPLY_PROP_CHARGE_NOW:
888+ val->intval = di->accum_current_uAh;
889+ break;
890+ case POWER_SUPPLY_PROP_TEMP:
891+ val->intval = di->temp_C;
892+ break;
893+ default:
894+ return -EINVAL;
895+ }
896+
897+ return 0;
898+}
899+
900+static enum power_supply_property ds2760_battery_props[] = {
901+ POWER_SUPPLY_PROP_STATUS,
902+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
903+ POWER_SUPPLY_PROP_CURRENT_NOW,
904+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
905+ POWER_SUPPLY_PROP_CHARGE_FULL,
906+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
907+ POWER_SUPPLY_PROP_CHARGE_NOW,
908+ POWER_SUPPLY_PROP_TEMP,
909+};
910+
911+static int ds2760_battery_probe(struct platform_device *pdev)
912+{
913+ int retval = 0;
914+ struct ds2760_device_info *di;
915+ struct ds2760_platform_data *pdata;
916+
917+ di = kzalloc(sizeof(*di), GFP_KERNEL);
918+ if (!di) {
919+ retval = -ENOMEM;
920+ goto di_alloc_failed;
921+ }
922+
923+ platform_set_drvdata(pdev, di);
924+
925+ pdata = pdev->dev.platform_data;
926+ di->dev = &pdev->dev;
927+ di->w1_dev = pdev->dev.parent;
928+ di->bat.name = pdev->dev.bus_id;
929+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
930+ di->bat.properties = ds2760_battery_props;
931+ di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
932+ di->bat.get_property = ds2760_battery_get_property;
933+ di->bat.external_power_changed =
934+ ds2760_battery_external_power_changed;
935+ di->bat.use_for_apm = 1;
936+
937+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
938+
939+ retval = power_supply_register(&pdev->dev, &di->bat);
940+ if (retval) {
941+ dev_err(di->dev, "failed to register battery");
942+ goto batt_failed;
943+ }
944+
945+ INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
946+ di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id);
947+ if (!di->monitor_wqueue) {
948+ retval = -ESRCH;
949+ goto workqueue_failed;
950+ }
951+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1);
952+
953+ goto success;
954+
955+workqueue_failed:
956+ power_supply_unregister(&di->bat);
957+batt_failed:
958+ kfree(di);
959+di_alloc_failed:
960+success:
961+ return retval;
962+}
963+
964+static int ds2760_battery_remove(struct platform_device *pdev)
965+{
966+ struct ds2760_device_info *di = platform_get_drvdata(pdev);
967+
968+ cancel_rearming_delayed_workqueue(di->monitor_wqueue,
969+ &di->monitor_work);
970+ destroy_workqueue(di->monitor_wqueue);
971+ power_supply_unregister(&di->bat);
972+
973+ return 0;
974+}
975+
976+#ifdef CONFIG_PM
977+
978+static int ds2760_battery_suspend(struct platform_device *pdev,
979+ pm_message_t state)
980+{
981+ struct ds2760_device_info *di = platform_get_drvdata(pdev);
982+
983+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
984+
985+ return 0;
986+}
987+
988+static int ds2760_battery_resume(struct platform_device *pdev)
989+{
990+ struct ds2760_device_info *di = platform_get_drvdata(pdev);
991+
992+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
993+ power_supply_changed(&di->bat);
994+
995+ cancel_delayed_work(&di->monitor_work);
996+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
997+
998+ return 0;
999+}
1000+
1001+#else
1002+
1003+#define ds2760_battery_suspend NULL
1004+#define ds2760_battery_resume NULL
1005+
1006+#endif /* CONFIG_PM */
1007+
1008+static struct platform_driver ds2760_battery_driver = {
1009+ .driver = {
1010+ .name = "ds2760-battery",
1011+ },
1012+ .probe = ds2760_battery_probe,
1013+ .remove = ds2760_battery_remove,
1014+ .suspend = ds2760_battery_suspend,
1015+ .resume = ds2760_battery_resume,
1016+};
1017+
1018+static int __init ds2760_battery_init(void)
1019+{
1020+ return platform_driver_register(&ds2760_battery_driver);
1021+}
1022+
1023+static void __exit ds2760_battery_exit(void)
1024+{
1025+ platform_driver_unregister(&ds2760_battery_driver);
1026+ return;
1027+}
1028+
1029+module_init(ds2760_battery_init);
1030+module_exit(ds2760_battery_exit);
1031+
1032+MODULE_LICENSE("GPL");
1033+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
1034+ "Matt Reimer <mreimer@vpop.net>, "
1035+ "Anton Vorontsov <cbou@mail.ru>");
1036+MODULE_DESCRIPTION("ds2760 battery driver");
1037Index: linux-2.6.22/drivers/power/Kconfig
1038===================================================================
1039--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1040+++ linux-2.6.22/drivers/power/Kconfig 2007-08-23 12:13:52.000000000 +0200
1041@@ -0,0 +1,70 @@
1042+menuconfig POWER_SUPPLY
1043+ tristate "Power supply class support"
1044+ help
1045+ Say Y here to enable power supply class support. This allows
1046+ power supply (batteries, AC, USB) monitoring by userspace
1047+ via sysfs and uevent (if available) and/or APM kernel interface
1048+ (if selected below).
1049+
1050+if POWER_SUPPLY
1051+
1052+config POWER_SUPPLY_DEBUG
1053+ bool "Power supply debug"
1054+ help
1055+ Say Y here to enable debugging messages for power supply class
1056+ and drivers.
1057+
1058+config PDA_POWER
1059+ tristate "Generic PDA/phone power driver"
1060+ help
1061+ Say Y here to enable generic power driver for PDAs and phones with
1062+ one or two external power supplies (AC/USB) connected to main and
1063+ backup batteries, and optional builtin charger.
1064+
1065+config APM_POWER
1066+ tristate "APM emulation for class batteries"
1067+ depends on APM_EMULATION
1068+ help
1069+ Say Y here to enable support APM status emulation using
1070+ battery class devices.
1071+
1072+config BATTERY_DS2760
1073+ tristate "DS2760 battery driver (HP iPAQ & others)"
1074+ select W1
1075+ select W1_SLAVE_DS2760
1076+ help
1077+ Say Y here to enable support for batteries with ds2760 chip.
1078+
1079+config BATTERY_PMU
1080+ tristate "Apple PMU battery"
1081+ depends on ADB_PMU
1082+ help
1083+ Say Y here to expose battery information on Apple machines
1084+ through the generic battery class.
1085+
1086+config BATTERY_OLPC
1087+ tristate "One Laptop Per Child battery"
1088+ depends on X86_32
1089+ help
1090+ Say Y to enable support for the battery on the OLPC laptop.
1091+
1092+# drivers below are not in battery2-2.6 tree
1093+
1094+config ADC_BATTERY
1095+ tristate "Generic ADC battery driver"
1096+ depends on ADC && POWER_SUPPLY
1097+ help
1098+ Say Y here to enable support for battery monitoring using generic ADC device.
1099+
1100+config IPAQ_MICRO_BATTERY
1101+ tristate "HP iPAQ Micro ASIC battery driver"
1102+ depends on IPAQ_MICRO && POWER_SUPPLY
1103+ help
1104+ Choose this option if you want to monitor battery status on
1105+ Compaq/HP iPAQ h3100 h3600
1106+
1107+config MCP_UCB1x00_SIMPAD_BATTERY
1108+ tristate "SIMpad Battery Reading Support"
1109+ depends on MCP_UCB1x00 && POWER_SUPPLY
1110+
1111+endif # POWER_SUPPLY
1112Index: linux-2.6.22/drivers/power/Makefile
1113===================================================================
1114--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1115+++ linux-2.6.22/drivers/power/Makefile 2007-08-23 12:13:52.000000000 +0200
1116@@ -0,0 +1,28 @@
1117+power_supply-objs := power_supply_core.o
1118+
1119+ifeq ($(CONFIG_SYSFS),y)
1120+power_supply-objs += power_supply_sysfs.o
1121+endif
1122+
1123+ifeq ($(CONFIG_LEDS_TRIGGERS),y)
1124+power_supply-objs += power_supply_leds.o
1125+endif
1126+
1127+ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y)
1128+EXTRA_CFLAGS += -DDEBUG
1129+endif
1130+
1131+obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
1132+
1133+obj-$(CONFIG_PDA_POWER) += pda_power.o
1134+obj-$(CONFIG_APM_POWER) += apm_power.o
1135+
1136+obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
1137+obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
1138+obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
1139+
1140+# drivers below are not in battery2-2.6 tree
1141+
1142+obj-$(CONFIG_ADC_BATTERY) += adc_battery.o
1143+obj-$(CONFIG_IPAQ_MICRO_BATTERY) += micro_battery.o
1144+obj-$(CONFIG_MCP_UCB1x00_SIMPAD_BATTERY) += simpad-battery.o
1145Index: linux-2.6.22/drivers/power/micro_battery.c
1146===================================================================
1147--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1148+++ linux-2.6.22/drivers/power/micro_battery.c 2007-08-23 12:25:20.000000000 +0200
1149@@ -0,0 +1,257 @@
1150+/*
1151+ * This program is free software; you can redistribute it and/or modify
1152+ * it under the terms of the GNU General Public License version 2 as
1153+ * published by the Free Software Foundation.
1154+ *
1155+ * h3600 atmel micro companion support, battery subdevice
1156+ * based on previous kernel 2.4 version
1157+ * Author : Alessandro Gardich <gremlin@gremlin.it>
1158+ *
1159+ */
1160+
1161+
1162+#include <linux/module.h>
1163+#include <linux/version.h>
1164+
1165+#include <linux/init.h>
1166+#include <linux/fs.h>
1167+#include <linux/interrupt.h>
1168+#include <linux/sched.h>
1169+#include <linux/pm.h>
1170+#include <linux/sysctl.h>
1171+#include <linux/proc_fs.h>
1172+#include <linux/delay.h>
1173+#include <linux/device.h>
1174+#include <linux/power_supply.h>
1175+#include <linux/platform_device.h>
1176+#include <linux/timer.h>
1177+
1178+#include <asm/arch/hardware.h>
1179+
1180+#include <asm/arch/h3600.h>
1181+#include <asm/arch/SA-1100.h>
1182+
1183+#include <asm/hardware/micro.h>
1184+
1185+#define BATT_PERIOD 10*HZ
1186+
1187+#define H3600_BATT_STATUS_HIGH 0x01
1188+#define H3600_BATT_STATUS_LOW 0x02
1189+#define H3600_BATT_STATUS_CRITICAL 0x04
1190+#define H3600_BATT_STATUS_CHARGING 0x08
1191+#define H3600_BATT_STATUS_CHARGEMAIN 0x10
1192+#define H3600_BATT_STATUS_DEAD 0x20 /* Battery will not charge */
1193+#define H3600_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */
1194+#define H3600_BATT_STATUS_FULL 0x40 /* Battery fully charged (and connected to AC) */
1195+#define H3600_BATT_STATUS_NOBATTERY 0x80
1196+#define H3600_BATT_STATUS_UNKNOWN 0xff
1197+
1198+
1199+//static struct power_supply_dev *micro_battery;
1200+
1201+static micro_private_t *p_micro;
1202+
1203+struct timer_list batt_timer;
1204+
1205+struct {
1206+ int ac;
1207+ int update_time;
1208+ int chemistry;
1209+ int voltage;
1210+ int temperature;
1211+ int flag;
1212+} micro_battery;
1213+
1214+static void micro_battery_receive (int len, unsigned char *data) {
1215+ if (0) {
1216+ printk(KERN_ERR "h3600_battery - AC = %02x\n", data[0]);
1217+ printk(KERN_ERR "h3600_battery - BAT1 chemistry = %02x\n", data[1]);
1218+ printk(KERN_ERR "h3600_battery - BAT1 voltage = %d %02x%02x\n", (data[3]<<8)+data[2], data[2], data[3]);
1219+ printk(KERN_ERR "h3600_battery - BAT1 status = %02x\n", data[4]);
1220+ }
1221+
1222+ micro_battery.ac = data[0];
1223+ micro_battery.chemistry = data[1];
1224+ micro_battery.voltage = ((((unsigned short)data[3]<<8)+data[2]) * 5000L ) * 1000 / 1024;
1225+ micro_battery.flag = data[4];
1226+
1227+ if (len == 9) {
1228+ if (0) {
1229+ printk(KERN_ERR "h3600_battery - BAT2 chemistry = %02x\n", data[5]);
1230+ printk(KERN_ERR "h3600_battery - BAT2 voltage = %d %02x%02x\n", (data[7]<<8)+data[6], data[6], data[7]);
1231+ printk(KERN_ERR "h3600_battery - BAT2 status = %02x\n", data[8]);
1232+ }
1233+ }
1234+}
1235+
1236+static void micro_temperature_receive (int len, unsigned char *data) {
1237+ micro_battery.temperature = ((unsigned short)data[1]<<8)+data[0];
1238+}
1239+
1240+void h3600_battery_read_status(unsigned long data) {
1241+
1242+ if (++data % 2)
1243+ h3600_micro_tx_msg(0x09,0,NULL);
1244+ else
1245+ h3600_micro_tx_msg(0x06,0,NULL);
1246+
1247+ batt_timer.expires += BATT_PERIOD;
1248+ batt_timer.data = data;
1249+
1250+ add_timer(&batt_timer);
1251+}
1252+
1253+int get_capacity(struct power_supply *b) {
1254+ switch (micro_battery.flag) {
1255+ case H3600_BATT_STATUS_HIGH : return 100; break;
1256+ case H3600_BATT_STATUS_LOW : return 50; break;
1257+ case H3600_BATT_STATUS_CRITICAL : return 5; break;
1258+ default: break;
1259+ }
1260+ return 0;
1261+}
1262+
1263+int get_status(struct power_supply *b) {
1264+
1265+ if (micro_battery.flag == H3600_BATT_STATUS_UNKNOWN)
1266+ return POWER_SUPPLY_STATUS_UNKNOWN;
1267+
1268+ if (micro_battery.flag & H3600_BATT_STATUS_FULL)
1269+ return POWER_SUPPLY_STATUS_FULL;
1270+
1271+ if ((micro_battery.flag & H3600_BATT_STATUS_CHARGING) ||
1272+ (micro_battery.flag & H3600_BATT_STATUS_CHARGEMAIN))
1273+ return POWER_SUPPLY_STATUS_CHARGING;
1274+
1275+ return POWER_SUPPLY_STATUS_DISCHARGING;
1276+}
1277+
1278+static int micro_batt_get_property(struct power_supply *b,
1279+ enum power_supply_property psp,
1280+ union power_supply_propval *val)
1281+{
1282+ switch (psp) {
1283+ case POWER_SUPPLY_PROP_STATUS:
1284+ val->intval = get_status(b);
1285+ break;
1286+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
1287+ val->intval = 4700000;
1288+ break;
1289+ case POWER_SUPPLY_PROP_CAPACITY:
1290+ val->intval = get_capacity(b);
1291+ break;
1292+ case POWER_SUPPLY_PROP_TEMP:
1293+ val->intval = micro_battery.temperature;
1294+ break;
1295+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1296+ val->intval = micro_battery.voltage;
1297+ break;
1298+ default:
1299+ return -EINVAL;
1300+ };
1301+
1302+ return 0;
1303+}
1304+
1305+static enum power_supply_property micro_batt_props[] = {
1306+ POWER_SUPPLY_PROP_STATUS,
1307+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1308+ POWER_SUPPLY_PROP_CAPACITY,
1309+ POWER_SUPPLY_PROP_TEMP,
1310+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
1311+};
1312+
1313+static struct power_supply h3600_battery = {
1314+ .name = "main-battery",
1315+ .properties = micro_batt_props,
1316+ .num_properties = ARRAY_SIZE(micro_batt_props),
1317+ .get_property = micro_batt_get_property,
1318+ .use_for_apm = 1,
1319+};
1320+
1321+static int micro_batt_probe (struct platform_device *pdev)
1322+{
1323+ if (1) printk(KERN_ERR "micro battery probe : begin\n");
1324+
1325+ power_supply_register(&pdev->dev, &h3600_battery);
1326+
1327+ { /*--- callback ---*/
1328+ p_micro = platform_get_drvdata(pdev);
1329+ spin_lock(p_micro->lock);
1330+ p_micro->h_batt = micro_battery_receive;
1331+ p_micro->h_temp = micro_temperature_receive;
1332+ spin_unlock(p_micro->lock);
1333+ }
1334+
1335+ { /*--- timer ---*/
1336+ init_timer(&batt_timer);
1337+ batt_timer.expires = jiffies + BATT_PERIOD;
1338+ batt_timer.data = 0;
1339+ batt_timer.function = h3600_battery_read_status;
1340+
1341+ add_timer(&batt_timer);
1342+ }
1343+
1344+ if (1) printk(KERN_ERR "micro battery probe : end\n");
1345+ return 0;
1346+}
1347+
1348+static int micro_batt_remove (struct platform_device *pdev)
1349+{
1350+ power_supply_unregister(&h3600_battery);
1351+ { /*--- callback ---*/
1352+ init_timer(&batt_timer);
1353+ p_micro->h_batt = NULL;
1354+ p_micro->h_temp = NULL;
1355+ spin_unlock(p_micro->lock);
1356+ }
1357+ { /*--- timer ---*/
1358+ del_timer_sync(&batt_timer);
1359+ }
1360+ return 0;
1361+}
1362+
1363+static int micro_batt_suspend ( struct platform_device *pdev, pm_message_t state)
1364+{
1365+ { /*--- timer ---*/
1366+ del_timer(&batt_timer);
1367+ }
1368+ return 0;
1369+}
1370+
1371+static int micro_batt_resume ( struct platform_device *pdev)
1372+{
1373+ { /*--- timer ---*/
1374+ add_timer(&batt_timer);
1375+ }
1376+ return 0;
1377+}
1378+
1379+struct platform_driver micro_batt_device_driver = {
1380+ .driver = {
1381+ .name = "h3600-micro-battery",
1382+ },
1383+ .probe = micro_batt_probe,
1384+ .remove = micro_batt_remove,
1385+ .suspend = micro_batt_suspend,
1386+ .resume = micro_batt_resume,
1387+};
1388+
1389+static int micro_batt_init (void)
1390+{
1391+ return platform_driver_register(&micro_batt_device_driver);
1392+}
1393+
1394+static void micro_batt_cleanup (void)
1395+{
1396+ platform_driver_unregister (&micro_batt_device_driver);
1397+}
1398+
1399+module_init (micro_batt_init);
1400+module_exit (micro_batt_cleanup);
1401+
1402+MODULE_LICENSE("GPL");
1403+MODULE_AUTHOR("gremlin.it");
1404+MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery");
1405+
1406+
1407Index: linux-2.6.22/drivers/power/olpc_battery.c
1408===================================================================
1409--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1410+++ linux-2.6.22/drivers/power/olpc_battery.c 2007-08-23 12:13:52.000000000 +0200
1411@@ -0,0 +1,302 @@
1412+/*
1413+ * Battery driver for One Laptop Per Child board.
1414+ *
1415+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
1416+ *
1417+ * This program is free software; you can redistribute it and/or modify
1418+ * it under the terms of the GNU General Public License version 2 as
1419+ * published by the Free Software Foundation.
1420+ */
1421+
1422+#include <linux/module.h>
1423+#include <linux/err.h>
1424+#include <linux/platform_device.h>
1425+#include <linux/power_supply.h>
1426+#include <linux/jiffies.h>
1427+#include <linux/sched.h>
1428+#include <asm/io.h>
1429+
1430+#define wBAT_VOLTAGE 0xf900 /* *9.76/32, mV */
1431+#define wBAT_CURRENT 0xf902 /* *15.625/120, mA */
1432+#define wBAT_TEMP 0xf906 /* *256/1000, °C */
1433+#define wAMB_TEMP 0xf908 /* *256/1000, °C */
1434+#define SOC 0xf910 /* percentage */
1435+#define sMBAT_STATUS 0xfaa4
1436+#define sBAT_PRESENT 1
1437+#define sBAT_FULL 2
1438+#define sBAT_DESTROY 4 /* what is this exactly? */
1439+#define sBAT_LOW 32
1440+#define sBAT_DISCHG 64
1441+#define sMCHARGE_STATUS 0xfaa5
1442+#define sBAT_CHARGE 1
1443+#define sBAT_OVERTEMP 4
1444+#define sBAT_NiMH 8
1445+#define sPOWER_FLAG 0xfa40
1446+#define ADAPTER_IN 1
1447+
1448+/*********************************************************************
1449+ * EC locking and access
1450+ *********************************************************************/
1451+
1452+static int lock_ec(void)
1453+{
1454+ unsigned long timeo = jiffies + HZ / 20;
1455+
1456+ while (1) {
1457+ unsigned char lock = inb(0x6c) & 0x80;
1458+ if (!lock)
1459+ return 0;
1460+ if (time_after(jiffies, timeo)) {
1461+ printk(KERN_ERR "olpc_battery: failed to lock EC for "
1462+ "battery access\n");
1463+ return 1;
1464+ }
1465+ yield();
1466+ }
1467+}
1468+
1469+static void unlock_ec(void)
1470+{
1471+ outb(0xff, 0x6c);
1472+ return;
1473+}
1474+
1475+static unsigned char read_ec_byte(unsigned short adr)
1476+{
1477+ outb(adr >> 8, 0x381);
1478+ outb(adr, 0x382);
1479+ return inb(0x383);
1480+}
1481+
1482+static unsigned short read_ec_word(unsigned short adr)
1483+{
1484+ return (read_ec_byte(adr) << 8) | read_ec_byte(adr + 1);
1485+}
1486+
1487+/*********************************************************************
1488+ * Power
1489+ *********************************************************************/
1490+
1491+static int olpc_ac_get_prop(struct power_supply *psy,
1492+ enum power_supply_property psp,
1493+ union power_supply_propval *val)
1494+{
1495+ int ret = 0;
1496+
1497+ if (lock_ec())
1498+ return -EIO;
1499+
1500+ switch (psp) {
1501+ case POWER_SUPPLY_PROP_ONLINE:
1502+ if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
1503+ ret = -ENODEV;
1504+ goto out;
1505+ }
1506+ val->intval = !!(read_ec_byte(sPOWER_FLAG) & ADAPTER_IN);
1507+ break;
1508+ default:
1509+ ret = -EINVAL;
1510+ break;
1511+ }
1512+out:
1513+ unlock_ec();
1514+ return ret;
1515+}
1516+
1517+static enum power_supply_property olpc_ac_props[] = {
1518+ POWER_SUPPLY_PROP_ONLINE,
1519+};
1520+
1521+static struct power_supply olpc_ac = {
1522+ .name = "olpc-ac",
1523+ .type = POWER_SUPPLY_TYPE_MAINS,
1524+ .properties = olpc_ac_props,
1525+ .num_properties = ARRAY_SIZE(olpc_ac_props),
1526+ .get_property = olpc_ac_get_prop,
1527+};
1528+
1529+/*********************************************************************
1530+ * Battery properties
1531+ *********************************************************************/
1532+
1533+static int olpc_bat_get_property(struct power_supply *psy,
1534+ enum power_supply_property psp,
1535+ union power_supply_propval *val)
1536+{
1537+ int ret = 0;
1538+
1539+ if (lock_ec())
1540+ return -EIO;
1541+
1542+ switch (psp) {
1543+ case POWER_SUPPLY_PROP_STATUS:
1544+ {
1545+ int status = POWER_SUPPLY_STATUS_UNKNOWN;
1546+
1547+ val->intval = read_ec_byte(sMBAT_STATUS);
1548+
1549+ if (!(val->intval & sBAT_PRESENT)) {
1550+ ret = -ENODEV;
1551+ goto out;
1552+ }
1553+
1554+ if (val->intval & sBAT_DISCHG)
1555+ status = POWER_SUPPLY_STATUS_DISCHARGING;
1556+ else if (val->intval & sBAT_FULL)
1557+ status = POWER_SUPPLY_STATUS_FULL;
1558+
1559+ val->intval = read_ec_byte(sMCHARGE_STATUS);
1560+ if (val->intval & sBAT_CHARGE)
1561+ status = POWER_SUPPLY_STATUS_CHARGING;
1562+
1563+ val->intval = status;
1564+ break;
1565+ }
1566+ case POWER_SUPPLY_PROP_PRESENT:
1567+ val->intval = !!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT);
1568+ break;
1569+ case POWER_SUPPLY_PROP_HEALTH:
1570+ val->intval = read_ec_byte(sMCHARGE_STATUS);
1571+ if (val->intval & sBAT_OVERTEMP)
1572+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
1573+ else
1574+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
1575+ break;
1576+ case POWER_SUPPLY_PROP_TECHNOLOGY:
1577+ val->intval = read_ec_byte(sMCHARGE_STATUS);
1578+ if (val->intval & sBAT_NiMH)
1579+ val->intval = POWER_SUPPLY_TECHNOLOGY_NIMH;
1580+ else
1581+ val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
1582+ break;
1583+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
1584+ val->intval = read_ec_byte(wBAT_VOLTAGE) * 9760L / 32;
1585+ break;
1586+ case POWER_SUPPLY_PROP_CURRENT_AVG:
1587+ val->intval = read_ec_byte(wBAT_CURRENT) * 15625L / 120;
1588+ break;
1589+ case POWER_SUPPLY_PROP_CAPACITY:
1590+ val->intval = read_ec_byte(SOC);
1591+ break;
1592+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
1593+ val->intval = read_ec_byte(sMBAT_STATUS);
1594+ if (val->intval & sBAT_FULL)
1595+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
1596+ else if (val->intval & sBAT_LOW)
1597+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
1598+ else
1599+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
1600+ break;
1601+ case POWER_SUPPLY_PROP_TEMP:
1602+ val->intval = read_ec_byte(wBAT_TEMP) * 256 / 100;
1603+ break;
1604+ case POWER_SUPPLY_PROP_TEMP_AMBIENT:
1605+ val->intval = read_ec_byte(wAMB_TEMP) * 256 / 100;
1606+ break;
1607+ default:
1608+ ret = -EINVAL;
1609+ break;
1610+ }
1611+
1612+out:
1613+ unlock_ec();
1614+ return ret;
1615+}
1616+
1617+static enum power_supply_property olpc_bat_props[] = {
1618+ POWER_SUPPLY_PROP_STATUS,
1619+ POWER_SUPPLY_PROP_PRESENT,
1620+ POWER_SUPPLY_PROP_HEALTH,
1621+ POWER_SUPPLY_PROP_TECHNOLOGY,
1622+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
1623+ POWER_SUPPLY_PROP_CURRENT_AVG,
1624+ POWER_SUPPLY_PROP_CAPACITY,
1625+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
1626+ POWER_SUPPLY_PROP_TEMP,
1627+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
1628+};
1629+
1630+/*********************************************************************
1631+ * Initialisation
1632+ *********************************************************************/
1633+
1634+static struct platform_device *bat_pdev;
1635+
1636+static struct power_supply olpc_bat = {
1637+ .properties = olpc_bat_props,
1638+ .num_properties = ARRAY_SIZE(olpc_bat_props),
1639+ .get_property = olpc_bat_get_property,
1640+ .use_for_apm = 1,
1641+};
1642+
1643+static int __init olpc_bat_init(void)
1644+{
1645+ int ret = 0;
1646+ unsigned short tmp;
1647+
1648+ if (!request_region(0x380, 4, "olpc-battery")) {
1649+ ret = -EIO;
1650+ goto region_failed;
1651+ }
1652+
1653+ if (lock_ec()) {
1654+ ret = -EIO;
1655+ goto lock_failed;
1656+ }
1657+
1658+ tmp = read_ec_word(0xfe92);
1659+ unlock_ec();
1660+
1661+ if (tmp != 0x380) {
1662+ /* Doesn't look like OLPC EC */
1663+ ret = -ENODEV;
1664+ goto not_olpc_ec;
1665+ }
1666+
1667+ bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
1668+ if (IS_ERR(bat_pdev)) {
1669+ ret = PTR_ERR(bat_pdev);
1670+ goto pdev_failed;
1671+ }
1672+
1673+ ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
1674+ if (ret)
1675+ goto ac_failed;
1676+
1677+ olpc_bat.name = bat_pdev->name;
1678+
1679+ ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
1680+ if (ret)
1681+ goto battery_failed;
1682+
1683+ goto success;
1684+
1685+battery_failed:
1686+ power_supply_unregister(&olpc_ac);
1687+ac_failed:
1688+ platform_device_unregister(bat_pdev);
1689+pdev_failed:
1690+not_olpc_ec:
1691+lock_failed:
1692+ release_region(0x380, 4);
1693+region_failed:
1694+success:
1695+ return ret;
1696+}
1697+
1698+static void __exit olpc_bat_exit(void)
1699+{
1700+ power_supply_unregister(&olpc_bat);
1701+ power_supply_unregister(&olpc_ac);
1702+ platform_device_unregister(bat_pdev);
1703+ release_region(0x380, 4);
1704+ return;
1705+}
1706+
1707+module_init(olpc_bat_init);
1708+module_exit(olpc_bat_exit);
1709+
1710+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1711+MODULE_LICENSE("GPL");
1712+MODULE_DESCRIPTION("Battery driver for One Laptop Per Child "
1713+ "($100 laptop) board.");
1714Index: linux-2.6.22/drivers/power/pda_power.c
1715===================================================================
1716--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1717+++ linux-2.6.22/drivers/power/pda_power.c 2007-08-23 12:13:52.000000000 +0200
1718@@ -0,0 +1,263 @@
1719+/*
1720+ * Common power driver for PDAs and phones with one or two external
1721+ * power supplies (AC/USB) connected to main and backup batteries,
1722+ * and optional builtin charger.
1723+ *
1724+ * Copyright 2007 Anton Vorontsov <cbou@mail.ru>
1725+ *
1726+ * This program is free software; you can redistribute it and/or modify
1727+ * it under the terms of the GNU General Public License version 2 as
1728+ * published by the Free Software Foundation.
1729+ */
1730+
1731+#include <linux/module.h>
1732+#include <linux/platform_device.h>
1733+#include <linux/interrupt.h>
1734+#include <linux/power_supply.h>
1735+#include <linux/pda_power.h>
1736+#include <linux/timer.h>
1737+#include <linux/jiffies.h>
1738+
1739+static inline unsigned int get_irq_flags(struct resource *res)
1740+{
1741+ unsigned int flags = IRQF_DISABLED | IRQF_SHARED;
1742+
1743+ flags |= res->flags & IRQF_TRIGGER_MASK;
1744+
1745+ return flags;
1746+}
1747+
1748+static struct device *dev;
1749+static struct pda_power_pdata *pdata;
1750+static struct resource *ac_irq, *usb_irq;
1751+static struct timer_list charger_timer;
1752+static struct timer_list supply_timer;
1753+
1754+static int pda_power_get_property(struct power_supply *psy,
1755+ enum power_supply_property psp,
1756+ union power_supply_propval *val)
1757+{
1758+ switch (psp) {
1759+ case POWER_SUPPLY_PROP_ONLINE:
1760+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
1761+ val->intval = pdata->is_ac_online ?
1762+ pdata->is_ac_online() : 0;
1763+ else
1764+ val->intval = pdata->is_usb_online ?
1765+ pdata->is_usb_online() : 0;
1766+ break;
1767+ default:
1768+ return -EINVAL;
1769+ }
1770+ return 0;
1771+}
1772+
1773+static enum power_supply_property pda_power_props[] = {
1774+ POWER_SUPPLY_PROP_ONLINE,
1775+};
1776+
1777+static char *pda_power_supplied_to[] = {
1778+ "main-battery",
1779+ "backup-battery",
1780+};
1781+
1782+static struct power_supply pda_power_supplies[] = {
1783+ {
1784+ .name = "ac",
1785+ .type = POWER_SUPPLY_TYPE_MAINS,
1786+ .supplied_to = pda_power_supplied_to,
1787+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
1788+ .properties = pda_power_props,
1789+ .num_properties = ARRAY_SIZE(pda_power_props),
1790+ .get_property = pda_power_get_property,
1791+ },
1792+ {
1793+ .name = "usb",
1794+ .type = POWER_SUPPLY_TYPE_USB,
1795+ .supplied_to = pda_power_supplied_to,
1796+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
1797+ .properties = pda_power_props,
1798+ .num_properties = ARRAY_SIZE(pda_power_props),
1799+ .get_property = pda_power_get_property,
1800+ },
1801+};
1802+
1803+static void update_charger(void)
1804+{
1805+ if (!pdata->set_charge)
1806+ return;
1807+
1808+ if (pdata->is_ac_online && pdata->is_ac_online()) {
1809+ dev_dbg(dev, "charger on (AC)\n");
1810+ pdata->set_charge(PDA_POWER_CHARGE_AC);
1811+ }
1812+ else if (pdata->is_usb_online && pdata->is_usb_online()) {
1813+ dev_dbg(dev, "charger on (USB)\n");
1814+ pdata->set_charge(PDA_POWER_CHARGE_USB);
1815+ }
1816+ else {
1817+ dev_dbg(dev, "charger off\n");
1818+ pdata->set_charge(0);
1819+ }
1820+
1821+ return;
1822+}
1823+
1824+static void supply_timer_func(unsigned long irq)
1825+{
1826+ if (ac_irq && irq == ac_irq->start)
1827+ power_supply_changed(&pda_power_supplies[0]);
1828+ else if (usb_irq && irq == usb_irq->start)
1829+ power_supply_changed(&pda_power_supplies[1]);
1830+ return;
1831+}
1832+
1833+static void charger_timer_func(unsigned long irq)
1834+{
1835+ update_charger();
1836+
1837+ /* Okay, charger set. Now wait a bit before notifying supplicants,
1838+ * charge power should stabilize. */
1839+ supply_timer.data = irq;
1840+ mod_timer(&supply_timer,
1841+ jiffies + msecs_to_jiffies(pdata->wait_for_charger));
1842+ return;
1843+}
1844+
1845+static irqreturn_t power_changed_isr(int irq, void *unused)
1846+{
1847+ /* Wait a bit before reading ac/usb line status and setting charger,
1848+ * because ac/usb status readings may lag from irq. */
1849+ charger_timer.data = irq;
1850+ mod_timer(&charger_timer,
1851+ jiffies + msecs_to_jiffies(pdata->wait_for_status));
1852+ return IRQ_HANDLED;
1853+}
1854+
1855+static int pda_power_probe(struct platform_device *pdev)
1856+{
1857+ int ret = 0;
1858+
1859+ dev = &pdev->dev;
1860+
1861+ if (pdev->id != -1) {
1862+ dev_err(dev, "it's meaningless to register several "
1863+ "pda_powers, use id = -1\n");
1864+ ret = -EINVAL;
1865+ goto wrongid;
1866+ }
1867+
1868+ pdata = pdev->dev.platform_data;
1869+
1870+ update_charger();
1871+
1872+ if (!pdata->wait_for_status)
1873+ pdata->wait_for_status = 500;
1874+
1875+ if (!pdata->wait_for_charger)
1876+ pdata->wait_for_charger = 500;
1877+
1878+ setup_timer(&charger_timer, charger_timer_func, 0);
1879+ setup_timer(&supply_timer, supply_timer_func, 0);
1880+
1881+ ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
1882+ usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
1883+ if (!ac_irq && !usb_irq) {
1884+ dev_err(dev, "no ac/usb irq specified\n");
1885+ ret = -ENODEV;
1886+ goto noirqs;
1887+ }
1888+
1889+ if (pdata->supplied_to) {
1890+ pda_power_supplies[0].supplied_to = pdata->supplied_to;
1891+ pda_power_supplies[1].supplied_to = pdata->supplied_to;
1892+ pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
1893+ pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
1894+ }
1895+
1896+ ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
1897+ if (ret) {
1898+ dev_err(dev, "failed to register %s power supply\n",
1899+ pda_power_supplies[0].name);
1900+ goto supply0_failed;
1901+ }
1902+
1903+ ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
1904+ if (ret) {
1905+ dev_err(dev, "failed to register %s power supply\n",
1906+ pda_power_supplies[1].name);
1907+ goto supply1_failed;
1908+ }
1909+
1910+ if (ac_irq) {
1911+ ret = request_irq(ac_irq->start, power_changed_isr,
1912+ get_irq_flags(ac_irq), ac_irq->name,
1913+ &pda_power_supplies[0]);
1914+ if (ret) {
1915+ dev_err(dev, "request ac irq failed\n");
1916+ goto ac_irq_failed;
1917+ }
1918+ }
1919+
1920+ if (usb_irq) {
1921+ ret = request_irq(usb_irq->start, power_changed_isr,
1922+ get_irq_flags(usb_irq), usb_irq->name,
1923+ &pda_power_supplies[1]);
1924+ if (ret) {
1925+ dev_err(dev, "request usb irq failed\n");
1926+ goto usb_irq_failed;
1927+ }
1928+ }
1929+
1930+ goto success;
1931+
1932+usb_irq_failed:
1933+ if (ac_irq)
1934+ free_irq(ac_irq->start, &pda_power_supplies[0]);
1935+ac_irq_failed:
1936+ power_supply_unregister(&pda_power_supplies[1]);
1937+supply1_failed:
1938+ power_supply_unregister(&pda_power_supplies[0]);
1939+supply0_failed:
1940+noirqs:
1941+wrongid:
1942+success:
1943+ return ret;
1944+}
1945+
1946+static int pda_power_remove(struct platform_device *pdev)
1947+{
1948+ if (usb_irq)
1949+ free_irq(usb_irq->start, &pda_power_supplies[1]);
1950+ if (ac_irq)
1951+ free_irq(ac_irq->start, &pda_power_supplies[0]);
1952+ del_timer_sync(&charger_timer);
1953+ del_timer_sync(&supply_timer);
1954+ power_supply_unregister(&pda_power_supplies[1]);
1955+ power_supply_unregister(&pda_power_supplies[0]);
1956+ return 0;
1957+}
1958+
1959+static struct platform_driver pda_power_pdrv = {
1960+ .driver = {
1961+ .name = "pda-power",
1962+ },
1963+ .probe = pda_power_probe,
1964+ .remove = pda_power_remove,
1965+};
1966+
1967+static int __init pda_power_init(void)
1968+{
1969+ return platform_driver_register(&pda_power_pdrv);
1970+}
1971+
1972+static void __exit pda_power_exit(void)
1973+{
1974+ platform_driver_unregister(&pda_power_pdrv);
1975+ return;
1976+}
1977+
1978+module_init(pda_power_init);
1979+module_exit(pda_power_exit);
1980+MODULE_LICENSE("GPL");
1981+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
1982Index: linux-2.6.22/drivers/power/pmu_battery.c
1983===================================================================
1984--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1985+++ linux-2.6.22/drivers/power/pmu_battery.c 2007-08-23 12:13:52.000000000 +0200
1986@@ -0,0 +1,215 @@
1987+/*
1988+ * Battery class driver for Apple PMU
1989+ *
1990+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
1991+ *
1992+ * This program is free software; you can redistribute it and/or modify
1993+ * it under the terms of the GNU General Public License version 2 as
1994+ * published by the Free Software Foundation.
1995+ */
1996+
1997+#include <linux/module.h>
1998+#include <linux/platform_device.h>
1999+#include <linux/err.h>
2000+#include <linux/power_supply.h>
2001+#include <linux/adb.h>
2002+#include <linux/pmu.h>
2003+
2004+static struct pmu_battery_dev {
2005+ struct power_supply bat;
2006+ struct pmu_battery_info *pbi;
2007+ char name[16];
2008+ int propval;
2009+} *pbats[PMU_MAX_BATTERIES];
2010+
2011+#define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
2012+
2013+/*********************************************************************
2014+ * Power
2015+ *********************************************************************/
2016+
2017+static int pmu_get_ac_prop(struct power_supply *psy,
2018+ enum power_supply_property psp,
2019+ union power_supply_propval *val)
2020+{
2021+ switch (psp) {
2022+ case POWER_SUPPLY_PROP_ONLINE:
2023+ val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
2024+ (pmu_battery_count == 0);
2025+ break;
2026+ default:
2027+ return -EINVAL;
2028+ }
2029+
2030+ return 0;
2031+}
2032+
2033+static enum power_supply_property pmu_ac_props[] = {
2034+ POWER_SUPPLY_PROP_ONLINE,
2035+};
2036+
2037+static struct power_supply pmu_ac = {
2038+ .name = "pmu-ac",
2039+ .type = POWER_SUPPLY_TYPE_MAINS,
2040+ .properties = pmu_ac_props,
2041+ .num_properties = ARRAY_SIZE(pmu_ac_props),
2042+ .get_property = pmu_get_ac_prop,
2043+};
2044+
2045+/*********************************************************************
2046+ * Battery properties
2047+ *********************************************************************/
2048+
2049+static char *pmu_batt_types[] = {
2050+ "Smart", "Comet", "Hooper", "Unknown"
2051+};
2052+
2053+static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
2054+{
2055+ switch (pbi->flags & PMU_BATT_TYPE_MASK) {
2056+ case PMU_BATT_TYPE_SMART:
2057+ return pmu_batt_types[0];
2058+ case PMU_BATT_TYPE_COMET:
2059+ return pmu_batt_types[1];
2060+ case PMU_BATT_TYPE_HOOPER:
2061+ return pmu_batt_types[2];
2062+ default: break;
2063+ }
2064+ return pmu_batt_types[3];
2065+}
2066+
2067+static int pmu_bat_get_property(struct power_supply *psy,
2068+ enum power_supply_property psp,
2069+ union power_supply_propval *val)
2070+{
2071+ struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
2072+ struct pmu_battery_info *pbi = pbat->pbi;
2073+
2074+ switch (psp) {
2075+ case POWER_SUPPLY_PROP_STATUS:
2076+ if (pbi->flags & PMU_BATT_CHARGING)
2077+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
2078+ else
2079+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
2080+ break;
2081+ case POWER_SUPPLY_PROP_PRESENT:
2082+ val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
2083+ break;
2084+ case POWER_SUPPLY_PROP_MODEL_NAME:
2085+ val->strval = pmu_bat_get_model_name(pbi);
2086+ break;
2087+ case POWER_SUPPLY_PROP_ENERGY_AVG:
2088+ val->intval = pbi->charge * 1000; /* mWh -> µWh */
2089+ break;
2090+ case POWER_SUPPLY_PROP_ENERGY_FULL:
2091+ val->intval = pbi->max_charge * 1000; /* mWh -> µWh */
2092+ break;
2093+ case POWER_SUPPLY_PROP_CURRENT_AVG:
2094+ val->intval = pbi->amperage * 1000; /* mA -> µA */
2095+ break;
2096+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
2097+ val->intval = pbi->voltage * 1000; /* mV -> µV */
2098+ break;
2099+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
2100+ val->intval = pbi->time_remaining;
2101+ break;
2102+ default:
2103+ return -EINVAL;
2104+ }
2105+
2106+ return 0;
2107+}
2108+
2109+static enum power_supply_property pmu_bat_props[] = {
2110+ POWER_SUPPLY_PROP_STATUS,
2111+ POWER_SUPPLY_PROP_PRESENT,
2112+ POWER_SUPPLY_PROP_MODEL_NAME,
2113+ POWER_SUPPLY_PROP_ENERGY_AVG,
2114+ POWER_SUPPLY_PROP_ENERGY_FULL,
2115+ POWER_SUPPLY_PROP_CURRENT_AVG,
2116+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
2117+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
2118+};
2119+
2120+/*********************************************************************
2121+ * Initialisation
2122+ *********************************************************************/
2123+
2124+static struct platform_device *bat_pdev;
2125+
2126+static int __init pmu_bat_init(void)
2127+{
2128+ int ret;
2129+ int i;
2130+
2131+ bat_pdev = platform_device_register_simple("pmu-battery",
2132+ 0, NULL, 0);
2133+ if (IS_ERR(bat_pdev)) {
2134+ ret = PTR_ERR(bat_pdev);
2135+ goto pdev_register_failed;
2136+ }
2137+
2138+ ret = power_supply_register(&bat_pdev->dev, &pmu_ac);
2139+ if (ret)
2140+ goto ac_register_failed;
2141+
2142+ for (i = 0; i < pmu_battery_count; i++) {
2143+ struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
2144+ GFP_KERNEL);
2145+ if (!pbat)
2146+ break;
2147+
2148+ sprintf(pbat->name, "PMU battery %d", i);
2149+ pbat->bat.name = pbat->name;
2150+ pbat->bat.properties = pmu_bat_props;
2151+ pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
2152+ pbat->bat.get_property = pmu_bat_get_property;
2153+ pbat->pbi = &pmu_batteries[i];
2154+
2155+ ret = power_supply_register(&bat_pdev->dev, &pbat->bat);
2156+ if (ret) {
2157+ kfree(pbat);
2158+ goto battery_register_failed;
2159+ }
2160+ pbats[i] = pbat;
2161+ }
2162+
2163+ goto success;
2164+
2165+battery_register_failed:
2166+ while (i--) {
2167+ if (!pbats[i])
2168+ continue;
2169+ power_supply_unregister(&pbats[i]->bat);
2170+ kfree(pbats[i]);
2171+ }
2172+ power_supply_unregister(&pmu_ac);
2173+ac_register_failed:
2174+ platform_device_unregister(bat_pdev);
2175+pdev_register_failed:
2176+success:
2177+ return ret;
2178+}
2179+
2180+static void __exit pmu_bat_exit(void)
2181+{
2182+ int i;
2183+
2184+ for (i = 0; i < PMU_MAX_BATTERIES; i++) {
2185+ if (!pbats[i])
2186+ continue;
2187+ power_supply_unregister(&pbats[i]->bat);
2188+ kfree(pbats[i]);
2189+ }
2190+ power_supply_unregister(&pmu_ac);
2191+ platform_device_unregister(bat_pdev);
2192+
2193+ return;
2194+}
2195+
2196+module_init(pmu_bat_init);
2197+module_exit(pmu_bat_exit);
2198+
2199+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
2200+MODULE_LICENSE("GPL");
2201+MODULE_DESCRIPTION("PMU battery driver");
2202Index: linux-2.6.22/drivers/power/power_supply_core.c
2203===================================================================
2204--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2205+++ linux-2.6.22/drivers/power/power_supply_core.c 2007-08-23 12:13:52.000000000 +0200
2206@@ -0,0 +1,168 @@
2207+/*
2208+ * Universal power supply monitor class
2209+ *
2210+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2211+ * Copyright (c) 2004 Szabolcs Gyurko
2212+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2213+ *
2214+ * Modified: 2004, Oct Szabolcs Gyurko
2215+ *
2216+ * You may use this code as per GPL version 2
2217+ */
2218+
2219+#include <linux/module.h>
2220+#include <linux/types.h>
2221+#include <linux/init.h>
2222+#include <linux/device.h>
2223+#include <linux/err.h>
2224+#include <linux/power_supply.h>
2225+#include "power_supply.h"
2226+
2227+struct class *power_supply_class;
2228+
2229+static void power_supply_changed_work(struct work_struct *work)
2230+{
2231+ struct power_supply *psy = container_of(work, struct power_supply,
2232+ changed_work);
2233+ int i;
2234+
2235+ dev_dbg(psy->dev, "%s\n", __FUNCTION__);
2236+
2237+ for (i = 0; i < psy->num_supplicants; i++) {
2238+ struct device *dev;
2239+
2240+ down(&power_supply_class->sem);
2241+ list_for_each_entry(dev, &power_supply_class->devices, node) {
2242+ struct power_supply *pst = dev_get_drvdata(dev);
2243+
2244+ if (!strcmp(psy->supplied_to[i], pst->name)) {
2245+ if (pst->external_power_changed)
2246+ pst->external_power_changed(pst);
2247+ }
2248+ }
2249+ up(&power_supply_class->sem);
2250+ }
2251+
2252+ power_supply_update_leds(psy);
2253+
2254+ kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
2255+
2256+ return;
2257+}
2258+
2259+void power_supply_changed(struct power_supply *psy)
2260+{
2261+ dev_dbg(psy->dev, "%s\n", __FUNCTION__);
2262+
2263+ schedule_work(&psy->changed_work);
2264+
2265+ return;
2266+}
2267+
2268+int power_supply_am_i_supplied(struct power_supply *psy)
2269+{
2270+ union power_supply_propval ret = {0,};
2271+ struct device *dev;
2272+
2273+ down(&power_supply_class->sem);
2274+ list_for_each_entry(dev, &power_supply_class->devices, node) {
2275+ struct power_supply *epsy = dev_get_drvdata(dev);
2276+ int i;
2277+
2278+ for (i = 0; i < epsy->num_supplicants; i++) {
2279+ if (!strcmp(epsy->supplied_to[i], psy->name)) {
2280+ if (epsy->get_property(epsy,
2281+ POWER_SUPPLY_PROP_ONLINE, &ret))
2282+ continue;
2283+ if (ret.intval)
2284+ goto out;
2285+ }
2286+ }
2287+ }
2288+out:
2289+ up(&power_supply_class->sem);
2290+
2291+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
2292+
2293+ return ret.intval;
2294+}
2295+
2296+int power_supply_register(struct device *parent, struct power_supply *psy)
2297+{
2298+ int rc = 0;
2299+
2300+ psy->dev = device_create(power_supply_class, parent, 0,
2301+ "%s", psy->name);
2302+ if (IS_ERR(psy->dev)) {
2303+ rc = PTR_ERR(psy->dev);
2304+ goto dev_create_failed;
2305+ }
2306+
2307+ dev_set_drvdata(psy->dev, psy);
2308+
2309+ INIT_WORK(&psy->changed_work, power_supply_changed_work);
2310+
2311+ rc = power_supply_create_attrs(psy);
2312+ if (rc)
2313+ goto create_attrs_failed;
2314+
2315+ rc = power_supply_create_triggers(psy);
2316+ if (rc)
2317+ goto create_triggers_failed;
2318+
2319+ power_supply_changed(psy);
2320+
2321+ goto success;
2322+
2323+create_triggers_failed:
2324+ power_supply_remove_attrs(psy);
2325+create_attrs_failed:
2326+ device_unregister(psy->dev);
2327+dev_create_failed:
2328+success:
2329+ return rc;
2330+}
2331+
2332+void power_supply_unregister(struct power_supply *psy)
2333+{
2334+ flush_scheduled_work();
2335+ power_supply_remove_triggers(psy);
2336+ power_supply_remove_attrs(psy);
2337+ device_unregister(psy->dev);
2338+ return;
2339+}
2340+
2341+static int __init power_supply_class_init(void)
2342+{
2343+ power_supply_class = class_create(THIS_MODULE, "power_supply");
2344+
2345+ if (IS_ERR(power_supply_class))
2346+ return PTR_ERR(power_supply_class);
2347+
2348+ power_supply_class->dev_uevent = power_supply_uevent;
2349+
2350+ return 0;
2351+}
2352+
2353+static void __exit power_supply_class_exit(void)
2354+{
2355+ class_destroy(power_supply_class);
2356+ return;
2357+}
2358+
2359+EXPORT_SYMBOL_GPL(power_supply_changed);
2360+EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
2361+EXPORT_SYMBOL_GPL(power_supply_register);
2362+EXPORT_SYMBOL_GPL(power_supply_unregister);
2363+
2364+/* exported for the APM Power driver, APM emulation */
2365+EXPORT_SYMBOL_GPL(power_supply_class);
2366+
2367+subsys_initcall(power_supply_class_init);
2368+module_exit(power_supply_class_exit);
2369+
2370+MODULE_DESCRIPTION("Universal power supply monitor class");
2371+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
2372+ "Szabolcs Gyurko, "
2373+ "Anton Vorontsov <cbou@mail.ru>");
2374+MODULE_LICENSE("GPL");
2375Index: linux-2.6.22/drivers/power/power_supply.h
2376===================================================================
2377--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2378+++ linux-2.6.22/drivers/power/power_supply.h 2007-08-23 12:13:52.000000000 +0200
2379@@ -0,0 +1,42 @@
2380+/*
2381+ * Functions private to power supply class
2382+ *
2383+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2384+ * Copyright (c) 2004 Szabolcs Gyurko
2385+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2386+ *
2387+ * Modified: 2004, Oct Szabolcs Gyurko
2388+ *
2389+ * You may use this code as per GPL version 2
2390+ */
2391+
2392+#ifdef CONFIG_SYSFS
2393+
2394+extern int power_supply_create_attrs(struct power_supply *psy);
2395+extern void power_supply_remove_attrs(struct power_supply *psy);
2396+extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
2397+ char *buffer, int buffer_size);
2398+
2399+#else
2400+
2401+static inline int power_supply_create_attrs(struct power_supply *psy)
2402+{ return 0; }
2403+static inline void power_supply_remove_attrs(struct power_supply *psy) {}
2404+#define power_supply_uevent NULL
2405+
2406+#endif /* CONFIG_SYSFS */
2407+
2408+#ifdef CONFIG_LEDS_TRIGGERS
2409+
2410+extern void power_supply_update_leds(struct power_supply *psy);
2411+extern int power_supply_create_triggers(struct power_supply *psy);
2412+extern void power_supply_remove_triggers(struct power_supply *psy);
2413+
2414+#else
2415+
2416+static inline void power_supply_update_leds(struct power_supply *psy) {}
2417+static inline int power_supply_create_triggers(struct power_supply *psy)
2418+{ return 0; }
2419+static inline void power_supply_remove_triggers(struct power_supply *psy) {}
2420+
2421+#endif /* CONFIG_LEDS_TRIGGERS */
2422Index: linux-2.6.22/drivers/power/power_supply_leds.c
2423===================================================================
2424--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2425+++ linux-2.6.22/drivers/power/power_supply_leds.c 2007-08-23 12:13:52.000000000 +0200
2426@@ -0,0 +1,188 @@
2427+/*
2428+ * LEDs triggers for power supply class
2429+ *
2430+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2431+ * Copyright (c) 2004 Szabolcs Gyurko
2432+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2433+ *
2434+ * Modified: 2004, Oct Szabolcs Gyurko
2435+ *
2436+ * You may use this code as per GPL version 2
2437+ */
2438+
2439+#include <linux/power_supply.h>
2440+
2441+/* If we have hwtimer trigger, then use it to blink charging LED */
2442+
2443+#if defined(CONFIG_LEDS_TRIGGER_HWTIMER) || \
2444+ (defined(CONFIG_BATTERY_MODULE) && \
2445+ defined(CONFIG_LEDS_TRIGGER_HWTIMER_MODULE))
2446+ #define led_trigger_register_charging led_trigger_register_hwtimer
2447+ #define led_trigger_unregister_charging led_trigger_unregister_hwtimer
2448+#else
2449+ #define led_trigger_register_charging led_trigger_register_simple
2450+ #define led_trigger_unregister_charging led_trigger_unregister_simple
2451+#endif
2452+
2453+/* Battery specific LEDs triggers. */
2454+
2455+static void power_supply_update_bat_leds(struct power_supply *psy)
2456+{
2457+ union power_supply_propval status;
2458+
2459+ if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
2460+ return;
2461+
2462+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
2463+
2464+ switch(status.intval) {
2465+ case POWER_SUPPLY_STATUS_FULL:
2466+ led_trigger_event(psy->charging_full_trig, LED_FULL);
2467+ led_trigger_event(psy->charging_trig, LED_OFF);
2468+ led_trigger_event(psy->full_trig, LED_FULL);
2469+ break;
2470+ case POWER_SUPPLY_STATUS_CHARGING:
2471+ led_trigger_event(psy->charging_full_trig, LED_FULL);
2472+ led_trigger_event(psy->charging_trig, LED_FULL);
2473+ led_trigger_event(psy->full_trig, LED_OFF);
2474+ break;
2475+ default:
2476+ led_trigger_event(psy->charging_full_trig, LED_OFF);
2477+ led_trigger_event(psy->charging_trig, LED_OFF);
2478+ led_trigger_event(psy->full_trig, LED_OFF);
2479+ break;
2480+ }
2481+
2482+ return;
2483+}
2484+
2485+static int power_supply_create_bat_triggers(struct power_supply *psy)
2486+{
2487+ int rc = 0;
2488+
2489+ psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
2490+ sizeof("-charging-or-full"), GFP_KERNEL);
2491+ if (!psy->charging_full_trig_name)
2492+ goto charging_full_failed;
2493+
2494+ psy->charging_trig_name = kmalloc(strlen(psy->name) +
2495+ sizeof("-charging"), GFP_KERNEL);
2496+ if (!psy->charging_trig_name)
2497+ goto charging_failed;
2498+
2499+ psy->full_trig_name = kmalloc(strlen(psy->name) +
2500+ sizeof("-full"), GFP_KERNEL);
2501+ if (!psy->full_trig_name)
2502+ goto full_failed;
2503+
2504+ strcpy(psy->charging_full_trig_name, psy->name);
2505+ strcat(psy->charging_full_trig_name, "-charging-or-full");
2506+ strcpy(psy->charging_trig_name, psy->name);
2507+ strcat(psy->charging_trig_name, "-charging");
2508+ strcpy(psy->full_trig_name, psy->name);
2509+ strcat(psy->full_trig_name, "-full");
2510+
2511+ led_trigger_register_simple(psy->charging_full_trig_name,
2512+ &psy->charging_full_trig);
2513+ led_trigger_register_charging(psy->charging_trig_name,
2514+ &psy->charging_trig);
2515+ led_trigger_register_simple(psy->full_trig_name,
2516+ &psy->full_trig);
2517+
2518+ goto success;
2519+
2520+full_failed:
2521+ kfree(psy->charging_trig_name);
2522+charging_failed:
2523+ kfree(psy->charging_full_trig_name);
2524+charging_full_failed:
2525+ rc = -ENOMEM;
2526+success:
2527+ return rc;
2528+}
2529+
2530+static void power_supply_remove_bat_triggers(struct power_supply *psy)
2531+{
2532+ led_trigger_unregister_simple(psy->charging_full_trig);
2533+ led_trigger_unregister_charging(psy->charging_trig);
2534+ led_trigger_unregister_simple(psy->full_trig);
2535+ kfree(psy->full_trig_name);
2536+ kfree(psy->charging_trig_name);
2537+ kfree(psy->charging_full_trig_name);
2538+ return;
2539+}
2540+
2541+/* Generated power specific LEDs triggers. */
2542+
2543+static void power_supply_update_gen_leds(struct power_supply *psy)
2544+{
2545+ union power_supply_propval online;
2546+
2547+ if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
2548+ return;
2549+
2550+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
2551+
2552+ if (online.intval)
2553+ led_trigger_event(psy->online_trig, LED_FULL);
2554+ else
2555+ led_trigger_event(psy->online_trig, LED_OFF);
2556+
2557+ return;
2558+}
2559+
2560+static int power_supply_create_gen_triggers(struct power_supply *psy)
2561+{
2562+ int rc = 0;
2563+
2564+ psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
2565+ GFP_KERNEL);
2566+ if (!psy->online_trig_name)
2567+ goto online_failed;
2568+
2569+ strcpy(psy->online_trig_name, psy->name);
2570+ strcat(psy->online_trig_name, "-online");
2571+
2572+ led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
2573+
2574+ goto success;
2575+
2576+online_failed:
2577+ rc = -ENOMEM;
2578+success:
2579+ return rc;
2580+}
2581+
2582+static void power_supply_remove_gen_triggers(struct power_supply *psy)
2583+{
2584+ led_trigger_unregister_simple(psy->online_trig);
2585+ kfree(psy->online_trig_name);
2586+ return;
2587+}
2588+
2589+/* Choice what triggers to create&update. */
2590+
2591+void power_supply_update_leds(struct power_supply *psy)
2592+{
2593+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
2594+ power_supply_update_bat_leds(psy);
2595+ else
2596+ power_supply_update_gen_leds(psy);
2597+ return;
2598+}
2599+
2600+int power_supply_create_triggers(struct power_supply *psy)
2601+{
2602+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
2603+ return power_supply_create_bat_triggers(psy);
2604+ return power_supply_create_gen_triggers(psy);
2605+}
2606+
2607+void power_supply_remove_triggers(struct power_supply *psy)
2608+{
2609+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
2610+ power_supply_remove_bat_triggers(psy);
2611+ else
2612+ power_supply_remove_gen_triggers(psy);
2613+ return;
2614+}
2615Index: linux-2.6.22/drivers/power/power_supply_sysfs.c
2616===================================================================
2617--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2618+++ linux-2.6.22/drivers/power/power_supply_sysfs.c 2007-08-23 12:13:52.000000000 +0200
2619@@ -0,0 +1,289 @@
2620+/*
2621+ * Sysfs interface for the universal power supply monitor class
2622+ *
2623+ * Copyright © 2007 David Woodhouse <dwmw2@infradead.org>
2624+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
2625+ * Copyright (c) 2004 Szabolcs Gyurko
2626+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
2627+ *
2628+ * Modified: 2004, Oct Szabolcs Gyurko
2629+ *
2630+ * You may use this code as per GPL version 2
2631+ */
2632+
2633+#include <linux/ctype.h>
2634+#include <linux/power_supply.h>
2635+
2636+/*
2637+ * This is because the name "current" breaks the device attr macro.
2638+ * The "current" word resolvs to "(get_current())" so instead of
2639+ * "current" "(get_current())" appears in the sysfs.
2640+ *
2641+ * The source of this definition is the device.h which calls __ATTR
2642+ * macro in sysfs.h which calls the __stringify macro.
2643+ *
2644+ * Only modification that the name is not tried to be resolved
2645+ * (as a macro let's say).
2646+ */
2647+
2648+#define POWER_SUPPLY_ATTR(_name) \
2649+{ \
2650+ .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \
2651+ .show = power_supply_show_property, \
2652+ .store = NULL, \
2653+}
2654+
2655+static struct device_attribute power_supply_attrs[];
2656+
2657+static ssize_t power_supply_show_property(struct device *dev,
2658+ struct device_attribute *attr,
2659+ char *buf) {
2660+ static char *status_text[] = {
2661+ "Unknown", "Charging", "Discharging", "Not charging", "Full"
2662+ };
2663+ static char *health_text[] = {
2664+ "Unknown", "Good", "Overheat", "Dead"
2665+ };
2666+ static char *technology_text[] = {
2667+ "Unknown", "NiMH", "Li-ion", "Li-poly"
2668+ };
2669+ static char *capacity_level_text[] = {
2670+ "Unknown", "Critical", "Low", "Normal", "High", "Full"
2671+ };
2672+ ssize_t ret;
2673+ struct power_supply *psy = dev_get_drvdata(dev);
2674+ const ptrdiff_t off = attr - power_supply_attrs;
2675+ union power_supply_propval value;
2676+
2677+ ret = psy->get_property(psy, off, &value);
2678+
2679+ if (ret < 0) {
2680+ dev_err(dev, "driver failed to report `%s' property\n",
2681+ attr->attr.name);
2682+ return ret;
2683+ }
2684+
2685+ if (off == POWER_SUPPLY_PROP_STATUS)
2686+ return sprintf(buf, "%s\n", status_text[value.intval]);
2687+ else if (off == POWER_SUPPLY_PROP_HEALTH)
2688+ return sprintf(buf, "%s\n", health_text[value.intval]);
2689+ else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
2690+ return sprintf(buf, "%s\n", technology_text[value.intval]);
2691+ else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
2692+ return sprintf(buf, "%s\n",
2693+ capacity_level_text[value.intval]);
2694+ else if (off == POWER_SUPPLY_PROP_MODEL_NAME)
2695+ return sprintf(buf, "%s\n", value.strval);
2696+
2697+ return sprintf(buf, "%d\n", value.intval);
2698+}
2699+
2700+/* Must be in the same order as POWER_SUPPLY_PROP_* */
2701+static struct device_attribute power_supply_attrs[] = {
2702+ /* Properties of type `int' */
2703+ POWER_SUPPLY_ATTR(status),
2704+ POWER_SUPPLY_ATTR(health),
2705+ POWER_SUPPLY_ATTR(present),
2706+ POWER_SUPPLY_ATTR(online),
2707+ POWER_SUPPLY_ATTR(technology),
2708+ POWER_SUPPLY_ATTR(voltage_max_design),
2709+ POWER_SUPPLY_ATTR(voltage_min_design),
2710+ POWER_SUPPLY_ATTR(voltage_now),
2711+ POWER_SUPPLY_ATTR(voltage_avg),
2712+ POWER_SUPPLY_ATTR(current_now),
2713+ POWER_SUPPLY_ATTR(current_avg),
2714+ POWER_SUPPLY_ATTR(charge_full_design),
2715+ POWER_SUPPLY_ATTR(charge_empty_design),
2716+ POWER_SUPPLY_ATTR(charge_full),
2717+ POWER_SUPPLY_ATTR(charge_empty),
2718+ POWER_SUPPLY_ATTR(charge_now),
2719+ POWER_SUPPLY_ATTR(charge_avg),
2720+ POWER_SUPPLY_ATTR(energy_full_design),
2721+ POWER_SUPPLY_ATTR(energy_empty_design),
2722+ POWER_SUPPLY_ATTR(energy_full),
2723+ POWER_SUPPLY_ATTR(energy_empty),
2724+ POWER_SUPPLY_ATTR(energy_now),
2725+ POWER_SUPPLY_ATTR(energy_avg),
2726+ POWER_SUPPLY_ATTR(capacity),
2727+ POWER_SUPPLY_ATTR(capacity_level),
2728+ POWER_SUPPLY_ATTR(temp),
2729+ POWER_SUPPLY_ATTR(temp_ambient),
2730+ POWER_SUPPLY_ATTR(time_to_empty_now),
2731+ POWER_SUPPLY_ATTR(time_to_empty_avg),
2732+ POWER_SUPPLY_ATTR(time_to_full_now),
2733+ POWER_SUPPLY_ATTR(time_to_full_avg),
2734+ /* Properties of type `const char *' */
2735+ POWER_SUPPLY_ATTR(model_name),
2736+};
2737+
2738+static ssize_t power_supply_show_static_attrs(struct device *dev,
2739+ struct device_attribute *attr,
2740+ char *buf) {
2741+ static char *type_text[] = { "Battery", "UPS", "Mains", "USB" };
2742+ struct power_supply *psy = dev_get_drvdata(dev);
2743+
2744+ return sprintf(buf, "%s\n", type_text[psy->type]);
2745+}
2746+
2747+static struct device_attribute power_supply_static_attrs[] = {
2748+ __ATTR(type, 0444, power_supply_show_static_attrs, NULL),
2749+};
2750+
2751+int power_supply_create_attrs(struct power_supply *psy)
2752+{
2753+ int rc = 0;
2754+ int i, j;
2755+
2756+ for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
2757+ rc = device_create_file(psy->dev,
2758+ &power_supply_static_attrs[i]);
2759+ if (rc)
2760+ goto statics_failed;
2761+ }
2762+
2763+ for (j = 0; j < psy->num_properties; j++) {
2764+ rc = device_create_file(psy->dev,
2765+ &power_supply_attrs[psy->properties[j]]);
2766+ if (rc)
2767+ goto dynamics_failed;
2768+ }
2769+
2770+ goto succeed;
2771+
2772+dynamics_failed:
2773+ while (j--)
2774+ device_remove_file(psy->dev,
2775+ &power_supply_attrs[psy->properties[j]]);
2776+statics_failed:
2777+ while (i--)
2778+ device_remove_file(psy->dev,
2779+ &power_supply_static_attrs[psy->properties[i]]);
2780+succeed:
2781+ return rc;
2782+}
2783+
2784+void power_supply_remove_attrs(struct power_supply *psy)
2785+{
2786+ int i;
2787+
2788+ for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
2789+ device_remove_file(psy->dev,
2790+ &power_supply_static_attrs[i]);
2791+
2792+ for (i = 0; i < psy->num_properties; i++)
2793+ device_remove_file(psy->dev,
2794+ &power_supply_attrs[psy->properties[i]]);
2795+
2796+ return;
2797+}
2798+
2799+static char *kstruprdup(const char *str, gfp_t gfp)
2800+{
2801+ char *ret, *ustr;
2802+
2803+ ustr = ret = kmalloc(strlen(str) + 1, gfp);
2804+
2805+ if (!ret)
2806+ return NULL;
2807+
2808+ while (*str)
2809+ *ustr++ = toupper(*str++);
2810+
2811+ *ustr = 0;
2812+
2813+ return ret;
2814+}
2815+
2816+int power_supply_uevent(struct device *dev, char **envp, int num_envp,
2817+ char *buffer, int buffer_size)
2818+{
2819+ struct power_supply *psy = dev_get_drvdata(dev);
2820+ int i = 0, length = 0, ret = 0, j;
2821+ char *prop_buf;
2822+ char *attrname;
2823+
2824+ dev_dbg(dev, "uevent\n");
2825+
2826+ if (!psy) {
2827+ dev_dbg(dev, "No power supply yet\n");
2828+ return ret;
2829+ }
2830+
2831+ dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
2832+
2833+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
2834+ &length, "POWER_SUPPLY_NAME=%s", psy->name);
2835+ if (ret)
2836+ return ret;
2837+
2838+ prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
2839+ if (!prop_buf)
2840+ return -ENOMEM;
2841+
2842+ for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
2843+ struct device_attribute *attr;
2844+ char *line;
2845+
2846+ attr = &power_supply_static_attrs[j];
2847+
2848+ ret = power_supply_show_static_attrs(dev, attr, prop_buf);
2849+ if (ret < 0)
2850+ goto out;
2851+
2852+ line = strchr(prop_buf, '\n');
2853+ if (line)
2854+ *line = 0;
2855+
2856+ attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
2857+ if (!attrname) {
2858+ ret = -ENOMEM;
2859+ goto out;
2860+ }
2861+
2862+ dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
2863+
2864+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
2865+ &length, "POWER_SUPPLY_%s=%s",
2866+ attrname, prop_buf);
2867+ kfree(attrname);
2868+ if (ret)
2869+ goto out;
2870+ }
2871+
2872+ dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
2873+
2874+ for (j = 0; j < psy->num_properties; j++) {
2875+ struct device_attribute *attr;
2876+ char *line;
2877+
2878+ attr = &power_supply_attrs[psy->properties[j]];
2879+
2880+ ret = power_supply_show_property(dev, attr, prop_buf);
2881+ if (ret < 0)
2882+ goto out;
2883+
2884+ line = strchr(prop_buf, '\n');
2885+ if (line)
2886+ *line = 0;
2887+
2888+ attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
2889+ if (!attrname) {
2890+ ret = -ENOMEM;
2891+ goto out;
2892+ }
2893+
2894+ dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
2895+
2896+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
2897+ &length, "POWER_SUPPLY_%s=%s",
2898+ attrname, prop_buf);
2899+ kfree(attrname);
2900+ if (ret)
2901+ goto out;
2902+ }
2903+
2904+out:
2905+ free_page((unsigned long)prop_buf);
2906+
2907+ return ret;
2908+}
2909Index: linux-2.6.22/drivers/power/simpad-battery.c
2910===================================================================
2911--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2912+++ linux-2.6.22/drivers/power/simpad-battery.c 2007-08-23 12:13:52.000000000 +0200
2913@@ -0,0 +1,242 @@
2914+/*
2915+ * linux/drivers/misc/simpad-battery.c
2916+ *
2917+ * Copyright (C) 2005 Holger Hans Peter Freyther
2918+ * Copyright (C) 2001 Juergen Messerer
2919+ *
2920+ * This program is free software; you can redistribute it and/or modify
2921+ * it under the terms of the GNU General Public License as published by
2922+ * the Free Software Foundation; either version 2 of the License.
2923+ *
2924+ * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is
2925+ * unsupported for now.
2926+ *
2927+ */
2928+
2929+#include <linux/battery.h>
2930+#include <asm/dma.h>
2931+#include "ucb1x00.h"
2932+
2933+
2934+/*
2935+ * Conversion from AD -> mV
2936+ * 7.5V = 1023 7.3313mV/Digit
2937+ *
2938+ * 400 Units == 9.7V
2939+ * a = ADC value
2940+ * 21 = ADC error
2941+ * 12600 = Divident to get 2*7.3242
2942+ * 860 = Divider to get 2*7.3242
2943+ * 170 = Voltagedrop over
2944+ */
2945+#define CALIBRATE_BATTERY(a) ((((a + 21)*12600)/860) + 170)
2946+
2947+/*
2948+ * We have two types of batteries a small and a large one
2949+ * To get the right value we to distinguish between those two
2950+ * 450 Units == 15 V
2951+ */
2952+#define CALIBRATE_SUPPLY(a) (((a) * 1500) / 45)
2953+#define MIN_SUPPLY 12000 /* Less then 12V means no powersupply */
2954+
2955+/*
2956+ * Charging Current
2957+ * if value is >= 50 then charging is on
2958+ */
2959+#define CALIBRATE_CHARGING(a) (((a)* 1000)/(152/4)))
2960+
2961+struct simpad_battery_t {
2962+ struct battery battery;
2963+ struct ucb1x00* ucb;
2964+
2965+ /*
2966+ * Variables for the values to one time support
2967+ * T-Sinuspad as well
2968+ */
2969+ int min_voltage;
2970+ int min_current;
2971+ int min_charge;
2972+
2973+ int max_voltage;
2974+ int max_current;
2975+ int max_charge;
2976+
2977+ int min_supply;
2978+ int charging_led_label;
2979+ int charging_max_label;
2980+ int batt_full;
2981+ int batt_low;
2982+ int batt_critical;
2983+ int batt_empty;
2984+};
2985+
2986+static int simpad_get_min_voltage(struct battery* _battery )
2987+{
2988+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
2989+ return battery->min_voltage;
2990+}
2991+
2992+static int simpad_get_min_current(struct battery* _battery)
2993+{
2994+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
2995+ return battery->min_current;
2996+}
2997+
2998+static int simpad_get_min_charge(struct battery* _battery)
2999+{
3000+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3001+ return battery->min_charge;
3002+}
3003+
3004+static int simpad_get_max_voltage(struct battery* _battery)
3005+{
3006+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3007+ return battery->max_voltage;
3008+}
3009+
3010+static int simpad_get_max_current(struct battery* _battery)
3011+{
3012+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3013+ return battery->max_current;
3014+}
3015+
3016+static int simpad_get_max_charge(struct battery* _battery)
3017+{
3018+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3019+ return battery->max_charge;
3020+}
3021+
3022+static int simpad_get_temp(struct battery* _battery)
3023+{
3024+ return 0;
3025+}
3026+
3027+static int simpad_get_voltage(struct battery* _battery)
3028+{
3029+ int val;
3030+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3031+
3032+
3033+ ucb1x00_adc_enable(battery->ucb);
3034+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD1, UCB_NOSYNC);
3035+ ucb1x00_adc_disable(battery->ucb);
3036+
3037+ return CALIBRATE_BATTERY(val);
3038+}
3039+
3040+static int simpad_get_current(struct battery* _battery)
3041+{
3042+ int val;
3043+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3044+
3045+ ucb1x00_adc_enable(battery->ucb);
3046+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD3, UCB_NOSYNC);
3047+ ucb1x00_adc_disable(battery->ucb);
3048+
3049+ return val;
3050+}
3051+
3052+static int simpad_get_charge(struct battery* _battery)
3053+{
3054+ int val;
3055+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery;
3056+
3057+ ucb1x00_adc_enable(battery->ucb);
3058+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD2, UCB_NOSYNC);
3059+ ucb1x00_adc_disable(battery->ucb);
3060+
3061+ return CALIBRATE_SUPPLY(val);
3062+
3063+}
3064+
3065+static int simpad_get_status(struct battery* _battery)
3066+{
3067+ struct simpad_battery_t* battery = (struct simpad_battery_t*)(_battery);
3068+ int vcharger = simpad_get_voltage(_battery);
3069+ int icharger = simpad_get_current(_battery);
3070+
3071+ int status = BATTERY_STATUS_UNKNOWN;
3072+ if(icharger > battery->charging_led_label)
3073+ status = BATTERY_STATUS_CHARGING;
3074+ else if(vcharger > battery->min_supply)
3075+ status = BATTERY_STATUS_NOT_CHARGING;
3076+ else
3077+ status = BATTERY_STATUS_DISCHARGING;
3078+
3079+ return status;
3080+}
3081+
3082+static struct simpad_battery_t simpad_battery = {
3083+ .battery = {
3084+ .get_min_voltage = simpad_get_min_voltage,
3085+ .get_min_current = simpad_get_min_current,
3086+ .get_min_charge = simpad_get_min_charge,
3087+ .get_max_voltage = simpad_get_max_voltage,
3088+ .get_max_current = simpad_get_max_current,
3089+ .get_max_charge = simpad_get_max_charge,
3090+ .get_temp = simpad_get_temp,
3091+ .get_voltage = simpad_get_voltage,
3092+ .get_current = simpad_get_current,
3093+ .get_charge = simpad_get_charge,
3094+ .get_status = simpad_get_status,
3095+ },
3096+ .min_voltage = 0,
3097+ .min_current = 0,
3098+ .min_charge = 0,
3099+ .max_voltage = 0,
3100+ .max_current = 0,
3101+ .max_charge = 0,
3102+
3103+ .min_supply = 1200,
3104+ .charging_led_label = 18,
3105+ .charging_max_label = 265,
3106+ .batt_full = 8300,
3107+ .batt_low = 7300,
3108+ .batt_critical = 6800,
3109+ .batt_empty = 6500,
3110+};
3111+
3112+
3113+
3114+/*
3115+ * UCB glue code
3116+ */
3117+static int ucb1x00_battery_add(struct class_device *dev)
3118+{
3119+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
3120+ simpad_battery.ucb = ucb;
3121+
3122+ battery_class_register(&simpad_battery.battery);
3123+
3124+ return 0;
3125+}
3126+
3127+static void ucb1x00_battery_remove(struct class_device *dev)
3128+{
3129+ return battery_class_unregister(&simpad_battery.battery);
3130+}
3131+
3132+
3133+static struct ucb1x00_class_interface ucb1x00_battery_interface = {
3134+ .interface = {
3135+ .add = ucb1x00_battery_add,
3136+ .remove = ucb1x00_battery_remove,
3137+ },
3138+};
3139+
3140+
3141+static int __init battery_register(void)
3142+{
3143+ return ucb1x00_register_interface(&ucb1x00_battery_interface);
3144+}
3145+
3146+static void __exit battery_unregister(void)
3147+{
3148+ ucb1x00_unregister_interface(&ucb1x00_battery_interface);
3149+}
3150+
3151+module_init(battery_register);
3152+module_exit(battery_unregister);
3153+
3154+MODULE_AUTHOR("Holger Hans Peter Freyther");
3155+MODULE_LICENSE("GPL");
3156Index: linux-2.6.22/arch/arm/Kconfig
3157===================================================================
3158--- linux-2.6.22.orig/arch/arm/Kconfig 2007-08-23 12:17:42.000000000 +0200
3159+++ linux-2.6.22/arch/arm/Kconfig 2007-08-23 12:22:28.000000000 +0200
3160@@ -1016,6 +1016,8 @@
3161
3162 source "drivers/w1/Kconfig"
3163
3164+source "drivers/power/Kconfig"
3165+
3166 source "drivers/hwmon/Kconfig"
3167
3168 #source "drivers/l3/Kconfig"
3169Index: linux-2.6.22/drivers/Kconfig
3170===================================================================
3171--- linux-2.6.22.orig/drivers/Kconfig 2007-08-23 12:21:27.000000000 +0200
3172+++ linux-2.6.22/drivers/Kconfig 2007-08-23 12:22:03.000000000 +0200
3173@@ -54,6 +54,8 @@
3174
3175 source "drivers/w1/Kconfig"
3176
3177+source "drivers/power/Kconfig"
3178+
3179 source "drivers/hwmon/Kconfig"
3180
3181 source "drivers/mfd/Kconfig"
3182Index: linux-2.6.22/drivers/Makefile
3183===================================================================
3184--- linux-2.6.22.orig/drivers/Makefile 2007-08-23 12:33:58.000000000 +0200
3185+++ linux-2.6.22/drivers/Makefile 2007-08-23 12:34:34.000000000 +0200
3186@@ -61,6 +61,7 @@
3187 obj-$(CONFIG_RTC_LIB) += rtc/
3188 obj-y += i2c/
3189 obj-$(CONFIG_W1) += w1/
3190+obj-$(CONFIG_POWER_SUPPLY) += power/
3191 obj-$(CONFIG_HWMON) += hwmon/
3192 obj-$(CONFIG_PHONE) += telephony/
3193 obj-$(CONFIG_MD) += md/
3194Index: linux-2.6.22/include/linux/power_supply.h
3195===================================================================
3196--- /dev/null 1970-01-01 00:00:00.000000000 +0000
3197+++ linux-2.6.22/include/linux/power_supply.h 2007-08-23 12:37:10.000000000 +0200
3198@@ -0,0 +1,175 @@
3199+/*
3200+ * Universal power supply monitor class
3201+ *
3202+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru>
3203+ * Copyright (c) 2004 Szabolcs Gyurko
3204+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
3205+ *
3206+ * Modified: 2004, Oct Szabolcs Gyurko
3207+ *
3208+ * You may use this code as per GPL version 2
3209+ */
3210+
3211+#ifndef __LINUX_POWER_SUPPLY_H__
3212+#define __LINUX_POWER_SUPPLY_H__
3213+
3214+#include <linux/device.h>
3215+#include <linux/workqueue.h>
3216+#include <linux/leds.h>
3217+
3218+/*
3219+ * All voltages, currents, charges, energies, time and temperatures in uV,
3220+ * uA, uAh, uWh, seconds and tenths of degree Celsius unless otherwise
3221+ * stated. It's driver's job to convert its raw values to units in which
3222+ * this class operates.
3223+ */
3224+
3225+/*
3226+ * For systems where the charger determines the maximum battery capacity
3227+ * the min and max fields should be used to present these values to user
3228+ * space. Unused/unknown fields will not appear in sysfs.
3229+ */
3230+
3231+enum {
3232+ POWER_SUPPLY_STATUS_UNKNOWN = 0,
3233+ POWER_SUPPLY_STATUS_CHARGING,
3234+ POWER_SUPPLY_STATUS_DISCHARGING,
3235+ POWER_SUPPLY_STATUS_NOT_CHARGING,
3236+ POWER_SUPPLY_STATUS_FULL,
3237+};
3238+
3239+enum {
3240+ POWER_SUPPLY_HEALTH_UNKNOWN = 0,
3241+ POWER_SUPPLY_HEALTH_GOOD,
3242+ POWER_SUPPLY_HEALTH_OVERHEAT,
3243+ POWER_SUPPLY_HEALTH_DEAD,
3244+};
3245+
3246+enum {
3247+ POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,
3248+ POWER_SUPPLY_TECHNOLOGY_NIMH,
3249+ POWER_SUPPLY_TECHNOLOGY_LION,
3250+ POWER_SUPPLY_TECHNOLOGY_LIPO,
3251+};
3252+
3253+enum {
3254+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
3255+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
3256+ POWER_SUPPLY_CAPACITY_LEVEL_LOW,
3257+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
3258+ POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
3259+ POWER_SUPPLY_CAPACITY_LEVEL_FULL,
3260+};
3261+
3262+enum power_supply_property {
3263+ /* Properties of type `int' */
3264+ POWER_SUPPLY_PROP_STATUS = 0,
3265+ POWER_SUPPLY_PROP_HEALTH,
3266+ POWER_SUPPLY_PROP_PRESENT,
3267+ POWER_SUPPLY_PROP_ONLINE,
3268+ POWER_SUPPLY_PROP_TECHNOLOGY,
3269+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
3270+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
3271+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
3272+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
3273+ POWER_SUPPLY_PROP_CURRENT_NOW,
3274+ POWER_SUPPLY_PROP_CURRENT_AVG,
3275+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
3276+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
3277+ POWER_SUPPLY_PROP_CHARGE_FULL,
3278+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
3279+ POWER_SUPPLY_PROP_CHARGE_NOW,
3280+ POWER_SUPPLY_PROP_CHARGE_AVG,
3281+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
3282+ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
3283+ POWER_SUPPLY_PROP_ENERGY_FULL,
3284+ POWER_SUPPLY_PROP_ENERGY_EMPTY,
3285+ POWER_SUPPLY_PROP_ENERGY_NOW,
3286+ POWER_SUPPLY_PROP_ENERGY_AVG,
3287+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
3288+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
3289+ POWER_SUPPLY_PROP_TEMP,
3290+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
3291+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
3292+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
3293+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
3294+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
3295+ /* Properties of type `const char *' */
3296+ POWER_SUPPLY_PROP_MODEL_NAME,
3297+};
3298+
3299+enum power_supply_type {
3300+ POWER_SUPPLY_TYPE_BATTERY = 0,
3301+ POWER_SUPPLY_TYPE_UPS,
3302+ POWER_SUPPLY_TYPE_MAINS,
3303+ POWER_SUPPLY_TYPE_USB,
3304+};
3305+
3306+union power_supply_propval {
3307+ int intval;
3308+ const char *strval;
3309+};
3310+
3311+struct power_supply {
3312+ const char *name;
3313+ enum power_supply_type type;
3314+ enum power_supply_property *properties;
3315+ size_t num_properties;
3316+
3317+ char **supplied_to;
3318+ size_t num_supplicants;
3319+
3320+ int (*get_property)(struct power_supply *psy,
3321+ enum power_supply_property psp,
3322+ union power_supply_propval *val);
3323+ void (*external_power_changed)(struct power_supply *psy);
3324+
3325+ /* For APM emulation, think legacy userspace. */
3326+ int use_for_apm;
3327+
3328+ /* private */
3329+ struct device *dev;
3330+ struct work_struct changed_work;
3331+
3332+#ifdef CONFIG_LEDS_TRIGGERS
3333+ struct led_trigger *charging_full_trig;
3334+ char *charging_full_trig_name;
3335+ struct led_trigger *charging_trig;
3336+ char *charging_trig_name;
3337+ struct led_trigger *full_trig;
3338+ char *full_trig_name;
3339+ struct led_trigger *online_trig;
3340+ char *online_trig_name;
3341+#endif
3342+};
3343+
3344+/*
3345+ * This is recommended structure to specify static power supply parameters.
3346+ * Generic one, parametrizable for different power supplies. Power supply
3347+ * class itself does not use it, but that's what implementing most platform
3348+ * drivers, should try reuse for consistency.
3349+ */
3350+
3351+struct power_supply_info {
3352+ const char *name;
3353+ int technology;
3354+ int voltage_max_design;
3355+ int voltage_min_design;
3356+ int charge_full_design;
3357+ int charge_empty_design;
3358+ int energy_full_design;
3359+ int energy_empty_design;
3360+ int use_for_apm;
3361+};
3362+
3363+extern void power_supply_changed(struct power_supply *psy);
3364+extern int power_supply_am_i_supplied(struct power_supply *psy);
3365+
3366+extern int power_supply_register(struct device *parent,
3367+ struct power_supply *psy);
3368+extern void power_supply_unregister(struct power_supply *psy);
3369+
3370+/* For APM emulation, think legacy userspace. */
3371+extern struct class *power_supply_class;
3372+
3373+#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 @@
1---
2 arch/arm/mm/Kconfig | 2 +-
3 1 file changed, 1 insertion(+), 1 deletion(-)
4
5--- linux-2.6.23.orig/arch/arm/mm/Kconfig
6+++ linux-2.6.23/arch/arm/mm/Kconfig
7@@ -343,11 +343,11 @@ config CPU_XSC3
8 select IO_36
9
10 # ARMv6
11 config CPU_V6
12 bool "Support ARM V6 processor"
13- depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
14+ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_VERSATILE_PB
15 default y if ARCH_MX3
16 select CPU_32v6
17 select CPU_ABRT_EV6
18 select CPU_CACHE_V6
19 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 @@
1---
2 drivers/char/vt_ioctl.c | 8 +++++---
3 1 file changed, 5 insertions(+), 3 deletions(-)
4
5Index: linux-2.6.22/drivers/char/vt_ioctl.c
6===================================================================
7--- linux-2.6.22.orig/drivers/char/vt_ioctl.c 2007-07-09 01:32:17.000000000 +0200
8+++ linux-2.6.22/drivers/char/vt_ioctl.c 2007-09-27 11:58:42.000000000 +0200
9@@ -770,6 +770,7 @@
10 /*
11 * Switching-from response
12 */
13+ acquire_console_sem();
14 if (vc->vt_newvt >= 0) {
15 if (arg == 0)
16 /*
17@@ -784,7 +785,6 @@
18 * complete the switch.
19 */
20 int newvt;
21- acquire_console_sem();
22 newvt = vc->vt_newvt;
23 vc->vt_newvt = -1;
24 i = vc_allocate(newvt);
25@@ -798,7 +798,6 @@
26 * other console switches..
27 */
28 complete_change_console(vc_cons[newvt].d);
29- release_console_sem();
30 }
31 }
32
33@@ -810,9 +809,12 @@
34 /*
35 * If it's just an ACK, ignore it
36 */
37- if (arg != VT_ACKACQ)
38+ if (arg != VT_ACKACQ) {
39+ release_console_sem();
40 return -EINVAL;
41+ }
42 }
43+ release_console_sem();
44
45 return 0;
46
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 @@
1From: Marcin Juszkiewicz <openembedded@haerwu.biz>
2
3drivers/video/w100fb.c: In function ‘w100fb_imageblit’:
4drivers/video/w100fb.c:507: warning: unused variable ‘par’
5
6Signed-off-by: Marcin Juszkiewicz <openembedded@haerwu.biz>
7
8--- linux-2.6.23/drivers/video/w100fb.c 2007-10-11 16:52:30.000000000 +0200
9+++ linux-2.6.23/drivers/video/w100fb.c 2007-10-15 12:56:01.000000000 +0200
10@@ -504,7 +504,6 @@ static void w100_hostdata(u32 width, u32
11 static void w100fb_imageblit(struct fb_info *info,
12 const struct fb_image *image)
13 {
14- struct w100fb_par *par = info->par;
15 union dp_gui_master_cntl_u gmc;
16 u32 fgcolor, bgcolor;
17
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 @@
1 sound/soc/codecs/wm9712.c | 28 ++++++++++++++++++----------
2 1 file changed, 18 insertions(+), 10 deletions(-)
3
4Index: git/sound/soc/codecs/wm9712.c
5===================================================================
6--- git.orig/sound/soc/codecs/wm9712.c 2006-11-07 22:10:01.000000000 +0000
7+++ git/sound/soc/codecs/wm9712.c 2006-11-07 22:11:50.000000000 +0000
8@@ -618,18 +618,26 @@ static int wm9712_dapm_event(struct snd_
9
10 static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
11 {
12- if (try_warm && soc_ac97_ops.warm_reset) {
13- soc_ac97_ops.warm_reset(codec->ac97);
14- if (!(ac97_read(codec, 0) & 0x8000))
15- return 1;
16- }
17+ int retry = 3;
18
19- soc_ac97_ops.reset(codec->ac97);
20- if (ac97_read(codec, 0) & 0x8000)
21- goto err;
22- return 0;
23+ while (retry--)
24+ {
25+ if(try_warm && soc_ac97_ops.warm_reset) {
26+ soc_ac97_ops.warm_reset(codec->ac97);
27+ if(ac97_read(codec, 0) & 0x8000)
28+ continue;
29+ else
30+ return 1;
31+ }
32+
33+ soc_ac97_ops.reset(codec->ac97);
34+ if(ac97_read(codec, 0) & 0x8000)
35+ continue;
36+ else
37+ return 0;
38+
39+ }
40
41-err:
42 printk(KERN_ERR "WM9712 AC97 reset failed\n");
43 return -EIO;
44 }
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 @@
1 sound/soc/codecs/wm9712.c | 2 +-
2 1 file changed, 1 insertion(+), 1 deletion(-)
3
4Index: git/sound/soc/codecs/wm9712.c
5===================================================================
6--- git.orig/sound/soc/codecs/wm9712.c 2006-11-07 21:57:34.000000000 +0000
7+++ git/sound/soc/codecs/wm9712.c 2006-11-07 21:59:30.000000000 +0000
8@@ -651,7 +651,7 @@ static int wm9712_soc_resume(struct plat
9 int i, ret;
10 u16 *cache = codec->reg_cache;
11
12- ret = wm9712_reset(codec, 1);
13+ ret = wm9712_reset(codec, 0);
14 if (ret < 0){
15 printk(KERN_ERR "could not reset AC97 codec\n");
16 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 @@
1 drivers/input/power.c | 2 +-
2 drivers/input/touchscreen/Kconfig | 2 +-
3 drivers/input/touchscreen/wm97xx-core.c | 35 ++++++++++++++++---------------
4 include/linux/wm97xx.h | 2 +-
5 4 files changed, 21 insertions(+), 20 deletions(-)
6
7diff --git a/drivers/input/power.c b/drivers/input/power.c
8index 4443e34..7aac875 100644
9--- a/drivers/input/power.c
10+++ b/drivers/input/power.c
11@@ -156,7 +156,7 @@ static void power_event(struct input_handle *handle, unsigned int type,
12 }
13 }
14
15-static struct input_handle *power_connect(struct input_handler *handler,
16+static int power_connect(struct input_handler *handler,
17 struct input_dev *dev,
18 const struct input_device_id *id)
19 {
20diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
21index 6862e8f..9b532e9 100644
22--- a/drivers/input/touchscreen/Kconfig
23+++ b/drivers/input/touchscreen/Kconfig
24@@ -247,7 +247,7 @@ config TOUCHSCREEN_TSC2101
25
26 config TOUCHSCREEN_WM97XX
27 tristate "Support for WM97xx AC97 touchscreen controllers"
28- depends SND_AC97_BUS
29+ depends AC97_BUS
30
31 choice
32 prompt "WM97xx codec type"
33diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
34index 9b2710e..d3ce3f3 100644
35--- a/drivers/input/touchscreen/wm97xx-core.c
36+++ b/drivers/input/touchscreen/wm97xx-core.c
37@@ -84,6 +84,7 @@
38 #include <linux/bitops.h>
39 #include <linux/workqueue.h>
40 #include <linux/device.h>
41+#include <linux/freezer.h>
42 #include <linux/wm97xx.h>
43 #include <asm/uaccess.h>
44 #include <asm/io.h>
45@@ -241,14 +242,15 @@ WM97XX_STATUS_ATTR(gpio);
46
47 static int wm97xx_sys_add(struct device *dev)
48 {
49+ int err;
50 if (aux_sys) {
51- device_create_file(dev, &dev_attr_aux1);
52- device_create_file(dev, &dev_attr_aux2);
53- device_create_file(dev, &dev_attr_aux3);
54- device_create_file(dev, &dev_attr_aux4);
55+ err = device_create_file(dev, &dev_attr_aux1);
56+ err = device_create_file(dev, &dev_attr_aux2);
57+ err = device_create_file(dev, &dev_attr_aux3);
58+ err = device_create_file(dev, &dev_attr_aux4);
59 }
60 if (status_sys)
61- device_create_file(dev, &dev_attr_gpio);
62+ err = device_create_file(dev, &dev_attr_gpio);
63 return 0;
64 }
65
66@@ -366,12 +368,12 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, wm97xx_gpio_dir_t dir,
67
68 /*
69 * Handle a pen down interrupt.
70- */
71-static void wm97xx_pen_irq_worker(void *ptr)
72-{
73- struct wm97xx *wm = (struct wm97xx *) ptr;
74-
75- /* do we need to enable the touch panel reader */
76+ */
77+static void wm97xx_pen_irq_worker(struct work_struct *work)
78+{
79+ struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work);
80+
81+ /* do we need to enable the touch panel reader */
82 if (wm->id == WM9705_ID2) {
83 if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN)
84 wm->pen_is_down = 1;
85@@ -411,9 +413,8 @@ static void wm97xx_pen_irq_worker(void *ptr)
86 * We have to disable the codec interrupt in the handler because it can
87 * take upto 1ms to clear the interrupt source. The interrupt is then enabled
88 * again in the slow handler when the source has been cleared.
89- */
90-static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id,
91- struct pt_regs *regs)
92+ */
93+static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
94 {
95 struct wm97xx *wm = (struct wm97xx *) dev_id;
96 disable_irq(wm->pen_irq);
97@@ -428,15 +429,15 @@ static int wm97xx_init_pen_irq(struct wm97xx *wm)
98 {
99 u16 reg;
100
101- INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker, wm);
102- if ((wm->pen_irq_workq =
103+ INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker);
104+ if ((wm->pen_irq_workq =
105 create_singlethread_workqueue("kwm97pen")) == NULL) {
106 err("could not create pen irq work queue");
107 wm->pen_irq = 0;
108 return -EINVAL;
109 }
110
111- if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, SA_SHIRQ, "wm97xx-pen", wm)) {
112+ if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED, "wm97xx-pen", wm)) {
113 err("could not register codec pen down interrupt, will poll for pen down");
114 destroy_workqueue(wm->pen_irq_workq);
115 wm->pen_irq = 0;
116diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h
117index b1c1740..a9bd57e 100644
118--- a/include/linux/wm97xx.h
119+++ b/include/linux/wm97xx.h
120@@ -243,7 +243,7 @@ struct wm97xx {
121 u16 dig_save[3]; /* saved during aux reading */
122 struct wm97xx_codec_drv *codec; /* attached codec driver*/
123 struct input_dev* input_dev; /* touchscreen input device */
124- ac97_t *ac97; /* ALSA codec access */
125+ struct snd_ac97 *ac97; /* ALSA codec access */
126 struct device *dev; /* ALSA device */
127 struct device *battery_dev;
128 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 @@
1Index: linux-2.6.17/drivers/input/touchscreen/Kconfig
2===================================================================
3--- linux-2.6.17.orig/drivers/input/touchscreen/Kconfig 2006-09-19 20:35:35.060495500 +0200
4+++ linux-2.6.17/drivers/input/touchscreen/Kconfig 2006-09-19 20:36:47.965051750 +0200
5@@ -121,4 +121,57 @@ config TOUCHSCREEN_TSC2101
6 To compile this driver as a module, choose M here: the
7 module will be called ads7846_ts.
8
9+config TOUCHSCREEN_WM97XX
10+ tristate "Support for WM97xx AC97 touchscreen controllers"
11+ depends SND_AC97_BUS
12+
13+choice
14+ prompt "WM97xx codec type"
15+
16+config TOUCHSCREEN_WM9705
17+ bool "WM9705 Touchscreen interface support"
18+ depends on TOUCHSCREEN_WM97XX
19+ help
20+ Say Y here if you have the wm9705 touchscreen.
21+
22+ If unsure, say N.
23+
24+ To compile this driver as a module, choose M here: the
25+ module will be called wm9705.
26+
27+config TOUCHSCREEN_WM9712
28+ bool "WM9712 Touchscreen interface support"
29+ depends on TOUCHSCREEN_WM97XX
30+ help
31+ Say Y here if you have the wm9712 touchscreen.
32+
33+ If unsure, say N.
34+
35+ To compile this driver as a module, choose M here: the
36+ module will be called wm9712.
37+
38+config TOUCHSCREEN_WM9713
39+ bool "WM9713 Touchscreen interface support"
40+ depends on TOUCHSCREEN_WM97XX
41+ help
42+ Say Y here if you have the wm9713 touchscreen.
43+
44+ If unsure, say N.
45+
46+ To compile this driver as a module, choose M here: the
47+ module will be called wm9713.
48+
49+endchoice
50+
51+config TOUCHSCREEN_WM97XX_PXA
52+ tristate "WM97xx PXA accelerated touch"
53+ depends on TOUCHSCREEN_WM97XX && ARCH_PXA
54+ help
55+ Say Y here for continuous mode touch on the PXA
56+
57+ If unsure, say N
58+
59+ To compile this driver as a module, choose M here: the
60+ module will be called pxa-wm97xx
61+
62 endif
63Index: linux-2.6.17/drivers/input/touchscreen/Makefile
64===================================================================
65--- linux-2.6.17.orig/drivers/input/touchscreen/Makefile 2006-09-19 20:35:35.072496250 +0200
66+++ linux-2.6.17/drivers/input/touchscreen/Makefile 2006-09-19 20:37:40.540337500 +0200
67@@ -4,6 +4,8 @@
68
69 # Each configuration option enables a list of files.
70
71+wm97xx-ts-objs := wm97xx-core.o
72+
73 obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
74 obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
75 obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
76@@ -13,3 +15,16 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtou
77 obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
78 obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
79 obj-$(CONFIG_TOUCHSCREEN_TSC2101) += tsc2101_ts.o
80+obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
81+obj-$(CONFIG_TOUCHSCREEN_WM97XX_PXA) += pxa-wm97xx.o
82+
83+ifeq ($(CONFIG_TOUCHSCREEN_WM9713),y)
84+wm97xx-ts-objs += wm9713.o
85+endif
86+
87+ifeq ($(CONFIG_TOUCHSCREEN_WM9712),y)
88+wm97xx-ts-objs += wm9712.o
89+endif
90+ifeq ($(CONFIG_TOUCHSCREEN_WM9705),y)
91+wm97xx-ts-objs += wm9705.o
92+endif
93Index: linux-2.6.17/drivers/input/touchscreen/pxa-wm97xx.c
94===================================================================
95--- /dev/null 1970-01-01 00:00:00.000000000 +0000
96+++ linux-2.6.17/drivers/input/touchscreen/pxa-wm97xx.c 2006-09-19 20:36:47.965051750 +0200
97@@ -0,0 +1,289 @@
98+/*
99+ * pxa-wm97xx.c -- pxa-wm97xx Continuous Touch screen driver for
100+ * Wolfson WM97xx AC97 Codecs.
101+ *
102+ * Copyright 2004 Wolfson Microelectronics PLC.
103+ * Author: Liam Girdwood
104+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
105+ * Parts Copyright : Ian Molton <spyro@f2s.com>
106+ * Andrew Zabolotny <zap@homelink.ru>
107+ *
108+ * This program is free software; you can redistribute it and/or modify it
109+ * under the terms of the GNU General Public License as published by the
110+ * Free Software Foundation; either version 2 of the License, or (at your
111+ * option) any later version.
112+ *
113+ * Notes:
114+ * This is a wm97xx extended touch driver to capture touch
115+ * data in a continuous manner on the Intel XScale archictecture
116+ *
117+ * Features:
118+ * - codecs supported:- WM9705, WM9712, WM9713
119+ * - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
120+ *
121+ * Revision history
122+ * 18th Aug 2004 Initial version.
123+ * 26th Jul 2005 Improved continous read back and added FIFO flushing.
124+ * 06th Sep 2005 Mike Arthur <linux@wolfsonmicro.com>
125+ * Moved to using the wm97xx bus
126+ *
127+ */
128+
129+#include <linux/module.h>
130+#include <linux/moduleparam.h>
131+#include <linux/version.h>
132+#include <linux/kernel.h>
133+#include <linux/init.h>
134+#include <linux/delay.h>
135+#include <linux/irq.h>
136+#include <linux/wm97xx.h>
137+#include <asm/io.h>
138+#include <asm/arch/pxa-regs.h>
139+
140+#define VERSION "0.13"
141+
142+struct continuous {
143+ u16 id; /* codec id */
144+ u8 code; /* continuous code */
145+ u8 reads; /* number of coord reads per read cycle */
146+ u32 speed; /* number of coords per second */
147+};
148+
149+#define WM_READS(sp) ((sp / HZ) + 1)
150+
151+static const struct continuous cinfo[] = {
152+ {WM9705_ID2, 0, WM_READS(94), 94},
153+ {WM9705_ID2, 1, WM_READS(188), 188},
154+ {WM9705_ID2, 2, WM_READS(375), 375},
155+ {WM9705_ID2, 3, WM_READS(750), 750},
156+ {WM9712_ID2, 0, WM_READS(94), 94},
157+ {WM9712_ID2, 1, WM_READS(188), 188},
158+ {WM9712_ID2, 2, WM_READS(375), 375},
159+ {WM9712_ID2, 3, WM_READS(750), 750},
160+ {WM9713_ID2, 0, WM_READS(94), 94},
161+ {WM9713_ID2, 1, WM_READS(120), 120},
162+ {WM9713_ID2, 2, WM_READS(154), 154},
163+ {WM9713_ID2, 3, WM_READS(188), 188},
164+};
165+
166+/* continuous speed index */
167+static int sp_idx = 0;
168+static u16 last = 0, tries = 0;
169+
170+/*
171+ * Pen sampling frequency (Hz) in continuous mode.
172+ */
173+static int cont_rate = 200;
174+module_param(cont_rate, int, 0);
175+MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
176+
177+/*
178+ * Pen down detection.
179+ *
180+ * This driver can either poll or use an interrupt to indicate a pen down
181+ * event. If the irq request fails then it will fall back to polling mode.
182+ */
183+static int pen_int = 1;
184+module_param(pen_int, int, 0);
185+MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
186+
187+/*
188+ * Pressure readback.
189+ *
190+ * Set to 1 to read back pen down pressure
191+ */
192+static int pressure = 0;
193+module_param(pressure, int, 0);
194+MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
195+
196+/*
197+ * AC97 touch data slot.
198+ *
199+ * Touch screen readback data ac97 slot
200+ */
201+static int ac97_touch_slot = 5;
202+module_param(ac97_touch_slot, int, 0);
203+MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
204+
205+
206+/* flush AC97 slot 5 FIFO on pxa machines */
207+#ifdef CONFIG_PXA27x
208+void wm97xx_acc_pen_up (struct wm97xx* wm)
209+{
210+ set_current_state(TASK_INTERRUPTIBLE);
211+ schedule_timeout(1);
212+
213+ while (MISR & (1 << 2))
214+ MODR;
215+}
216+#else
217+void wm97xx_acc_pen_up (struct wm97xx* wm)
218+{
219+ int count = 16;
220+ set_current_state(TASK_INTERRUPTIBLE);
221+ schedule_timeout(1);
222+
223+ while (count < 16) {
224+ MODR;
225+ count--;
226+ }
227+}
228+#endif
229+
230+int wm97xx_acc_pen_down (struct wm97xx* wm)
231+{
232+ u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
233+ int reads = 0;
234+
235+ /* data is never immediately available after pen down irq */
236+ set_current_state(TASK_INTERRUPTIBLE);
237+ schedule_timeout(1);
238+
239+ if (tries > 5){
240+ tries = 0;
241+ return RC_PENUP;
242+ }
243+
244+ x = MODR;
245+ if (x == last) {
246+ tries++;
247+ return RC_AGAIN;
248+ }
249+ last = x;
250+ do {
251+ if (reads)
252+ x= MODR;
253+ y= MODR;
254+ if (pressure)
255+ p = MODR;
256+
257+ /* are samples valid */
258+ if ((x & 0x7000) != WM97XX_ADCSEL_X ||
259+ (y & 0x7000) != WM97XX_ADCSEL_Y ||
260+ (p & 0x7000) != WM97XX_ADCSEL_PRES)
261+ goto up;
262+
263+ /* coordinate is good */
264+ tries = 0;
265+ //printk("x %x y %x p %x\n", x,y,p);
266+ input_report_abs (wm->input_dev, ABS_X, x & 0xfff);
267+ input_report_abs (wm->input_dev, ABS_Y, y & 0xfff);
268+ input_report_abs (wm->input_dev, ABS_PRESSURE, p & 0xfff);
269+ input_sync (wm->input_dev);
270+ reads++;
271+ } while (reads < cinfo[sp_idx].reads);
272+up:
273+ return RC_PENDOWN | RC_AGAIN;
274+}
275+
276+int wm97xx_acc_startup(struct wm97xx* wm)
277+{
278+ int idx = 0;
279+
280+ /* check we have a codec */
281+ if (wm->ac97 == NULL)
282+ return -ENODEV;
283+
284+ /* Go you big red fire engine */
285+ for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
286+ if (wm->id != cinfo[idx].id)
287+ continue;
288+ sp_idx = idx;
289+ if (cont_rate <= cinfo[idx].speed)
290+ break;
291+ }
292+ wm->acc_rate = cinfo[sp_idx].code;
293+ wm->acc_slot = ac97_touch_slot;
294+ printk(KERN_INFO "pxa2xx accelerated touchscreen driver, %d samples (sec)\n",
295+ cinfo[sp_idx].speed);
296+
297+ /* codec specific irq config */
298+ if (pen_int) {
299+ switch (wm->id) {
300+ case WM9705_ID2:
301+ wm->pen_irq = IRQ_GPIO(4);
302+ set_irq_type(IRQ_GPIO(4), IRQT_BOTHEDGE);
303+ break;
304+ case WM9712_ID2:
305+ case WM9713_ID2:
306+ /* enable pen down interrupt */
307+ /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
308+ wm->pen_irq = MAINSTONE_AC97_IRQ;
309+ wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
310+ WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, WM97XX_GPIO_WAKE);
311+ wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
312+ WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_NOTSTICKY, WM97XX_GPIO_NOWAKE);
313+ break;
314+ default:
315+ printk(KERN_WARNING "pen down irq not supported on this device\n");
316+ pen_int = 0;
317+ break;
318+ }
319+ }
320+
321+ return 0;
322+}
323+
324+void wm97xx_acc_shutdown(struct wm97xx* wm)
325+{
326+ /* codec specific deconfig */
327+ if (pen_int) {
328+ switch (wm->id & 0xffff) {
329+ case WM9705_ID2:
330+ wm->pen_irq = 0;
331+ break;
332+ case WM9712_ID2:
333+ case WM9713_ID2:
334+ /* disable interrupt */
335+ wm->pen_irq = 0;
336+ break;
337+ }
338+ }
339+}
340+
341+static struct wm97xx_mach_ops pxa_mach_ops = {
342+ .acc_enabled = 1,
343+ .acc_pen_up = wm97xx_acc_pen_up,
344+ .acc_pen_down = wm97xx_acc_pen_down,
345+ .acc_startup = wm97xx_acc_startup,
346+ .acc_shutdown = wm97xx_acc_shutdown,
347+};
348+
349+int pxa_wm97xx_probe(struct device *dev)
350+{
351+ struct wm97xx *wm = dev->driver_data;
352+ return wm97xx_register_mach_ops (wm, &pxa_mach_ops);
353+}
354+
355+int pxa_wm97xx_remove(struct device *dev)
356+{
357+ struct wm97xx *wm = dev->driver_data;
358+ wm97xx_unregister_mach_ops (wm);
359+ return 0;
360+}
361+
362+static struct device_driver pxa_wm97xx_driver = {
363+ .name = "wm97xx-touchscreen",
364+ .bus = &wm97xx_bus_type,
365+ .owner = THIS_MODULE,
366+ .probe = pxa_wm97xx_probe,
367+ .remove = pxa_wm97xx_remove
368+};
369+
370+static int __init pxa_wm97xx_init(void)
371+{
372+ return driver_register(&pxa_wm97xx_driver);
373+}
374+
375+static void __exit pxa_wm97xx_exit(void)
376+{
377+ driver_unregister(&pxa_wm97xx_driver);
378+}
379+
380+module_init(pxa_wm97xx_init);
381+module_exit(pxa_wm97xx_exit);
382+
383+/* Module information */
384+MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
385+MODULE_DESCRIPTION("wm97xx continuous touch driver for pxa2xx");
386+MODULE_LICENSE("GPL");
387Index: linux-2.6.17/drivers/input/touchscreen/wm9705.c
388===================================================================
389--- /dev/null 1970-01-01 00:00:00.000000000 +0000
390+++ linux-2.6.17/drivers/input/touchscreen/wm9705.c 2006-09-19 20:36:47.969052000 +0200
391@@ -0,0 +1,360 @@
392+/*
393+ * wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
394+ *
395+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
396+ * Author: Liam Girdwood
397+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
398+ * Parts Copyright : Ian Molton <spyro@f2s.com>
399+ * Andrew Zabolotny <zap@homelink.ru>
400+ * Russell King <rmk@arm.linux.org.uk>
401+ *
402+ * This program is free software; you can redistribute it and/or modify it
403+ * under the terms of the GNU General Public License as published by the
404+ * Free Software Foundation; either version 2 of the License, or (at your
405+ * option) any later version.
406+ *
407+ * Revision history
408+ * 6th Sep 2006 Mike Arthur <linux@wolfsonmicro.com>
409+ * Added pre and post sample calls.
410+ *
411+ */
412+
413+#include <linux/module.h>
414+#include <linux/moduleparam.h>
415+#include <linux/version.h>
416+#include <linux/kernel.h>
417+#include <linux/input.h>
418+#include <linux/delay.h>
419+#include <linux/bitops.h>
420+#include <linux/wm97xx.h>
421+
422+#define TS_NAME "wm97xx"
423+#define WM9705_VERSION "0.62"
424+#define DEFAULT_PRESSURE 0xb0c0
425+
426+/*
427+ * Debug
428+ */
429+#if 0
430+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
431+#else
432+#define dbg(format, arg...)
433+#endif
434+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
435+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
436+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
437+
438+/*
439+ * Module parameters
440+ */
441+
442+/*
443+ * Set current used for pressure measurement.
444+ *
445+ * Set pil = 2 to use 400uA
446+ * pil = 1 to use 200uA and
447+ * pil = 0 to disable pressure measurement.
448+ *
449+ * This is used to increase the range of values returned by the adc
450+ * when measureing touchpanel pressure.
451+ */
452+static int pil = 0;
453+module_param(pil, int, 0);
454+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
455+
456+/*
457+ * Set threshold for pressure measurement.
458+ *
459+ * Pen down pressure below threshold is ignored.
460+ */
461+static int pressure = DEFAULT_PRESSURE & 0xfff;
462+module_param(pressure, int, 0);
463+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
464+
465+/*
466+ * Set adc sample delay.
467+ *
468+ * For accurate touchpanel measurements, some settling time may be
469+ * required between the switch matrix applying a voltage across the
470+ * touchpanel plate and the ADC sampling the signal.
471+ *
472+ * This delay can be set by setting delay = n, where n is the array
473+ * position of the delay in the array delay_table below.
474+ * Long delays > 1ms are supported for completeness, but are not
475+ * recommended.
476+ */
477+static int delay = 4;
478+module_param(delay, int, 0);
479+MODULE_PARM_DESC(delay, "Set adc sample delay.");
480+
481+/*
482+ * Pen detect comparator threshold.
483+ *
484+ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
485+ * i.e. 1 = Vmid/15 threshold
486+ * 15 = Vmid/1 threshold
487+ *
488+ * Adjust this value if you are having problems with pen detect not
489+ * detecting any down events.
490+ */
491+static int pdd = 8;
492+module_param(pdd, int, 0);
493+MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
494+
495+/*
496+ * Set adc mask function.
497+ *
498+ * Sources of glitch noise, such as signals driving an LCD display, may feed
499+ * through to the touch screen plates and affect measurement accuracy. In
500+ * order to minimise this, a signal may be applied to the MASK pin to delay or
501+ * synchronise the sampling.
502+ *
503+ * 0 = No delay or sync
504+ * 1 = High on pin stops conversions
505+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
506+ * 3 = Edge triggered, edge on pin starts conversion after delay param
507+ */
508+static int mask = 0;
509+module_param(mask, int, 0);
510+MODULE_PARM_DESC(mask, "Set adc mask function.");
511+
512+/*
513+ * ADC sample delay times in uS
514+ */
515+static const int delay_table[] = {
516+ 21, // 1 AC97 Link frames
517+ 42, // 2
518+ 84, // 4
519+ 167, // 8
520+ 333, // 16
521+ 667, // 32
522+ 1000, // 48
523+ 1333, // 64
524+ 2000, // 96
525+ 2667, // 128
526+ 3333, // 160
527+ 4000, // 192
528+ 4667, // 224
529+ 5333, // 256
530+ 6000, // 288
531+ 0 // No delay, switch matrix always on
532+};
533+
534+/*
535+ * Delay after issuing a POLL command.
536+ *
537+ * The delay is 3 AC97 link frames + the touchpanel settling delay
538+ */
539+static inline void poll_delay(int d)
540+{
541+ udelay (3 * AC97_LINK_FRAME + delay_table [d]);
542+}
543+
544+/*
545+ * set up the physical settings of the WM9705
546+ */
547+static void init_wm9705_phy(struct wm97xx* wm)
548+{
549+ u16 dig1 = 0, dig2 = WM97XX_RPR;
550+
551+ /*
552+ * mute VIDEO and AUX as they share X and Y touchscreen
553+ * inputs on the WM9705
554+ */
555+ wm97xx_reg_write(wm, AC97_AUX, 0x8000);
556+ wm97xx_reg_write(wm, AC97_VIDEO, 0x8000);
557+
558+ /* touchpanel pressure current*/
559+ if (pil == 2) {
560+ dig2 |= WM9705_PIL;
561+ dbg("setting pressure measurement current to 400uA.");
562+ } else if (pil)
563+ dbg("setting pressure measurement current to 200uA.");
564+ if(!pil)
565+ pressure = 0;
566+
567+ /* polling mode sample settling delay */
568+ if (delay!=4) {
569+ if (delay < 0 || delay > 15) {
570+ dbg("supplied delay out of range.");
571+ delay = 4;
572+ }
573+ }
574+ dig1 &= 0xff0f;
575+ dig1 |= WM97XX_DELAY(delay);
576+ dbg("setting adc sample delay to %d u Secs.", delay_table[delay]);
577+
578+ /* WM9705 pdd */
579+ dig2 |= (pdd & 0x000f);
580+ dbg("setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
581+
582+ /* mask */
583+ dig2 |= ((mask & 0x3) << 4);
584+
585+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
586+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
587+}
588+
589+static int wm9705_digitiser_ioctl(struct wm97xx* wm, int cmd)
590+{
591+ switch(cmd) {
592+ case WM97XX_DIG_START:
593+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig[2] | WM97XX_PRP_DET_DIG);
594+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
595+ break;
596+ case WM97XX_DIG_STOP:
597+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig[2] & ~WM97XX_PRP_DET_DIG);
598+ break;
599+ case WM97XX_AUX_PREPARE:
600+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
601+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
602+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
603+ break;
604+ case WM97XX_DIG_RESTORE:
605+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
606+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
607+ break;
608+ case WM97XX_PHY_INIT:
609+ init_wm9705_phy(wm);
610+ break;
611+ default:
612+ return -EINVAL;
613+ }
614+ return 0;
615+}
616+
617+static inline int is_pden (struct wm97xx* wm)
618+{
619+ return wm->dig[2] & WM9705_PDEN;
620+}
621+
622+/*
623+ * Read a sample from the WM9705 adc in polling mode.
624+ */
625+static int wm9705_poll_sample (struct wm97xx* wm, int adcsel, int *sample)
626+{
627+ int timeout = 5 * delay;
628+
629+ if (!wm->pen_probably_down) {
630+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
631+ if (!(data & WM97XX_PEN_DOWN))
632+ return RC_PENUP;
633+ wm->pen_probably_down = 1;
634+ }
635+
636+ /* set up digitiser */
637+ if (adcsel & 0x8000)
638+ adcsel = ((adcsel & 0x7fff) + 3) << 12;
639+
640+ if (wm->mach_ops && wm->mach_ops->pre_sample)
641+ wm->mach_ops->pre_sample(adcsel);
642+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
643+
644+ /* wait 3 AC97 time slots + delay for conversion */
645+ poll_delay (delay);
646+
647+ /* wait for POLL to go low */
648+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) {
649+ udelay(AC97_LINK_FRAME);
650+ timeout--;
651+ }
652+
653+ if (timeout <= 0) {
654+ /* If PDEN is set, we can get a timeout when pen goes up */
655+ if (is_pden(wm))
656+ wm->pen_probably_down = 0;
657+ else
658+ dbg ("adc sample timeout");
659+ return RC_PENUP;
660+ }
661+
662+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
663+ if (wm->mach_ops && wm->mach_ops->post_sample)
664+ wm->mach_ops->post_sample(adcsel);
665+
666+ /* check we have correct sample */
667+ if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
668+ dbg ("adc wrong sample, read %x got %x", adcsel,
669+ *sample & WM97XX_ADCSEL_MASK);
670+ return RC_PENUP;
671+ }
672+
673+ if (!(*sample & WM97XX_PEN_DOWN)) {
674+ wm->pen_probably_down = 0;
675+ return RC_PENUP;
676+ }
677+
678+ return RC_VALID;
679+}
680+
681+/*
682+ * Sample the WM9705 touchscreen in polling mode
683+ */
684+static int wm9705_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
685+{
686+ int rc;
687+
688+ if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID)
689+ return rc;
690+ if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID)
691+ return rc;
692+ if (pil) {
693+ if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID)
694+ return rc;
695+ } else
696+ data->p = DEFAULT_PRESSURE;
697+
698+ return RC_VALID;
699+}
700+
701+/*
702+ * Enable WM9705 continuous mode, i.e. touch data is streamed across an AC97 slot
703+ */
704+static int wm9705_acc_enable (struct wm97xx* wm, int enable)
705+{
706+ u16 dig1, dig2;
707+ int ret = 0;
708+
709+ dig1 = wm->dig[1];
710+ dig2 = wm->dig[2];
711+
712+ if (enable) {
713+ /* continous mode */
714+ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0)
715+ return ret;
716+ dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
717+ WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
718+ dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
719+ WM97XX_DELAY (delay) |
720+ WM97XX_SLT (wm->acc_slot) |
721+ WM97XX_RATE (wm->acc_rate);
722+ if (pil)
723+ dig1 |= WM97XX_ADCSEL_PRES;
724+ dig2 |= WM9705_PDEN;
725+ } else {
726+ dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
727+ dig2 &= ~WM9705_PDEN;
728+ if (wm->mach_ops->acc_shutdown)
729+ wm->mach_ops->acc_shutdown(wm);
730+ }
731+
732+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
733+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
734+ return ret;
735+}
736+
737+struct wm97xx_codec_drv wm97xx_codec = {
738+ .id = WM9705_ID2,
739+ .name = "wm9705",
740+ .poll_sample = wm9705_poll_sample,
741+ .poll_touch = wm9705_poll_touch,
742+ .acc_enable = wm9705_acc_enable,
743+ .digitiser_ioctl = wm9705_digitiser_ioctl,
744+};
745+
746+EXPORT_SYMBOL_GPL(wm97xx_codec);
747+
748+/* Module information */
749+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
750+MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
751+MODULE_LICENSE("GPL");
752Index: linux-2.6.17/drivers/input/touchscreen/wm9712.c
753===================================================================
754--- /dev/null 1970-01-01 00:00:00.000000000 +0000
755+++ linux-2.6.17/drivers/input/touchscreen/wm9712.c 2006-09-19 20:36:47.969052000 +0200
756@@ -0,0 +1,464 @@
757+/*
758+ * wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
759+ *
760+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
761+ * Author: Liam Girdwood
762+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
763+ * Parts Copyright : Ian Molton <spyro@f2s.com>
764+ * Andrew Zabolotny <zap@homelink.ru>
765+ * Russell King <rmk@arm.linux.org.uk>
766+ *
767+ * This program is free software; you can redistribute it and/or modify it
768+ * under the terms of the GNU General Public License as published by the
769+ * Free Software Foundation; either version 2 of the License, or (at your
770+ * option) any later version.
771+ *
772+ * Revision history
773+ * 4th Jul 2005 Initial version.
774+ * 6th Sep 2006 Mike Arthur <linux@wolfsonmicro.com>
775+ * Added pre and post sample calls.
776+ *
777+ */
778+
779+#include <linux/module.h>
780+#include <linux/moduleparam.h>
781+#include <linux/version.h>
782+#include <linux/kernel.h>
783+#include <linux/input.h>
784+#include <linux/delay.h>
785+#include <linux/bitops.h>
786+#include <linux/wm97xx.h>
787+
788+#define TS_NAME "wm97xx"
789+#define WM9712_VERSION "0.61"
790+#define DEFAULT_PRESSURE 0xb0c0
791+
792+/*
793+ * Debug
794+ */
795+#if 0
796+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
797+#else
798+#define dbg(format, arg...)
799+#endif
800+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
801+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
802+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
803+
804+/*
805+ * Module parameters
806+ */
807+
808+/*
809+ * Set internal pull up for pen detect.
810+ *
811+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
812+ * i.e. pull up resistance = 64k Ohms / rpu.
813+ *
814+ * Adjust this value if you are having problems with pen detect not
815+ * detecting any down event.
816+ */
817+static int rpu = 3;
818+module_param(rpu, int, 0);
819+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
820+
821+/*
822+ * Set current used for pressure measurement.
823+ *
824+ * Set pil = 2 to use 400uA
825+ * pil = 1 to use 200uA and
826+ * pil = 0 to disable pressure measurement.
827+ *
828+ * This is used to increase the range of values returned by the adc
829+ * when measureing touchpanel pressure.
830+ */
831+static int pil = 0;
832+module_param(pil, int, 0);
833+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
834+
835+/*
836+ * Set threshold for pressure measurement.
837+ *
838+ * Pen down pressure below threshold is ignored.
839+ */
840+static int pressure = DEFAULT_PRESSURE & 0xfff;
841+module_param(pressure, int, 0);
842+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
843+
844+/*
845+ * Set adc sample delay.
846+ *
847+ * For accurate touchpanel measurements, some settling time may be
848+ * required between the switch matrix applying a voltage across the
849+ * touchpanel plate and the ADC sampling the signal.
850+ *
851+ * This delay can be set by setting delay = n, where n is the array
852+ * position of the delay in the array delay_table below.
853+ * Long delays > 1ms are supported for completeness, but are not
854+ * recommended.
855+ */
856+static int delay = 3;
857+module_param(delay, int, 0);
858+MODULE_PARM_DESC(delay, "Set adc sample delay.");
859+
860+/*
861+ * Set five_wire = 1 to use a 5 wire touchscreen.
862+ *
863+ * NOTE: Five wire mode does not allow for readback of pressure.
864+ */
865+static int five_wire;
866+module_param(five_wire, int, 0);
867+MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
868+
869+/*
870+ * Set adc mask function.
871+ *
872+ * Sources of glitch noise, such as signals driving an LCD display, may feed
873+ * through to the touch screen plates and affect measurement accuracy. In
874+ * order to minimise this, a signal may be applied to the MASK pin to delay or
875+ * synchronise the sampling.
876+ *
877+ * 0 = No delay or sync
878+ * 1 = High on pin stops conversions
879+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
880+ * 3 = Edge triggered, edge on pin starts conversion after delay param
881+ */
882+static int mask = 0;
883+module_param(mask, int, 0);
884+MODULE_PARM_DESC(mask, "Set adc mask function.");
885+
886+/*
887+ * Coordinate Polling Enable.
888+ *
889+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
890+ * for every poll.
891+ */
892+static int coord = 0;
893+module_param(coord, int, 0);
894+MODULE_PARM_DESC(coord, "Polling coordinate mode");
895+
896+/*
897+ * ADC sample delay times in uS
898+ */
899+static const int delay_table[] = {
900+ 21, // 1 AC97 Link frames
901+ 42, // 2
902+ 84, // 4
903+ 167, // 8
904+ 333, // 16
905+ 667, // 32
906+ 1000, // 48
907+ 1333, // 64
908+ 2000, // 96
909+ 2667, // 128
910+ 3333, // 160
911+ 4000, // 192
912+ 4667, // 224
913+ 5333, // 256
914+ 6000, // 288
915+ 0 // No delay, switch matrix always on
916+};
917+
918+/*
919+ * Delay after issuing a POLL command.
920+ *
921+ * The delay is 3 AC97 link frames + the touchpanel settling delay
922+ */
923+static inline void poll_delay(int d)
924+{
925+ udelay (3 * AC97_LINK_FRAME + delay_table [d]);
926+}
927+
928+/*
929+ * set up the physical settings of the WM9712
930+ */
931+static void init_wm9712_phy(struct wm97xx* wm)
932+{
933+ u16 dig1 = 0;
934+ u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
935+
936+ /* WM9712 rpu */
937+ if (rpu) {
938+ dig2 &= 0xffc0;
939+ dig2 |= WM9712_RPU(rpu);
940+ dbg("setting pen detect pull-up to %d Ohms",64000 / rpu);
941+ }
942+
943+ /* touchpanel pressure current*/
944+ if (pil == 2) {
945+ dig2 |= WM9712_PIL;
946+ dbg("setting pressure measurement current to 400uA.");
947+ } else if (pil)
948+ dbg("setting pressure measurement current to 200uA.");
949+ if(!pil)
950+ pressure = 0;
951+
952+ /* WM9712 five wire */
953+ if (five_wire) {
954+ dig2 |= WM9712_45W;
955+ dbg("setting 5-wire touchscreen mode.");
956+ }
957+
958+ /* polling mode sample settling delay */
959+ if (delay < 0 || delay > 15) {
960+ dbg("supplied delay out of range.");
961+ delay = 4;
962+ }
963+ dig1 &= 0xff0f;
964+ dig1 |= WM97XX_DELAY(delay);
965+ dbg("setting adc sample delay to %d u Secs.", delay_table[delay]);
966+
967+ /* mask */
968+ dig2 |= ((mask & 0x3) << 6);
969+ if (mask) {
970+ u16 reg;
971+ /* Set GPIO4 as Mask Pin*/
972+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
973+ wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
974+ reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
975+ wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
976+ }
977+
978+ /* wait - coord mode */
979+ if(coord)
980+ dig2 |= WM9712_WAIT;
981+
982+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
983+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
984+}
985+
986+static int wm9712_digitiser_ioctl(struct wm97xx* wm, int cmd)
987+{
988+ u16 dig2 = wm->dig[2];
989+
990+ switch(cmd) {
991+ case WM97XX_DIG_START:
992+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2 | WM97XX_PRP_DET_DIG);
993+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
994+ break;
995+ case WM97XX_DIG_STOP:
996+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2 & ~WM97XX_PRP_DET_DIG);
997+ break;
998+ case WM97XX_AUX_PREPARE:
999+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
1000+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
1001+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
1002+ break;
1003+ case WM97XX_DIG_RESTORE:
1004+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
1005+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
1006+ break;
1007+ case WM97XX_PHY_INIT:
1008+ init_wm9712_phy(wm);
1009+ break;
1010+ default:
1011+ return -EINVAL;
1012+ }
1013+ return 0;
1014+}
1015+
1016+static inline int is_pden (struct wm97xx* wm)
1017+{
1018+ return wm->dig[2] & WM9712_PDEN;
1019+}
1020+
1021+/*
1022+ * Read a sample from the WM9712 adc in polling mode.
1023+ */
1024+static int wm9712_poll_sample (struct wm97xx* wm, int adcsel, int *sample)
1025+{
1026+ int timeout = 5 * delay;
1027+
1028+ if (!wm->pen_probably_down) {
1029+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1030+ if (!(data & WM97XX_PEN_DOWN))
1031+ return RC_PENUP;
1032+ wm->pen_probably_down = 1;
1033+ }
1034+
1035+ /* set up digitiser */
1036+ if (adcsel & 0x8000)
1037+ adcsel = ((adcsel & 0x7fff) + 3) << 12;
1038+
1039+ if (wm->mach_ops && wm->mach_ops->pre_sample)
1040+ wm->mach_ops->pre_sample(adcsel);
1041+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
1042+
1043+ /* wait 3 AC97 time slots + delay for conversion */
1044+ poll_delay (delay);
1045+
1046+ /* wait for POLL to go low */
1047+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) {
1048+ udelay(AC97_LINK_FRAME);
1049+ timeout--;
1050+ }
1051+
1052+ if (timeout <= 0) {
1053+ /* If PDEN is set, we can get a timeout when pen goes up */
1054+ if (is_pden(wm))
1055+ wm->pen_probably_down = 0;
1056+ else
1057+ dbg ("adc sample timeout");
1058+ return RC_PENUP;
1059+ }
1060+
1061+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1062+ if (wm->mach_ops && wm->mach_ops->post_sample)
1063+ wm->mach_ops->post_sample(adcsel);
1064+
1065+ /* check we have correct sample */
1066+ if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
1067+ dbg ("adc wrong sample, read %x got %x", adcsel,
1068+ *sample & WM97XX_ADCSEL_MASK);
1069+ return RC_PENUP;
1070+ }
1071+
1072+ if (!(*sample & WM97XX_PEN_DOWN)) {
1073+ wm->pen_probably_down = 0;
1074+ return RC_PENUP;
1075+ }
1076+
1077+ return RC_VALID;
1078+}
1079+
1080+/*
1081+ * Read a coord from the WM9712 adc in polling mode.
1082+ */
1083+static int wm9712_poll_coord (struct wm97xx* wm, struct wm97xx_data *data)
1084+{
1085+ int timeout = 5 * delay;
1086+
1087+ if (!wm->pen_probably_down) {
1088+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1089+ if (!(data & WM97XX_PEN_DOWN))
1090+ return RC_PENUP;
1091+ wm->pen_probably_down = 1;
1092+ }
1093+
1094+ /* set up digitiser */
1095+ if (wm->mach_ops && wm->mach_ops->pre_sample)
1096+ wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
1097+
1098+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
1099+ WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
1100+
1101+ /* wait 3 AC97 time slots + delay for conversion and read x */
1102+ poll_delay(delay);
1103+ data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1104+ /* wait for POLL to go low */
1105+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) {
1106+ udelay(AC97_LINK_FRAME);
1107+ timeout--;
1108+ }
1109+
1110+ if (timeout <= 0) {
1111+ /* If PDEN is set, we can get a timeout when pen goes up */
1112+ if (is_pden(wm))
1113+ wm->pen_probably_down = 0;
1114+ else
1115+ dbg ("adc sample timeout");
1116+ return RC_PENUP;
1117+ }
1118+
1119+ /* read back y data */
1120+ data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1121+ if (pil)
1122+ data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1123+ else
1124+ data->p = DEFAULT_PRESSURE;
1125+
1126+ if (wm->mach_ops && wm->mach_ops->post_sample)
1127+ wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
1128+
1129+ /* check we have correct sample */
1130+ if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
1131+ goto err;
1132+ if(pil && !(data->p & WM97XX_ADCSEL_PRES))
1133+ goto err;
1134+
1135+ if (!(data->x & WM97XX_PEN_DOWN)) {
1136+ wm->pen_probably_down = 0;
1137+ return RC_PENUP;
1138+ }
1139+ return RC_VALID;
1140+err:
1141+ return RC_PENUP;
1142+}
1143+
1144+/*
1145+ * Sample the WM9712 touchscreen in polling mode
1146+ */
1147+static int wm9712_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
1148+{
1149+ int rc;
1150+
1151+ if(coord) {
1152+ if((rc = wm9712_poll_coord(wm, data)) != RC_VALID)
1153+ return rc;
1154+ } else {
1155+ if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID)
1156+ return rc;
1157+
1158+ if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID)
1159+ return rc;
1160+
1161+ if (pil && !five_wire) {
1162+ if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID)
1163+ return rc;
1164+ } else
1165+ data->p = DEFAULT_PRESSURE;
1166+ }
1167+ return RC_VALID;
1168+}
1169+
1170+/*
1171+ * Enable WM9712 continuous mode, i.e. touch data is streamed across an AC97 slot
1172+ */
1173+static int wm9712_acc_enable (struct wm97xx* wm, int enable)
1174+{
1175+ u16 dig1, dig2;
1176+ int ret = 0;
1177+
1178+ dig1 = wm->dig[1];
1179+ dig2 = wm->dig[2];
1180+
1181+ if (enable) {
1182+ /* continous mode */
1183+ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0)
1184+ return ret;
1185+ dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
1186+ WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
1187+ dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
1188+ WM97XX_DELAY (delay) |
1189+ WM97XX_SLT (wm->acc_slot) |
1190+ WM97XX_RATE (wm->acc_rate);
1191+ if (pil)
1192+ dig1 |= WM97XX_ADCSEL_PRES;
1193+ dig2 |= WM9712_PDEN;
1194+ } else {
1195+ dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
1196+ dig2 &= ~WM9712_PDEN;
1197+ if (wm->mach_ops->acc_shutdown)
1198+ wm->mach_ops->acc_shutdown(wm);
1199+ }
1200+
1201+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
1202+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
1203+ return 0;
1204+}
1205+
1206+struct wm97xx_codec_drv wm97xx_codec = {
1207+ .id = WM9712_ID2,
1208+ .name = "wm9712",
1209+ .poll_sample = wm9712_poll_sample,
1210+ .poll_touch = wm9712_poll_touch,
1211+ .acc_enable = wm9712_acc_enable,
1212+ .digitiser_ioctl = wm9712_digitiser_ioctl,
1213+};
1214+
1215+EXPORT_SYMBOL_GPL(wm97xx_codec);
1216+
1217+/* Module information */
1218+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1219+MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
1220+MODULE_LICENSE("GPL");
1221Index: linux-2.6.17/drivers/input/touchscreen/wm9713.c
1222===================================================================
1223--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1224+++ linux-2.6.17/drivers/input/touchscreen/wm9713.c 2006-09-19 20:36:47.969052000 +0200
1225@@ -0,0 +1,461 @@
1226+/*
1227+ * wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec.
1228+ *
1229+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
1230+ * Author: Liam Girdwood
1231+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
1232+ * Parts Copyright : Ian Molton <spyro@f2s.com>
1233+ * Andrew Zabolotny <zap@homelink.ru>
1234+ * Russell King <rmk@arm.linux.org.uk>
1235+ *
1236+ * This program is free software; you can redistribute it and/or modify it
1237+ * under the terms of the GNU General Public License as published by the
1238+ * Free Software Foundation; either version 2 of the License, or (at your
1239+ * option) any later version.
1240+ *
1241+ * Revision history
1242+ * 6th Sep 2006 Mike Arthur <linux@wolfsonmicro.com>
1243+ * Added pre and post sample calls.
1244+ *
1245+ */
1246+
1247+#include <linux/module.h>
1248+#include <linux/moduleparam.h>
1249+#include <linux/version.h>
1250+#include <linux/kernel.h>
1251+#include <linux/input.h>
1252+#include <linux/delay.h>
1253+#include <linux/bitops.h>
1254+#include <linux/wm97xx.h>
1255+
1256+#define TS_NAME "wm97xx"
1257+#define WM9713_VERSION "0.53"
1258+#define DEFAULT_PRESSURE 0xb0c0
1259+
1260+/*
1261+ * Debug
1262+ */
1263+#if 0
1264+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
1265+#else
1266+#define dbg(format, arg...)
1267+#endif
1268+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
1269+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
1270+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
1271+
1272+/*
1273+ * Module parameters
1274+ */
1275+
1276+/*
1277+ * Set internal pull up for pen detect.
1278+ *
1279+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
1280+ * i.e. pull up resistance = 64k Ohms / rpu.
1281+ *
1282+ * Adjust this value if you are having problems with pen detect not
1283+ * detecting any down event.
1284+ */
1285+static int rpu = 1;
1286+module_param(rpu, int, 0);
1287+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
1288+
1289+/*
1290+ * Set current used for pressure measurement.
1291+ *
1292+ * Set pil = 2 to use 400uA
1293+ * pil = 1 to use 200uA and
1294+ * pil = 0 to disable pressure measurement.
1295+ *
1296+ * This is used to increase the range of values returned by the adc
1297+ * when measureing touchpanel pressure.
1298+ */
1299+static int pil = 0;
1300+module_param(pil, int, 0);
1301+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
1302+
1303+/*
1304+ * Set threshold for pressure measurement.
1305+ *
1306+ * Pen down pressure below threshold is ignored.
1307+ */
1308+static int pressure = DEFAULT_PRESSURE & 0xfff;
1309+module_param(pressure, int, 0);
1310+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
1311+
1312+/*
1313+ * Set adc sample delay.
1314+ *
1315+ * For accurate touchpanel measurements, some settling time may be
1316+ * required between the switch matrix applying a voltage across the
1317+ * touchpanel plate and the ADC sampling the signal.
1318+ *
1319+ * This delay can be set by setting delay = n, where n is the array
1320+ * position of the delay in the array delay_table below.
1321+ * Long delays > 1ms are supported for completeness, but are not
1322+ * recommended.
1323+ */
1324+static int delay = 4;
1325+module_param(delay, int, 0);
1326+MODULE_PARM_DESC(delay, "Set adc sample delay.");
1327+
1328+/*
1329+ * Set adc mask function.
1330+ *
1331+ * Sources of glitch noise, such as signals driving an LCD display, may feed
1332+ * through to the touch screen plates and affect measurement accuracy. In
1333+ * order to minimise this, a signal may be applied to the MASK pin to delay or
1334+ * synchronise the sampling.
1335+ *
1336+ * 0 = No delay or sync
1337+ * 1 = High on pin stops conversions
1338+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
1339+ * 3 = Edge triggered, edge on pin starts conversion after delay param
1340+ */
1341+static int mask = 0;
1342+module_param(mask, int, 0);
1343+MODULE_PARM_DESC(mask, "Set adc mask function.");
1344+
1345+/*
1346+ * Coordinate Polling Enable.
1347+ *
1348+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
1349+ * for every poll.
1350+ */
1351+static int coord = 1;
1352+module_param(coord, int, 0);
1353+MODULE_PARM_DESC(coord, "Polling coordinate mode");
1354+
1355+/*
1356+ * ADC sample delay times in uS
1357+ */
1358+static const int delay_table[] = {
1359+ 21, // 1 AC97 Link frames
1360+ 42, // 2
1361+ 84, // 4
1362+ 167, // 8
1363+ 333, // 16
1364+ 667, // 32
1365+ 1000, // 48
1366+ 1333, // 64
1367+ 2000, // 96
1368+ 2667, // 128
1369+ 3333, // 160
1370+ 4000, // 192
1371+ 4667, // 224
1372+ 5333, // 256
1373+ 6000, // 288
1374+ 0 // No delay, switch matrix always on
1375+};
1376+
1377+/*
1378+ * Delay after issuing a POLL command.
1379+ *
1380+ * The delay is 3 AC97 link frames + the touchpanel settling delay
1381+ */
1382+static inline void poll_delay(int d)
1383+{
1384+ udelay (3 * AC97_LINK_FRAME + delay_table [d]);
1385+}
1386+
1387+/*
1388+ * set up the physical settings of the WM9713
1389+ */
1390+static void init_wm9713_phy(struct wm97xx* wm)
1391+{
1392+ u16 dig1 = 0, dig2, dig3;
1393+
1394+ /* default values */
1395+ dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
1396+ dig3= WM9712_RPU(1);
1397+
1398+ /* rpu */
1399+ if (rpu) {
1400+ dig3 &= 0xffc0;
1401+ dig3 |= WM9712_RPU(rpu);
1402+ info("setting pen detect pull-up to %d Ohms",64000 / rpu);
1403+ }
1404+
1405+ /* touchpanel pressure */
1406+ if (pil == 2) {
1407+ dig3 |= WM9712_PIL;
1408+ info("setting pressure measurement current to 400uA.");
1409+ } else if (pil)
1410+ info ("setting pressure measurement current to 200uA.");
1411+ if(!pil)
1412+ pressure = 0;
1413+
1414+ /* sample settling delay */
1415+ if (delay < 0 || delay > 15) {
1416+ info ("supplied delay out of range.");
1417+ delay = 4;
1418+ info("setting adc sample delay to %d u Secs.", delay_table[delay]);
1419+ }
1420+ dig2 &= 0xff0f;
1421+ dig2 |= WM97XX_DELAY(delay);
1422+
1423+ /* mask */
1424+ dig3 |= ((mask & 0x3) << 4);
1425+ if(coord)
1426+ dig3 |= WM9713_WAIT;
1427+
1428+ wm->misc = wm97xx_reg_read(wm, 0x5a);
1429+
1430+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
1431+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
1432+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
1433+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
1434+}
1435+
1436+static int wm9713_digitiser_ioctl(struct wm97xx* wm, int cmd)
1437+{
1438+ u16 val = 0;
1439+
1440+ switch(cmd){
1441+ case WM97XX_DIG_START:
1442+ val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
1443+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
1444+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] | WM97XX_PRP_DET_DIG);
1445+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
1446+ break;
1447+ case WM97XX_DIG_STOP:
1448+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] & ~WM97XX_PRP_DET_DIG);
1449+ val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
1450+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
1451+ break;
1452+ case WM97XX_AUX_PREPARE:
1453+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
1454+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
1455+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
1456+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
1457+ break;
1458+ case WM97XX_DIG_RESTORE:
1459+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
1460+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
1461+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
1462+ break;
1463+ case WM97XX_PHY_INIT:
1464+ init_wm9713_phy(wm);
1465+ break;
1466+ default:
1467+ return -EINVAL;
1468+ }
1469+ return 0;
1470+}
1471+
1472+static inline int is_pden (struct wm97xx* wm)
1473+{
1474+ return wm->dig[2] & WM9713_PDEN;
1475+}
1476+
1477+/*
1478+ * Read a sample from the WM9713 adc in polling mode.
1479+ */
1480+static int wm9713_poll_sample (struct wm97xx* wm, int adcsel, int *sample)
1481+{
1482+ u16 dig1;
1483+ int timeout = 5 * delay;
1484+
1485+ if (!wm->pen_probably_down) {
1486+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1487+ if (!(data & WM97XX_PEN_DOWN))
1488+ return RC_PENUP;
1489+ wm->pen_probably_down = 1;
1490+ }
1491+
1492+ /* set up digitiser */
1493+ if (adcsel & 0x8000)
1494+ adcsel = 1 << ((adcsel & 0x7fff) + 3);
1495+
1496+ dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
1497+ dig1 &= ~WM9713_ADCSEL_MASK;
1498+
1499+ if (wm->mach_ops && wm->mach_ops->pre_sample)
1500+ wm->mach_ops->pre_sample(adcsel);
1501+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel |WM9713_POLL);
1502+
1503+ /* wait 3 AC97 time slots + delay for conversion */
1504+ poll_delay(delay);
1505+
1506+ /* wait for POLL to go low */
1507+ while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && timeout) {
1508+ udelay(AC97_LINK_FRAME);
1509+ timeout--;
1510+ }
1511+
1512+ if (timeout <= 0) {
1513+ /* If PDEN is set, we can get a timeout when pen goes up */
1514+ if (is_pden(wm))
1515+ wm->pen_probably_down = 0;
1516+ else
1517+ dbg ("adc sample timeout");
1518+ return RC_PENUP;
1519+ }
1520+
1521+ *sample =wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1522+ if (wm->mach_ops && wm->mach_ops->post_sample)
1523+ wm->mach_ops->post_sample(adcsel);
1524+
1525+ /* check we have correct sample */
1526+ if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
1527+ dbg ("adc wrong sample, read %x got %x", adcsel,
1528+ *sample & WM97XX_ADCSRC_MASK);
1529+ return RC_PENUP;
1530+ }
1531+
1532+ if (!(*sample & WM97XX_PEN_DOWN)) {
1533+ wm->pen_probably_down = 0;
1534+ return RC_PENUP;
1535+ }
1536+
1537+ return RC_VALID;
1538+}
1539+
1540+/*
1541+ * Read a coordinate from the WM9713 adc in polling mode.
1542+ */
1543+static int wm9713_poll_coord (struct wm97xx* wm, struct wm97xx_data *data)
1544+{
1545+ u16 dig1;
1546+ int timeout = 5 * delay;
1547+
1548+ if (!wm->pen_probably_down) {
1549+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1550+ if (!(data & WM97XX_PEN_DOWN))
1551+ return RC_PENUP;
1552+ wm->pen_probably_down = 1;
1553+ }
1554+
1555+ /* set up digitiser */
1556+ dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
1557+ dig1 &= ~WM9713_ADCSEL_MASK;
1558+ if(pil)
1559+ dig1 |= WM97XX_ADCSEL_PRES;
1560+
1561+ if (wm->mach_ops && wm->mach_ops->pre_sample)
1562+ wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
1563+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL | WM9713_COO);
1564+
1565+ /* wait 3 AC97 time slots + delay for conversion */
1566+ poll_delay(delay);
1567+ data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1568+ /* wait for POLL to go low */
1569+ while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && timeout) {
1570+ udelay(AC97_LINK_FRAME);
1571+ timeout--;
1572+ }
1573+
1574+ if (timeout <= 0) {
1575+ /* If PDEN is set, we can get a timeout when pen goes up */
1576+ if (is_pden(wm))
1577+ wm->pen_probably_down = 0;
1578+ else
1579+ dbg ("adc sample timeout");
1580+ return RC_PENUP;
1581+ }
1582+
1583+ /* read back data */
1584+ data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1585+ if (pil)
1586+ data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
1587+ else
1588+ data->p = DEFAULT_PRESSURE;
1589+
1590+ if (wm->mach_ops && wm->mach_ops->post_sample)
1591+ wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
1592+
1593+ /* check we have correct sample */
1594+ if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
1595+ goto err;
1596+ if(pil && !(data->p & WM97XX_ADCSEL_PRES))
1597+ goto err;
1598+
1599+ if (!(data->x & WM97XX_PEN_DOWN)) {
1600+ wm->pen_probably_down = 0;
1601+ return RC_PENUP;
1602+ }
1603+ return RC_VALID;
1604+err:
1605+ return RC_PENUP;
1606+}
1607+
1608+/*
1609+ * Sample the WM9713 touchscreen in polling mode
1610+ */
1611+static int wm9713_poll_touch(struct wm97xx* wm, struct wm97xx_data *data)
1612+{
1613+ int rc;
1614+
1615+ if(coord) {
1616+ if((rc = wm9713_poll_coord(wm, data)) != RC_VALID)
1617+ return rc;
1618+ } else {
1619+ if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x)) != RC_VALID)
1620+ return rc;
1621+ if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y)) != RC_VALID)
1622+ return rc;
1623+ if (pil) {
1624+ if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES, &data->p)) != RC_VALID)
1625+ return rc;
1626+ } else
1627+ data->p = DEFAULT_PRESSURE;
1628+ }
1629+ return RC_VALID;
1630+}
1631+
1632+/*
1633+ * Enable WM9713 continuous mode, i.e. touch data is streamed across an AC97 slot
1634+ */
1635+static int wm9713_acc_enable (struct wm97xx* wm, int enable)
1636+{
1637+ u16 dig1, dig2, dig3;
1638+ int ret = 0;
1639+
1640+ dig1 = wm->dig[0];
1641+ dig2 = wm->dig[1];
1642+ dig3 = wm->dig[2];
1643+
1644+ if (enable) {
1645+ /* continous mode */
1646+ if (wm->mach_ops->acc_startup &&
1647+ (ret = wm->mach_ops->acc_startup(wm)) < 0)
1648+ return ret;
1649+
1650+ dig1 &= ~WM9713_ADCSEL_MASK;
1651+ dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X | WM9713_ADCSEL_Y;
1652+ if (pil)
1653+ dig1 |= WM9713_ADCSEL_PRES;
1654+ dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK | WM97XX_CM_RATE_MASK);
1655+ dig2 |= WM97XX_SLEN | WM97XX_DELAY (delay) |
1656+ WM97XX_SLT (wm->acc_slot) | WM97XX_RATE (wm->acc_rate);
1657+ dig3 |= WM9713_PDEN;
1658+ } else {
1659+ dig1 &= ~(WM9713_CTC | WM9713_COO);
1660+ dig2 &= ~WM97XX_SLEN;
1661+ dig3 &= ~WM9713_PDEN;
1662+ if (wm->mach_ops->acc_shutdown)
1663+ wm->mach_ops->acc_shutdown(wm);
1664+ }
1665+
1666+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
1667+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
1668+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
1669+ return ret;
1670+}
1671+
1672+struct wm97xx_codec_drv wm97xx_codec = {
1673+ .id = WM9713_ID2,
1674+ .name = "wm9713",
1675+ .poll_sample = wm9713_poll_sample,
1676+ .poll_touch = wm9713_poll_touch,
1677+ .acc_enable = wm9713_acc_enable,
1678+ .digitiser_ioctl = wm9713_digitiser_ioctl,
1679+};
1680+
1681+EXPORT_SYMBOL_GPL(wm97xx_codec);
1682+
1683+/* Module information */
1684+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1685+MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
1686+MODULE_LICENSE("GPL");
1687Index: linux-2.6.17/drivers/input/touchscreen/wm97xx-core.c
1688===================================================================
1689--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1690+++ linux-2.6.17/drivers/input/touchscreen/wm97xx-core.c 2006-09-19 20:36:47.969052000 +0200
1691@@ -0,0 +1,912 @@
1692+/*
1693+ * wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712
1694+ * and WM9713 AC97 Codecs.
1695+ *
1696+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC.
1697+ * Author: Liam Girdwood
1698+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
1699+ * Parts Copyright : Ian Molton <spyro@f2s.com>
1700+ * Andrew Zabolotny <zap@homelink.ru>
1701+ * Russell King <rmk@arm.linux.org.uk>
1702+ *
1703+ * This program is free software; you can redistribute it and/or modify it
1704+ * under the terms of the GNU General Public License as published by the
1705+ * Free Software Foundation; either version 2 of the License, or (at your
1706+ * option) any later version.
1707+ *
1708+ * Notes:
1709+ *
1710+ * Features:
1711+ * - supports WM9705, WM9712, WM9713
1712+ * - polling mode
1713+ * - continuous mode (arch-dependent)
1714+ * - adjustable rpu/dpp settings
1715+ * - adjustable pressure current
1716+ * - adjustable sample settle delay
1717+ * - 4 and 5 wire touchscreens (5 wire is WM9712 only)
1718+ * - pen down detection
1719+ * - battery monitor
1720+ * - sample AUX adc's
1721+ * - power management
1722+ * - codec GPIO
1723+ * - codec event notification
1724+ * Todo
1725+ * - Support for async sampling control for noisy LCD's.
1726+ *
1727+ * Revision history
1728+ * 7th May 2003 Initial version.
1729+ * 6th June 2003 Added non module support and AC97 registration.
1730+ * 18th June 2003 Added AUX adc sampling.
1731+ * 23rd June 2003 Did some minimal reformatting, fixed a couple of
1732+ * codec_mutexing bugs and noted a race to fix.
1733+ * 24th June 2003 Added power management and fixed race condition.
1734+ * 10th July 2003 Changed to a misc device.
1735+ * 31st July 2003 Moved TS_EVENT and TS_CAL to wm97xx.h
1736+ * 8th Aug 2003 Added option for read() calling wm97xx_sample_touch()
1737+ * because some ac97_read/ac_97_write call schedule()
1738+ * 7th Nov 2003 Added Input touch event interface, stanley.cai@intel.com
1739+ * 13th Nov 2003 Removed h3600 touch interface, added interrupt based
1740+ * pen down notification and implemented continous mode
1741+ * on XScale arch.
1742+ * 16th Nov 2003 Ian Molton <spyro@f2s.com>
1743+ * Modified so that it suits the new 2.6 driver model.
1744+ * 25th Jan 2004 Andrew Zabolotny <zap@homelink.ru>
1745+ * Implemented IRQ-driven pen down detection, implemented
1746+ * the private API meant to be exposed to platform-specific
1747+ * drivers, reorganized the driver so that it supports
1748+ * an arbitrary number of devices.
1749+ * 1st Feb 2004 Moved continuous mode handling to a separate
1750+ * architecture-dependent file. For now only PXA
1751+ * built-in AC97 controller is supported (pxa-ac97-wm97xx.c).
1752+ * 11th Feb 2004 Reduced CPU usage by keeping a cached copy of both
1753+ * digitizer registers instead of reading them every time.
1754+ * A reorganization of the whole code for better
1755+ * error handling.
1756+ * 17th Apr 2004 Added BMON support.
1757+ * 17th Nov 2004 Added codec GPIO, codec event handling (real and virtual
1758+ * GPIOs) and 2.6 power management.
1759+ * 29th Nov 2004 Added WM9713 support.
1760+ * 4th Jul 2005 Moved codec specific code out to seperate files.
1761+ * 6th Sep 2006 Mike Arthur <linux@wolfsonmicro.com>
1762+ * Added bus interface.
1763+ */
1764+
1765+#include <linux/module.h>
1766+#include <linux/moduleparam.h>
1767+#include <linux/version.h>
1768+#include <linux/kernel.h>
1769+#include <linux/init.h>
1770+#include <linux/delay.h>
1771+#include <linux/string.h>
1772+#include <linux/proc_fs.h>
1773+#include <linux/pm.h>
1774+#include <linux/interrupt.h>
1775+#include <linux/bitops.h>
1776+#include <linux/workqueue.h>
1777+#include <linux/device.h>
1778+#include <linux/wm97xx.h>
1779+#include <asm/uaccess.h>
1780+#include <asm/io.h>
1781+
1782+#define TS_NAME "wm97xx"
1783+#define WM_CORE_VERSION "0.63"
1784+#define DEFAULT_PRESSURE 0xb0c0
1785+
1786+/*
1787+ * WM97xx - enable/disable AUX ADC sysfs
1788+ */
1789+static int aux_sys = 1;
1790+module_param(aux_sys, int, 0);
1791+MODULE_PARM_DESC(aux_sys, "enable AUX ADC sysfs entries");
1792+
1793+/*
1794+ * WM97xx - enable/disable codec status sysfs
1795+ */
1796+static int status_sys = 1;
1797+module_param(status_sys, int, 0);
1798+MODULE_PARM_DESC(status_sys, "enable codec status sysfs entries");
1799+
1800+/*
1801+ * Touchscreen absolute values
1802+ *
1803+ * These parameters are used to help the input layer discard out of
1804+ * range readings and reduce jitter etc.
1805+ *
1806+ * o min, max:- indicate the min and max values your touch screen returns
1807+ * o fuzz:- use a higher number to reduce jitter
1808+ *
1809+ * The default values correspond to Mainstone II in QVGA mode
1810+ *
1811+ * Please read
1812+ * Documentation/input/input-programming.txt for more details.
1813+ */
1814+
1815+static int abs_x[3] = {350,3900,5};
1816+module_param_array(abs_x, int, NULL, 0);
1817+MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
1818+
1819+static int abs_y[3] = {320,3750,40};
1820+module_param_array(abs_y, int, NULL, 0);
1821+MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
1822+
1823+static int abs_p[3] = {0,150,4};
1824+module_param_array(abs_p, int, NULL, 0);
1825+MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz");
1826+
1827+/*
1828+ * Debug
1829+ */
1830+#if 0
1831+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg)
1832+#else
1833+#define dbg(format, arg...)
1834+#endif
1835+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
1836+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
1837+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
1838+
1839+/* codec AC97 IO access */
1840+int wm97xx_reg_read(struct wm97xx *wm, u16 reg)
1841+{
1842+ if (wm->ac97)
1843+ return wm->ac97->bus->ops->read(wm->ac97, reg);
1844+ else
1845+ return -1;
1846+}
1847+
1848+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val)
1849+{
1850+ /* cache digitiser registers */
1851+ if(reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3)
1852+ wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val;
1853+
1854+ /* cache gpio regs */
1855+ if(reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE)
1856+ wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val;
1857+
1858+ /* wm9713 irq reg */
1859+ if(reg == 0x5a)
1860+ wm->misc = val;
1861+
1862+ if (wm->ac97)
1863+ wm->ac97->bus->ops->write(wm->ac97, reg, val);
1864+}
1865+
1866+
1867+/**
1868+ * wm97xx_read_aux_adc - Read the aux adc.
1869+ * @wm: wm97xx device.
1870+ * @adcsel: codec ADC to be read
1871+ *
1872+ * Reads the selected AUX ADC.
1873+ */
1874+
1875+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
1876+{
1877+ int power_adc = 0, auxval;
1878+ u16 power = 0;
1879+
1880+ /* get codec */
1881+ mutex_lock(&wm->codec_mutex);
1882+
1883+ /* When the touchscreen is not in use, we may have to power up the AUX ADC
1884+ * before we can use sample the AUX inputs->
1885+ */
1886+ if (wm->id == WM9713_ID2 &&
1887+ (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) {
1888+ power_adc = 1;
1889+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff);
1890+ }
1891+
1892+ /* Prepare the codec for AUX reading */
1893+ wm->codec->digitiser_ioctl(wm, WM97XX_AUX_PREPARE);
1894+
1895+ /* Turn polling mode on to read AUX ADC */
1896+ wm->pen_probably_down = 1;
1897+ wm->codec->poll_sample(wm, adcsel, &auxval);
1898+
1899+ if (power_adc)
1900+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
1901+
1902+ wm->codec->digitiser_ioctl(wm, WM97XX_DIG_RESTORE);
1903+
1904+ wm->pen_probably_down = 0;
1905+
1906+ mutex_unlock(&wm->codec_mutex);
1907+ return auxval & 0xfff;
1908+}
1909+
1910+#define WM97XX_AUX_ATTR(name,input) \
1911+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \
1912+{ \
1913+ struct wm97xx *wm = (struct wm97xx*)dev->driver_data; \
1914+ return sprintf(buf, "%d\n", wm97xx_read_aux_adc(wm, input)); \
1915+} \
1916+static DEVICE_ATTR(name, 0444, name##_show, NULL)
1917+
1918+WM97XX_AUX_ATTR(aux1, WM97XX_AUX_ID1);
1919+WM97XX_AUX_ATTR(aux2, WM97XX_AUX_ID2);
1920+WM97XX_AUX_ATTR(aux3, WM97XX_AUX_ID3);
1921+WM97XX_AUX_ATTR(aux4, WM97XX_AUX_ID4);
1922+
1923+#define WM97XX_STATUS_ATTR(name) \
1924+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \
1925+{ \
1926+ struct wm97xx *wm = (struct wm97xx*)dev->driver_data; \
1927+ return sprintf(buf, "%d\n", wm97xx_reg_read(wm, AC97_GPIO_STATUS)); \
1928+} \
1929+static DEVICE_ATTR(name, 0444, name##_show, NULL)
1930+
1931+WM97XX_STATUS_ATTR(gpio);
1932+
1933+static int wm97xx_sys_add(struct device *dev)
1934+{
1935+ if (aux_sys) {
1936+ device_create_file(dev, &dev_attr_aux1);
1937+ device_create_file(dev, &dev_attr_aux2);
1938+ device_create_file(dev, &dev_attr_aux3);
1939+ device_create_file(dev, &dev_attr_aux4);
1940+ }
1941+ if (status_sys)
1942+ device_create_file(dev, &dev_attr_gpio);
1943+ return 0;
1944+}
1945+
1946+static void wm97xx_sys_remove(struct device *dev)
1947+{
1948+ if (status_sys)
1949+ device_remove_file(dev, &dev_attr_gpio);
1950+ if (aux_sys) {
1951+ device_remove_file(dev, &dev_attr_aux1);
1952+ device_remove_file(dev, &dev_attr_aux2);
1953+ device_remove_file(dev, &dev_attr_aux3);
1954+ device_remove_file(dev, &dev_attr_aux4);
1955+ }
1956+}
1957+
1958+/**
1959+ * wm97xx_get_gpio - Get the status of a codec GPIO.
1960+ * @wm: wm97xx device.
1961+ * @gpio: gpio
1962+ *
1963+ * Get the status of a codec GPIO pin
1964+ */
1965+
1966+wm97xx_gpio_status_t wm97xx_get_gpio(struct wm97xx *wm, u32 gpio)
1967+{
1968+ u16 status;
1969+ wm97xx_gpio_status_t ret;
1970+
1971+ mutex_lock(&wm->codec_mutex);
1972+ status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
1973+
1974+ if (status & gpio)
1975+ ret = WM97XX_GPIO_HIGH;
1976+ else
1977+ ret = WM97XX_GPIO_LOW;
1978+
1979+ mutex_unlock(&wm->codec_mutex);
1980+ return ret;
1981+}
1982+
1983+/**
1984+ * wm97xx_set_gpio - Set the status of a codec GPIO.
1985+ * @wm: wm97xx device.
1986+ * @gpio: gpio
1987+ *
1988+ *
1989+ * Set the status of a codec GPIO pin
1990+ */
1991+
1992+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
1993+ wm97xx_gpio_status_t status)
1994+{
1995+ u16 reg;
1996+
1997+ mutex_lock(&wm->codec_mutex);
1998+ reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
1999+
2000+ if (status & WM97XX_GPIO_HIGH)
2001+ reg |= gpio;
2002+ else
2003+ reg &= ~gpio;
2004+
2005+ if (wm->id == WM9712_ID2)
2006+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
2007+ else
2008+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
2009+ mutex_unlock(&wm->codec_mutex);
2010+}
2011+
2012+/*
2013+ * Codec GPIO pin configuration, this set's pin direction, polarity,
2014+ * stickyness and wake up.
2015+ */
2016+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, wm97xx_gpio_dir_t dir,
2017+ wm97xx_gpio_pol_t pol, wm97xx_gpio_sticky_t sticky,
2018+ wm97xx_gpio_wake_t wake)
2019+{
2020+ u16 reg;
2021+
2022+ mutex_lock(&wm->codec_mutex);
2023+ reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
2024+
2025+ if (pol == WM97XX_GPIO_POL_HIGH)
2026+ reg |= gpio;
2027+ else
2028+ reg &= ~gpio;
2029+
2030+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg);
2031+ reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
2032+
2033+ if (sticky == WM97XX_GPIO_STICKY)
2034+ reg |= gpio;
2035+ else
2036+ reg &= ~gpio;
2037+
2038+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg);
2039+ reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
2040+
2041+ if (wake == WM97XX_GPIO_WAKE)
2042+ reg |= gpio;
2043+ else
2044+ reg &= ~gpio;
2045+
2046+ wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg);
2047+ reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
2048+
2049+ if (dir == WM97XX_GPIO_IN)
2050+ reg |= gpio;
2051+ else
2052+ reg &= ~gpio;
2053+
2054+ wm97xx_reg_write(wm, AC97_GPIO_CFG, reg);
2055+ mutex_unlock(&wm->codec_mutex);
2056+}
2057+
2058+/*
2059+ * Handle a pen down interrupt.
2060+ */
2061+static void wm97xx_pen_irq_worker(void *ptr)
2062+{
2063+ struct wm97xx *wm = (struct wm97xx *) ptr;
2064+
2065+ /* do we need to enable the touch panel reader */
2066+ if (wm->id == WM9705_ID2) {
2067+ if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN)
2068+ wm->pen_is_down = 1;
2069+ else
2070+ wm->pen_is_down = 0;
2071+ wake_up_interruptible(&wm->pen_irq_wait);
2072+ } else {
2073+ u16 status, pol;
2074+ mutex_lock(&wm->codec_mutex);
2075+ status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
2076+ pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
2077+
2078+ if (WM97XX_GPIO_13 & pol & status) {
2079+ wm->pen_is_down = 1;
2080+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol & ~WM97XX_GPIO_13);
2081+ } else {
2082+ wm->pen_is_down = 0;
2083+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol | WM97XX_GPIO_13);
2084+ }
2085+
2086+ if (wm->id == WM9712_ID2)
2087+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & ~WM97XX_GPIO_13) << 1);
2088+ else
2089+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, status & ~WM97XX_GPIO_13);
2090+ mutex_unlock(&wm->codec_mutex);
2091+ wake_up_interruptible(&wm->pen_irq_wait);
2092+ }
2093+
2094+ if (!wm->pen_is_down && wm->mach_ops && wm->mach_ops->acc_enabled)
2095+ wm->mach_ops->acc_pen_up(wm);
2096+ enable_irq(wm->pen_irq);
2097+}
2098+
2099+/*
2100+ * Codec PENDOWN irq handler
2101+ *
2102+ * We have to disable the codec interrupt in the handler because it can
2103+ * take upto 1ms to clear the interrupt source. The interrupt is then enabled
2104+ * again in the slow handler when the source has been cleared.
2105+ */
2106+static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id,
2107+ struct pt_regs *regs)
2108+{
2109+ struct wm97xx *wm = (struct wm97xx *) dev_id;
2110+ disable_irq(wm->pen_irq);
2111+ queue_work(wm->pen_irq_workq, &wm->pen_event_work);
2112+ return IRQ_HANDLED;
2113+}
2114+
2115+/*
2116+ * initialise pen IRQ handler and workqueue
2117+ */
2118+static int wm97xx_init_pen_irq(struct wm97xx *wm)
2119+{
2120+ u16 reg;
2121+
2122+ INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker, wm);
2123+ if ((wm->pen_irq_workq =
2124+ create_singlethread_workqueue("kwm97pen")) == NULL) {
2125+ err("could not create pen irq work queue");
2126+ wm->pen_irq = 0;
2127+ return -EINVAL;
2128+ }
2129+
2130+ if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, SA_SHIRQ, "wm97xx-pen", wm)) {
2131+ err("could not register codec pen down interrupt, will poll for pen down");
2132+ destroy_workqueue(wm->pen_irq_workq);
2133+ wm->pen_irq = 0;
2134+ return -EINVAL;
2135+ }
2136+
2137+ /* enable PEN down on wm9712/13 */
2138+ if (wm->id != WM9705_ID2) {
2139+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
2140+ wm97xx_reg_write(wm, AC97_MISC_AFE, reg & 0xfffb);
2141+ reg = wm97xx_reg_read(wm, 0x5a);
2142+ wm97xx_reg_write(wm, 0x5a, reg & ~0x0001);
2143+ }
2144+
2145+ return 0;
2146+}
2147+
2148+/* Private struct for communication between struct wm97xx_tshread
2149+ * and wm97xx_read_samples */
2150+struct ts_state {
2151+ int sleep_time;
2152+ int min_sleep_time;
2153+};
2154+
2155+static int wm97xx_read_samples(struct wm97xx *wm, struct ts_state *state)
2156+{
2157+ struct wm97xx_data data;
2158+ int rc;
2159+
2160+ mutex_lock(&wm->codec_mutex);
2161+
2162+ if (wm->mach_ops && wm->mach_ops->acc_enabled)
2163+ rc = wm->mach_ops->acc_pen_down(wm);
2164+ else
2165+ rc = wm->codec->poll_touch(wm, &data);
2166+
2167+ if (rc & RC_PENUP) {
2168+ if (wm->pen_is_down) {
2169+ wm->pen_is_down = 0;
2170+ dbg("pen up");
2171+ input_report_abs(wm->input_dev, ABS_PRESSURE, 0);
2172+ input_sync(wm->input_dev);
2173+ } else if (!(rc & RC_AGAIN)) {
2174+ /* We need high frequency updates only while pen is down,
2175+ * the user never will be able to touch screen faster than
2176+ * a few times per second... On the other hand, when the
2177+ * user is actively working with the touchscreen we don't
2178+ * want to lose the quick response. So we will slowly
2179+ * increase sleep time after the pen is up and quicky
2180+ * restore it to ~one task switch when pen is down again.
2181+ */
2182+ if (state->sleep_time < HZ / 10)
2183+ state->sleep_time++;
2184+ }
2185+
2186+ } else if (rc & RC_VALID) {
2187+ dbg("pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
2188+ data.x >> 12, data.x & 0xfff, data.y >> 12,
2189+ data.y & 0xfff, data.p >> 12, data.p & 0xfff);
2190+ input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
2191+ input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
2192+ input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
2193+ input_sync(wm->input_dev);
2194+ wm->pen_is_down = 1;
2195+ state->sleep_time = state->min_sleep_time;
2196+ } else if (rc & RC_PENDOWN) {
2197+ dbg("pen down");
2198+ wm->pen_is_down = 1;
2199+ state->sleep_time = state->min_sleep_time;
2200+ }
2201+
2202+ mutex_unlock(&wm->codec_mutex);
2203+ return rc;
2204+}
2205+
2206+/*
2207+* The touchscreen sample reader thread.
2208+*/
2209+static int wm97xx_ts_read(void *data)
2210+{
2211+ int rc;
2212+ struct ts_state state;
2213+ struct wm97xx *wm = (struct wm97xx *) data;
2214+
2215+ /* set up thread context */
2216+ wm->ts_task = current;
2217+ daemonize("kwm97xxts");
2218+
2219+ if (wm->codec == NULL) {
2220+ wm->ts_task = NULL;
2221+ printk(KERN_ERR "codec is NULL, bailing\n");
2222+ }
2223+
2224+ complete(&wm->ts_init);
2225+ wm->pen_is_down = 0;
2226+ state.min_sleep_time = HZ >= 100 ? HZ / 100 : 1;
2227+ if (state.min_sleep_time < 1)
2228+ state.min_sleep_time = 1;
2229+ state.sleep_time = state.min_sleep_time;
2230+
2231+ /* touch reader loop */
2232+ while (wm->ts_task) {
2233+ do {
2234+ try_to_freeze();
2235+ rc = wm97xx_read_samples(wm, &state);
2236+ } while (rc & RC_AGAIN);
2237+ if (!wm->pen_is_down && wm->pen_irq) {
2238+ /* Nice, we don't have to poll for pen down event */
2239+ wait_event_interruptible(wm->pen_irq_wait, wm->pen_is_down);
2240+ } else {
2241+ set_task_state(current, TASK_INTERRUPTIBLE);
2242+ schedule_timeout(state.sleep_time);
2243+ }
2244+ }
2245+ complete_and_exit(&wm->ts_exit, 0);
2246+}
2247+
2248+/**
2249+ * wm97xx_ts_input_open - Open the touch screen input device.
2250+ * @idev: Input device to be opened.
2251+ *
2252+ * Called by the input sub system to open a wm97xx touchscreen device.
2253+ * Starts the touchscreen thread and touch digitiser.
2254+ */
2255+static int wm97xx_ts_input_open(struct input_dev *idev)
2256+{
2257+ int ret = 0;
2258+ struct wm97xx *wm = (struct wm97xx *) idev->private;
2259+
2260+ mutex_lock(&wm->codec_mutex);
2261+ /* first time opened ? */
2262+ if (wm->ts_use_count++ == 0) {
2263+ /* start touchscreen thread */
2264+ init_completion(&wm->ts_init);
2265+ init_completion(&wm->ts_exit);
2266+ ret = kernel_thread(wm97xx_ts_read, wm, CLONE_KERNEL);
2267+
2268+ if (ret >= 0) {
2269+ wait_for_completion(&wm->ts_init);
2270+ if (wm->ts_task == NULL)
2271+ ret = -EINVAL;
2272+ } else {
2273+ mutex_unlock(&wm->codec_mutex);
2274+ return ret;
2275+ }
2276+
2277+ /* start digitiser */
2278+ if (wm->mach_ops && wm->mach_ops->acc_enabled)
2279+ wm->codec->acc_enable(wm, 1);
2280+ wm->codec->digitiser_ioctl(wm, WM97XX_DIG_START);
2281+
2282+ /* init pen down/up irq handling */
2283+ if (wm->pen_irq) {
2284+ wm97xx_init_pen_irq(wm);
2285+
2286+ if (wm->pen_irq == 0) {
2287+ /* we failed to get an irq for pen down events,
2288+ * so we resort to polling. kickstart the reader */
2289+ wm->pen_is_down = 1;
2290+ wake_up_interruptible(&wm->pen_irq_wait);
2291+ }
2292+ }
2293+ }
2294+
2295+ mutex_unlock(&wm->codec_mutex);
2296+ return 0;
2297+}
2298+
2299+/**
2300+ * wm97xx_ts_input_close - Close the touch screen input device.
2301+ * @idev: Input device to be closed.
2302+ *
2303+ * Called by the input sub system to close a wm97xx touchscreen device.
2304+ * Kills the touchscreen thread and stops the touch digitiser.
2305+ */
2306+
2307+static void wm97xx_ts_input_close(struct input_dev *idev)
2308+{
2309+ struct wm97xx *wm = (struct wm97xx *) idev->private;
2310+
2311+ mutex_lock(&wm->codec_mutex);
2312+ if (--wm->ts_use_count == 0) {
2313+ /* destroy workqueues and free irqs */
2314+ if (wm->pen_irq) {
2315+ free_irq(wm->pen_irq, wm);
2316+ destroy_workqueue(wm->pen_irq_workq);
2317+ }
2318+
2319+ /* kill thread */
2320+ if (wm->ts_task) {
2321+ wm->ts_task = NULL;
2322+ wm->pen_is_down = 1;
2323+ wake_up_interruptible(&wm->pen_irq_wait);
2324+ wait_for_completion(&wm->ts_exit);
2325+ wm->pen_is_down = 0;
2326+ }
2327+
2328+ /* stop digitiser */
2329+ wm->codec->digitiser_ioctl(wm, WM97XX_DIG_STOP);
2330+ if (wm->mach_ops && wm->mach_ops->acc_enabled)
2331+ wm->codec->acc_enable(wm, 0);
2332+ }
2333+ mutex_unlock(&wm->codec_mutex);
2334+}
2335+
2336+static int wm97xx_bus_match(struct device *dev, struct device_driver *drv)
2337+{
2338+ return !(strcmp(dev->bus_id,drv->name));
2339+}
2340+
2341+/*
2342+ * The AC97 audio driver will do all the Codec suspend and resume
2343+ * tasks. This is just for anything machine specific or extra.
2344+ */
2345+static int wm97xx_bus_suspend(struct device *dev, pm_message_t state)
2346+{
2347+ int ret = 0;
2348+
2349+ if (dev->driver && dev->driver->suspend)
2350+ ret = dev->driver->suspend(dev, state);
2351+
2352+ return ret;
2353+}
2354+
2355+static int wm97xx_bus_resume(struct device *dev)
2356+{
2357+ int ret = 0;
2358+
2359+ if (dev->driver && dev->driver->resume)
2360+ ret = dev->driver->resume(dev);
2361+
2362+ return ret;
2363+}
2364+
2365+struct bus_type wm97xx_bus_type = {
2366+ .name = "wm97xx",
2367+ .match = wm97xx_bus_match,
2368+ .suspend = wm97xx_bus_suspend,
2369+ .resume = wm97xx_bus_resume,
2370+};
2371+
2372+static void wm97xx_release(struct device *dev)
2373+{
2374+ kfree(dev);
2375+}
2376+
2377+static int wm97xx_probe(struct device *dev)
2378+{
2379+ struct wm97xx* wm;
2380+ int ret = 0, id = 0;
2381+
2382+ if (!(wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL)))
2383+ return -ENOMEM;
2384+ mutex_init(&wm->codec_mutex);
2385+
2386+ init_waitqueue_head(&wm->pen_irq_wait);
2387+ wm->dev = dev;
2388+ dev->driver_data = wm;
2389+ wm->ac97 = to_ac97_t(dev);
2390+
2391+ /* check that we have a supported codec */
2392+ if ((id = wm97xx_reg_read(wm, AC97_VENDOR_ID1)) != WM97XX_ID1) {
2393+ err("could not find a wm97xx, found a %x instead\n", id);
2394+ kfree(wm);
2395+ return -ENODEV;
2396+ }
2397+
2398+ wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
2399+ if(wm->id != wm97xx_codec.id) {
2400+ err("could not find a the selected codec, please build for wm97%2x", wm->id & 0xff);
2401+ kfree(wm);
2402+ return -ENODEV;
2403+ }
2404+
2405+ if((wm->input_dev = input_allocate_device()) == NULL) {
2406+ kfree(wm);
2407+ return -ENOMEM;
2408+ }
2409+
2410+ /* set up touch configuration */
2411+ info("detected a wm97%2x codec", wm->id & 0xff);
2412+ wm->input_dev->name = "wm97xx touchscreen";
2413+ wm->input_dev->open = wm97xx_ts_input_open;
2414+ wm->input_dev->close = wm97xx_ts_input_close;
2415+ set_bit(EV_ABS, wm->input_dev->evbit);
2416+ set_bit(ABS_X, wm->input_dev->absbit);
2417+ set_bit(ABS_Y, wm->input_dev->absbit);
2418+ set_bit(ABS_PRESSURE, wm->input_dev->absbit);
2419+ wm->input_dev->absmax[ABS_X] = abs_x[1];
2420+ wm->input_dev->absmax[ABS_Y] = abs_y[1];
2421+ wm->input_dev->absmax[ABS_PRESSURE] = abs_p[1];
2422+ wm->input_dev->absmin[ABS_X] = abs_x[0];
2423+ wm->input_dev->absmin[ABS_Y] = abs_y[0];
2424+ wm->input_dev->absmin[ABS_PRESSURE] = abs_p[0];
2425+ wm->input_dev->absfuzz[ABS_X] = abs_x[2];
2426+ wm->input_dev->absfuzz[ABS_Y] = abs_y[2];
2427+ wm->input_dev->absfuzz[ABS_PRESSURE] = abs_p[2];
2428+ wm->input_dev->private = wm;
2429+ wm->codec = &wm97xx_codec;
2430+ if((ret = input_register_device(wm->input_dev)) < 0) {
2431+ kfree(wm);
2432+ return -ENOMEM;
2433+ }
2434+
2435+ if(aux_sys)
2436+ wm97xx_sys_add(dev);
2437+
2438+ /* set up physical characteristics */
2439+ wm->codec->digitiser_ioctl(wm, WM97XX_PHY_INIT);
2440+
2441+ /* load gpio cache */
2442+ wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
2443+ wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
2444+ wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
2445+ wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
2446+ wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
2447+ wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
2448+
2449+ /* register our battery device */
2450+ if (!(wm->battery_dev = kzalloc(sizeof(struct device), GFP_KERNEL))) {
2451+ ret = -ENOMEM;
2452+ goto batt_err;
2453+ }
2454+ wm->battery_dev->bus = &wm97xx_bus_type;
2455+ strcpy(wm->battery_dev->bus_id,"wm97xx-battery");
2456+ wm->battery_dev->driver_data = wm;
2457+ wm->battery_dev->parent = dev;
2458+ wm->battery_dev->release = wm97xx_release;
2459+ if((ret = device_register(wm->battery_dev)) < 0)
2460+ goto batt_reg_err;
2461+
2462+ /* register our extended touch device (for machine specific extensions) */
2463+ if (!(wm->touch_dev = kzalloc(sizeof(struct device), GFP_KERNEL))) {
2464+ ret = -ENOMEM;
2465+ goto touch_err;
2466+ }
2467+ wm->touch_dev->bus = &wm97xx_bus_type;
2468+ strcpy(wm->touch_dev->bus_id,"wm97xx-touchscreen");
2469+ wm->touch_dev->driver_data = wm;
2470+ wm->touch_dev->parent = dev;
2471+ wm->touch_dev->release = wm97xx_release;
2472+ if((ret = device_register(wm->touch_dev)) < 0)
2473+ goto touch_reg_err;
2474+
2475+ return ret;
2476+
2477+touch_reg_err:
2478+ kfree(wm->touch_dev);
2479+touch_err:
2480+ device_unregister(wm->battery_dev);
2481+batt_reg_err:
2482+ kfree(wm->battery_dev);
2483+batt_err:
2484+ input_unregister_device(wm->input_dev);
2485+ kfree(wm);
2486+ return ret;
2487+}
2488+
2489+static int wm97xx_remove(struct device *dev)
2490+{
2491+ struct wm97xx *wm = dev_get_drvdata(dev);
2492+
2493+ /* Stop touch reader thread */
2494+ if (wm->ts_task) {
2495+ wm->ts_task = NULL;
2496+ wm->pen_is_down = 1;
2497+ wake_up_interruptible(&wm->pen_irq_wait);
2498+ wait_for_completion(&wm->ts_exit);
2499+ }
2500+ device_unregister(wm->battery_dev);
2501+ device_unregister(wm->touch_dev);
2502+ input_unregister_device(wm->input_dev);
2503+
2504+ if(aux_sys)
2505+ wm97xx_sys_remove(dev);
2506+
2507+ kfree(wm);
2508+ return 0;
2509+}
2510+
2511+#ifdef CONFIG_PM
2512+int wm97xx_resume(struct device* dev)
2513+{
2514+ struct wm97xx *wm = dev_get_drvdata(dev);
2515+
2516+ /* restore digitiser and gpio's */
2517+ if(wm->id == WM9713_ID2) {
2518+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
2519+ wm97xx_reg_write(wm, 0x5a, wm->misc);
2520+ if(wm->ts_use_count) {
2521+ u16 reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff;
2522+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
2523+ }
2524+ }
2525+
2526+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]);
2527+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]);
2528+
2529+ wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]);
2530+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]);
2531+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]);
2532+ wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]);
2533+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]);
2534+ wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]);
2535+
2536+ return 0;
2537+}
2538+
2539+#else
2540+#define wm97xx_resume NULL
2541+#endif
2542+
2543+int wm97xx_register_mach_ops(struct wm97xx *wm, struct wm97xx_mach_ops *mach_ops)
2544+{
2545+ mutex_lock(&wm->codec_mutex);
2546+ if(wm->mach_ops) {
2547+ mutex_unlock(&wm->codec_mutex);
2548+ return -EINVAL;
2549+ }
2550+ wm->mach_ops = mach_ops;
2551+ mutex_unlock(&wm->codec_mutex);
2552+ return 0;
2553+}
2554+
2555+void wm97xx_unregister_mach_ops(struct wm97xx *wm)
2556+{
2557+ mutex_lock(&wm->codec_mutex);
2558+ wm->mach_ops = NULL;
2559+ mutex_unlock(&wm->codec_mutex);
2560+}
2561+
2562+static struct device_driver wm97xx_driver = {
2563+ .name = "ac97",
2564+ .bus = &ac97_bus_type,
2565+ .owner = THIS_MODULE,
2566+ .probe = wm97xx_probe,
2567+ .remove = wm97xx_remove,
2568+ .resume = wm97xx_resume,
2569+};
2570+
2571+static int __init wm97xx_init(void)
2572+{
2573+ int ret;
2574+
2575+ info("version %s liam.girdwood@wolfsonmicro.com", WM_CORE_VERSION);
2576+ if((ret = bus_register(&wm97xx_bus_type)) < 0)
2577+ return ret;
2578+ return driver_register(&wm97xx_driver);
2579+}
2580+
2581+static void __exit wm97xx_exit(void)
2582+{
2583+ driver_unregister(&wm97xx_driver);
2584+ bus_unregister(&wm97xx_bus_type);
2585+}
2586+
2587+EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
2588+EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
2589+EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
2590+EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
2591+EXPORT_SYMBOL_GPL(wm97xx_reg_read);
2592+EXPORT_SYMBOL_GPL(wm97xx_reg_write);
2593+EXPORT_SYMBOL_GPL(wm97xx_bus_type);
2594+EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops);
2595+EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
2596+
2597+module_init(wm97xx_init);
2598+module_exit(wm97xx_exit);
2599+
2600+/* Module information */
2601+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
2602+MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
2603+MODULE_LICENSE("GPL");
2604Index: linux-2.6.17/include/linux/wm97xx.h
2605===================================================================
2606--- /dev/null 1970-01-01 00:00:00.000000000 +0000
2607+++ linux-2.6.17/include/linux/wm97xx.h 2006-09-19 20:36:47.973052250 +0200
2608@@ -0,0 +1,291 @@
2609+
2610+/*
2611+ * Register bits and API for Wolfson WM97xx series of codecs
2612+ */
2613+
2614+#ifndef _LINUX_WM97XX_H
2615+#define _LINUX_WM97XX_H
2616+
2617+#include <sound/driver.h>
2618+#include <sound/core.h>
2619+#include <sound/pcm.h>
2620+#include <sound/ac97_codec.h>
2621+#include <sound/initval.h>
2622+#include <linux/types.h>
2623+#include <linux/list.h>
2624+#include <linux/input.h> /* Input device layer */
2625+
2626+/*
2627+ * WM97xx AC97 Touchscreen registers
2628+ */
2629+#define AC97_WM97XX_DIGITISER1 0x76
2630+#define AC97_WM97XX_DIGITISER2 0x78
2631+#define AC97_WM97XX_DIGITISER_RD 0x7a
2632+#define AC97_WM9713_DIG1 0x74
2633+#define AC97_WM9713_DIG2 AC97_WM97XX_DIGITISER1
2634+#define AC97_WM9713_DIG3 AC97_WM97XX_DIGITISER2
2635+
2636+/*
2637+ * WM97xx register bits
2638+ */
2639+#define WM97XX_POLL 0x8000 /* initiate a polling measurement */
2640+#define WM97XX_ADCSEL_X 0x1000 /* x coord measurement */
2641+#define WM97XX_ADCSEL_Y 0x2000 /* y coord measurement */
2642+#define WM97XX_ADCSEL_PRES 0x3000 /* pressure measurement */
2643+#define WM97XX_ADCSEL_MASK 0x7000
2644+#define WM97XX_COO 0x0800 /* enable coordinate mode */
2645+#define WM97XX_CTC 0x0400 /* enable continuous mode */
2646+#define WM97XX_CM_RATE_93 0x0000 /* 93.75Hz continuous rate */
2647+#define WM97XX_CM_RATE_187 0x0100 /* 187.5Hz continuous rate */
2648+#define WM97XX_CM_RATE_375 0x0200 /* 375Hz continuous rate */
2649+#define WM97XX_CM_RATE_750 0x0300 /* 750Hz continuous rate */
2650+#define WM97XX_CM_RATE_8K 0x00f0 /* 8kHz continuous rate */
2651+#define WM97XX_CM_RATE_12K 0x01f0 /* 12kHz continuous rate */
2652+#define WM97XX_CM_RATE_24K 0x02f0 /* 24kHz continuous rate */
2653+#define WM97XX_CM_RATE_48K 0x03f0 /* 48kHz continuous rate */
2654+#define WM97XX_CM_RATE_MASK 0x03f0
2655+#define WM97XX_RATE(i) (((i & 3) << 8) | ((i & 4) ? 0xf0 : 0))
2656+#define WM97XX_DELAY(i) ((i << 4) & 0x00f0) /* sample delay times */
2657+#define WM97XX_DELAY_MASK 0x00f0
2658+#define WM97XX_SLEN 0x0008 /* slot read back enable */
2659+#define WM97XX_SLT(i) ((i - 5) & 0x7) /* touchpanel slot selection (5-11) */
2660+#define WM97XX_SLT_MASK 0x0007
2661+#define WM97XX_PRP_DETW 0x4000 /* pen detect on, digitiser off, wake up */
2662+#define WM97XX_PRP_DET 0x8000 /* pen detect on, digitiser off, no wake up */
2663+#define WM97XX_PRP_DET_DIG 0xc000 /* pen detect on, digitiser on */
2664+#define WM97XX_RPR 0x2000 /* wake up on pen down */
2665+#define WM97XX_PEN_DOWN 0x8000 /* pen is down */
2666+#define WM97XX_ADCSRC_MASK 0x7000 /* ADC source mask */
2667+
2668+#define WM97XX_AUX_ID1 0x8001
2669+#define WM97XX_AUX_ID2 0x8002
2670+#define WM97XX_AUX_ID3 0x8003
2671+#define WM97XX_AUX_ID4 0x8004
2672+
2673+
2674+/* WM9712 Bits */
2675+#define WM9712_45W 0x1000 /* set for 5-wire touchscreen */
2676+#define WM9712_PDEN 0x0800 /* measure only when pen down */
2677+#define WM9712_WAIT 0x0200 /* wait until adc is read before next sample */
2678+#define WM9712_PIL 0x0100 /* current used for pressure measurement. set 400uA else 200uA */
2679+#define WM9712_MASK_HI 0x0040 /* hi on mask pin (47) stops conversions */
2680+#define WM9712_MASK_EDGE 0x0080 /* rising/falling edge on pin delays sample */
2681+#define WM9712_MASK_SYNC 0x00c0 /* rising/falling edge on mask initiates sample */
2682+#define WM9712_RPU(i) (i&0x3f) /* internal pull up on pen detect (64k / rpu) */
2683+#define WM9712_PD(i) (0x1 << i) /* power management */
2684+
2685+/* WM9712 Registers */
2686+#define AC97_WM9712_POWER 0x24
2687+#define AC97_WM9712_REV 0x58
2688+
2689+/* WM9705 Bits */
2690+#define WM9705_PDEN 0x1000 /* measure only when pen is down */
2691+#define WM9705_PINV 0x0800 /* inverts sense of pen down output */
2692+#define WM9705_BSEN 0x0400 /* BUSY flag enable, pin47 is 1 when busy */
2693+#define WM9705_BINV 0x0200 /* invert BUSY (pin47) output */
2694+#define WM9705_WAIT 0x0100 /* wait until adc is read before next sample */
2695+#define WM9705_PIL 0x0080 /* current used for pressure measurement. set 400uA else 200uA */
2696+#define WM9705_PHIZ 0x0040 /* set PHONE and PCBEEP inputs to high impedance */
2697+#define WM9705_MASK_HI 0x0010 /* hi on mask stops conversions */
2698+#define WM9705_MASK_EDGE 0x0020 /* rising/falling edge on pin delays sample */
2699+#define WM9705_MASK_SYNC 0x0030 /* rising/falling edge on mask initiates sample */
2700+#define WM9705_PDD(i) (i & 0x000f) /* pen detect comparator threshold */
2701+
2702+
2703+/* WM9713 Bits */
2704+#define WM9713_PDPOL 0x0400 /* Pen down polarity */
2705+#define WM9713_POLL 0x0200 /* initiate a polling measurement */
2706+#define WM9713_CTC 0x0100 /* enable continuous mode */
2707+#define WM9713_ADCSEL_X 0x0002 /* X measurement */
2708+#define WM9713_ADCSEL_Y 0x0004 /* Y measurement */
2709+#define WM9713_ADCSEL_PRES 0x0008 /* Pressure measurement */
2710+#define WM9713_COO 0x0001 /* enable coordinate mode */
2711+#define WM9713_PDEN 0x0800 /* measure only when pen down */
2712+#define WM9713_ADCSEL_MASK 0x00fe /* ADC selection mask */
2713+#define WM9713_WAIT 0x0200 /* coordinate wait */
2714+
2715+/* AUX ADC ID's */
2716+#define TS_COMP1 0x0
2717+#define TS_COMP2 0x1
2718+#define TS_BMON 0x2
2719+#define TS_WIPER 0x3
2720+
2721+/* ID numbers */
2722+#define WM97XX_ID1 0x574d
2723+#define WM9712_ID2 0x4c12
2724+#define WM9705_ID2 0x4c05
2725+#define WM9713_ID2 0x4c13
2726+
2727+/* Codec GPIO's */
2728+#define WM97XX_MAX_GPIO 16
2729+#define WM97XX_GPIO_1 (1 << 1)
2730+#define WM97XX_GPIO_2 (1 << 2)
2731+#define WM97XX_GPIO_3 (1 << 3)
2732+#define WM97XX_GPIO_4 (1 << 4)
2733+#define WM97XX_GPIO_5 (1 << 5)
2734+#define WM97XX_GPIO_6 (1 << 6)
2735+#define WM97XX_GPIO_7 (1 << 7)
2736+#define WM97XX_GPIO_8 (1 << 8)
2737+#define WM97XX_GPIO_9 (1 << 9)
2738+#define WM97XX_GPIO_10 (1 << 10)
2739+#define WM97XX_GPIO_11 (1 << 11)
2740+#define WM97XX_GPIO_12 (1 << 12)
2741+#define WM97XX_GPIO_13 (1 << 13)
2742+#define WM97XX_GPIO_14 (1 << 14)
2743+#define WM97XX_GPIO_15 (1 << 15)
2744+
2745+
2746+#define AC97_LINK_FRAME 21 /* time in uS for AC97 link frame */
2747+
2748+
2749+/*---------------- Return codes from sample reading functions ---------------*/
2750+
2751+/* More data is available; call the sample gathering function again */
2752+#define RC_AGAIN 0x00000001
2753+/* The returned sample is valid */
2754+#define RC_VALID 0x00000002
2755+/* The pen is up (the first RC_VALID without RC_PENUP means pen is down) */
2756+#define RC_PENUP 0x00000004
2757+/* The pen is down (RC_VALID implies RC_PENDOWN, but sometimes it is helpful
2758+ to tell the handler that the pen is down but we don't know yet his coords,
2759+ so the handler should not sleep or wait for pendown irq) */
2760+#define RC_PENDOWN 0x00000008
2761+
2762+/* The wm97xx driver provides a private API for writing platform-specific
2763+ * drivers.
2764+ */
2765+
2766+/* The structure used to return arch specific sampled data into */
2767+struct wm97xx_data {
2768+ int x;
2769+ int y;
2770+ int p;
2771+};
2772+
2773+/* Codec GPIO status
2774+ */
2775+typedef enum {
2776+ WM97XX_GPIO_HIGH,
2777+ WM97XX_GPIO_LOW
2778+} wm97xx_gpio_status_t;
2779+
2780+/* Codec GPIO direction
2781+ */
2782+typedef enum {
2783+ WM97XX_GPIO_IN,
2784+ WM97XX_GPIO_OUT
2785+} wm97xx_gpio_dir_t;
2786+
2787+/* Codec GPIO polarity
2788+ */
2789+typedef enum {
2790+ WM97XX_GPIO_POL_HIGH,
2791+ WM97XX_GPIO_POL_LOW
2792+} wm97xx_gpio_pol_t;
2793+
2794+/* Codec GPIO sticky
2795+ */
2796+typedef enum {
2797+ WM97XX_GPIO_STICKY,
2798+ WM97XX_GPIO_NOTSTICKY
2799+} wm97xx_gpio_sticky_t;
2800+
2801+/* Codec GPIO wake
2802+ */
2803+typedef enum {
2804+ WM97XX_GPIO_WAKE,
2805+ WM97XX_GPIO_NOWAKE
2806+} wm97xx_gpio_wake_t;
2807+
2808+
2809+/*
2810+ * Digitiser ioctl commands
2811+ */
2812+#define WM97XX_DIG_START 0x1
2813+#define WM97XX_DIG_STOP 0x2
2814+#define WM97XX_PHY_INIT 0x3
2815+#define WM97XX_AUX_PREPARE 0x4
2816+#define WM97XX_DIG_RESTORE 0x5
2817+
2818+struct wm97xx;
2819+extern struct wm97xx_codec_drv wm97xx_codec;
2820+
2821+/*
2822+ * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
2823+ */
2824+struct wm97xx_codec_drv {
2825+ u16 id;
2826+ char *name;
2827+ int (*poll_sample) (struct wm97xx *, int adcsel, int *sample); /* read 1 sample */
2828+ int (*poll_touch) (struct wm97xx *, struct wm97xx_data *); /* read X,Y,[P] in poll */
2829+ int (*digitiser_ioctl) (struct wm97xx *, int cmd);
2830+ int (*acc_enable) (struct wm97xx *, int enable);
2831+};
2832+
2833+
2834+/* Machine specific and accelerated touch operations */
2835+struct wm97xx_mach_ops {
2836+
2837+ /* accelerated touch readback - coords are transmited on AC97 link */
2838+ int acc_enabled;
2839+ void (*acc_pen_up) (struct wm97xx *);
2840+ int (*acc_pen_down) (struct wm97xx *);
2841+ int (*acc_startup) (struct wm97xx *);
2842+ void (*acc_shutdown) (struct wm97xx *);
2843+
2844+ /* pre and post sample - can be used to minimise any analog noise */
2845+ void (*pre_sample) (int); /* function to run before sampling */
2846+ void (*post_sample) (int); /* function to run after sampling */
2847+};
2848+
2849+struct wm97xx {
2850+ u16 dig[3], id, gpio[6], misc; /* Cached codec registers */
2851+ u16 dig_save[3]; /* saved during aux reading */
2852+ struct wm97xx_codec_drv *codec; /* attached codec driver*/
2853+ struct input_dev* input_dev; /* touchscreen input device */
2854+ ac97_t *ac97; /* ALSA codec access */
2855+ struct device *dev; /* ALSA device */
2856+ struct device *battery_dev;
2857+ struct device *touch_dev;
2858+ struct wm97xx_mach_ops *mach_ops;
2859+ struct mutex codec_mutex;
2860+ struct completion ts_init;
2861+ struct completion ts_exit;
2862+ struct task_struct *ts_task;
2863+ unsigned int pen_irq; /* Pen IRQ number in use */
2864+ wait_queue_head_t pen_irq_wait; /* Pen IRQ wait queue */
2865+ struct workqueue_struct *pen_irq_workq;
2866+ struct work_struct pen_event_work;
2867+ u16 acc_slot; /* AC97 slot used for acc touch data */
2868+ u16 acc_rate; /* acc touch data rate */
2869+ unsigned int ts_use_count;
2870+ unsigned pen_is_down:1; /* Pen is down */
2871+ unsigned aux_waiting:1; /* aux measurement waiting */
2872+ unsigned pen_probably_down:1; /* used in polling mode */
2873+};
2874+
2875+/* Codec GPIO access (not supported on WM9705)
2876+ * This can be used to set/get codec GPIO and Virtual GPIO status.
2877+ */
2878+wm97xx_gpio_status_t wm97xx_get_gpio(struct wm97xx *wm, u32 gpio);
2879+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
2880+ wm97xx_gpio_status_t status);
2881+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio,
2882+ wm97xx_gpio_dir_t dir,
2883+ wm97xx_gpio_pol_t pol,
2884+ wm97xx_gpio_sticky_t sticky,
2885+ wm97xx_gpio_wake_t wake);
2886+
2887+/* codec AC97 IO access */
2888+int wm97xx_reg_read(struct wm97xx *wm, u16 reg);
2889+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val);
2890+
2891+/* aux adc readback */
2892+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel);
2893+
2894+/* machine ops */
2895+int wm97xx_register_mach_ops(struct wm97xx *, struct wm97xx_mach_ops *);
2896+void wm97xx_unregister_mach_ops(struct wm97xx *);
2897+
2898+extern struct bus_type wm97xx_bus_type;
2899+#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 @@
1require linux-rp.inc 1require linux-rp.inc
2 2
3PR = "r2" 3PR = "r4"
4 4
5DEFAULT_PREFERENCE = "-1" 5DEFAULT_PREFERENCE = "-1"
6 6
@@ -17,43 +17,44 @@ DEFAULT_PREFERENCE = "-1"
17# Hacks should clearly named and at the bottom 17# Hacks should clearly named and at the bottom
18SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \ 18SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
19 ${KERNELORG_MIRROR}pub/linux/kernel/v2.6/testing/patch-2.6.24-rc8.bz2;patch=1 \ 19 ${KERNELORG_MIRROR}pub/linux/kernel/v2.6/testing/patch-2.6.24-rc8.bz2;patch=1 \
20 ${RPSRC}/lzo_crypto-r2.patch;patch=1 \ 20 ${RPSRC}/export_atags-r2.patch;patch=1;status=pending \
21 ${RPSRC}/lzo_crypto-r2.patch;patch=1;status=pending \
22 ${RPSRC}/corgi_rearrange_lcd-r0.patch;patch=1;status=pending \
21 ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \ 23 ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \
22 file://hx2750_base-r31.patch;patch=1 \ 24 ${RPSRC}/hx2750_base-r31.patch;patch=1 \
23 ${RPSRC}/hx2750_bl-r9.patch;patch=1 \ 25 ${RPSRC}/hx2750_bl-r9.patch;patch=1 \
24 ${RPSRC}/hx2750_pcmcia-r3.patch;patch=1 \ 26 ${RPSRC}/hx2750_pcmcia-r3.patch;patch=1 \
25 ${RPSRC}/pxa_keys-r8.patch;patch=1 \ 27 ${RPSRC}/pxa_keys-r8.patch;patch=1 \
26# ${RPSRC}/tsc2101-r16.patch;patch=1 \ 28 ${RPSRC}/tsc2101-r17.patch;patch=1 \
27 ${RPSRC}/hx2750_test1-r7.patch;patch=1 \ 29 ${RPSRC}/hx2750_test1-r7.patch;patch=1 \
28 ${RPSRC}/input_power-r10.patch;patch=1 \ 30 ${RPSRC}/input_power-r10.patch;patch=1 \
29 ${RPSRC}/input_power_fix-r0.patch;patch=1 \
30 ${RPSRC}/pxa25x_cpufreq-r2.patch;patch=1 \ 31 ${RPSRC}/pxa25x_cpufreq-r2.patch;patch=1 \
31 ${RPSRC}/sharpsl_pm_fixes1-r0.patch;patch=1 \ 32 ${RPSRC}/sharpsl_pm_fixes1-r0.patch;patch=1 \
32 ${RPSRC}/pm_changes-r1.patch;patch=1 \ 33 ${RPSRC}/pm_changes-r1.patch;patch=1 \
33 ${RPSRC}/usb_add_epalloc-r4.patch;patch=1 \ 34 ${RPSRC}/usb_add_epalloc-r4.patch;patch=1 \
34 ${RPSRC}/usb_pxa27x_udc-r7.patch;patch=1 \ 35 ${RPSRC}/usb_pxa27x_udc-r8.patch;patch=1 \
35 ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \ 36 ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \
36 ${RPSRC}/poodle_pm-r5.patch;patch=1 \ 37 ${RPSRC}/pxa27x_overlay-r8.patch;patch=1 \
37 file://pxa27x_overlay-r8.patch;patch=1 \ 38 ${RPSRC}/w100_extaccel-r2.patch;patch=1 \
38 ${RPSRC}/w100_extaccel-r1.patch;patch=1 \
39 ${RPSRC}/w100_extmem-r1.patch;patch=1 \ 39 ${RPSRC}/w100_extmem-r1.patch;patch=1 \
40 ${RPSRC}/export_atags-r1.patch;patch=1 \ 40 ${RPSRC}/poodle_pm-r5.patch;patch=1 \
41 file://w100fb-unused-var.patch;patch=1 \ 41 ${RPSRC}/poodle_lcd_hack-r0.patch;patch=1 \
42 file://hostap-monitor-mode.patch;patch=1 \ 42 ${RPSRC}/poodle_asoc_fix-r1.patch;patch=1 \
43 file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1 \ 43 file://squashfs3.3.patch;patch=1;status=external \
44 ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \ 44 ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \
45 ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \ 45 ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \
46 file://hostap-monitor-mode.patch;patch=1;status=unmergable \
47 file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1;status=unmergable \
46 ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \ 48 ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \
47 file://mmcsd_no_scr_check-r2.patch;patch=1 \ 49 ${RPSRC}/mmcsd_no_scr_check-r2.patch;patch=1;status=hack \
48 ${RPSRC}/integrator_rgb-r1.patch;patch=1;status=hack \ 50 ${RPSRC}/integrator_rgb-r1.patch;patch=1;status=hack \
49 ${RPSRC}/pxa_cf_initorder_hack-r1.patch;patch=1;status=hack \ 51 ${RPSRC}/pxa_cf_initorder_hack-r1.patch;patch=1;status=hack \
50 ${RPSRC}/corgi_rearrange_lcd-r0.patch;patch=1 \
51 file://pxa-serial-hack.patch;patch=1;status=hack \ 52 file://pxa-serial-hack.patch;patch=1;status=hack \
52 file://connectplus-remove-ide-HACK.patch;patch=1;status=hack \ 53 file://connectplus-remove-ide-HACK.patch;patch=1;status=hack \
53# file://squashfs3.2-2.6.20-r0.patch;patch=1;status=external \ 54 file://connectplus-prevent-oops-HACK.patch;patch=1;status=hack \
54# file://htcuni.patch;patch=1 \ 55# file://htcuni.patch;patch=1 \
55 file://binutils-buildid-arm.patch;patch=1 \ 56 file://binutils-buildid-arm.patch;patch=1 \
56 file://versatile-armv6.patch;patch=1 \ 57 file://versatile-armv6.patch;patch=1 \
57 file://defconfig-c7x0 \ 58 file://defconfig-c7x0 \
58 file://defconfig-hx2000 \ 59 file://defconfig-hx2000 \
59 file://defconfig-collie \ 60 file://defconfig-collie \
@@ -84,36 +85,51 @@ SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
84# These patches are extracted from Pavel Machek's git tree 85# These patches are extracted from Pavel Machek's git tree
85# (diff against vanilla kernel) 86# (diff against vanilla kernel)
86SRC_URI_append_collie = "\ 87SRC_URI_append_collie = "\
87 ${DOSRC}/collie/mtd-sharp-flash-hack-r0.patch;patch=1 \ 88 ${TKSRC}/mtd-sharp-flash-hack-r3.patch;patch=1 \
88 ${DOSRC}/collie/collie-r0.patch;patch=1 \ 89 ${TKSRC}/mcp-sa11x0-r0.patch;patch=1 \
89 ${DOSRC}/collie/locomolcd-backlight-r0.patch;patch=1 \ 90 ${TKSRC}/locomo-r0.patch;patch=1 \
90 ${DOSRC}/collie/ucb1x00-touch-audio-r0.patch;patch=1 \ 91# ${TKSRC}/locomo_spi-4.patch;patch=1 \
91 file://collie-mcp-r1.patch;patch=1 \ 92 ${TKSRC}/collie-kexec.patch;patch=1 \
92 ${DOSRC}/collie/sa1100-udc-r0.patch;patch=1 \ 93 ${TKSRC}/sharpsl_pm-3.patch;patch=1 \
93# ${DOSRC}/collie/collie-pm-r1.patch;patch=1 \ 94 ${TKSRC}/collie_pm-2.patch;patch=1 \
95 ${TKSRC}/locomokeyb_suspendkey-2.patch;patch=1 \
96 ${TKSRC}/ucb1x00_suspend.patch;patch=1 \
97 ${TKSRC}/collie-ts.patch;patch=1 \
98 ${TKSRC}/pcmcia_suspend.patch;patch=1 \
99"
100
101SRC_URI_append_poodle = "\
102 ${RPSRC}/poodle_serial_vcc-r0.patch;patch=1 \
94" 103"
95 104
96SRC_URI_append_tosa = "\ 105SRC_URI_append_tosa = "\
97 ${CHSRC}/usb-ohci-hooks-r1.patch;patch=1 \
98 ${CHSRC}/tmio-core-r4.patch;patch=1 \ 106 ${CHSRC}/tmio-core-r4.patch;patch=1 \
99 file://tmio-tc6393-r8.patch;patch=1 \ 107 file://tmio-tc6393-r8.patch;patch=1 \
100 file://tmio-nand-r7.patch;patch=1 \ 108 file://tmio-nand-r8.patch;patch=1 \
101 file://tmio-ohci-r6.patch;patch=1 \
102 ${CHSRC}/tmio-fb-r6.patch;patch=1 \ 109 ${CHSRC}/tmio-fb-r6.patch;patch=1 \
103 file://tosa-keyboard-r18.patch;patch=1 \ 110 file://tmio-fb-r6-fix-r0.patch;patch=1 \
111 file://tosa-keyboard-r19.patch;patch=1 \
104 ${DOSRC}/tosa-pxaac97-r6.patch;patch=1 \ 112 ${DOSRC}/tosa-pxaac97-r6.patch;patch=1 \
113 file://tosa-pxaac97-r6-fix-r0.patch;patch=1 \
105 ${DOSRC}/tosa-tmio-r6.patch;patch=1 \ 114 ${DOSRC}/tosa-tmio-r6.patch;patch=1 \
106 ${DOSRC}/tosa-power-r17.patch;patch=1 \ 115 file://tosa-power-r18.patch;patch=1 \
116 file://tosa-power-r18-fix-r0.patch;patch=1 \
107 file://tosa-tmio-lcd-r10.patch;patch=1 \ 117 file://tosa-tmio-lcd-r10.patch;patch=1 \
108 ${DOSRC}/tosa-bluetooth-r8.patch;patch=1 \ 118 file://tosa-tmio-lcd-r10-fix-r0.patch;patch=1 \
109 ${DOSRC}/wm97xx-lg7-r0.patch;patch=1 \ 119 file://tosa-bluetooth-r8.patch;patch=1 \
120 file://wm97xx-lg13-r0.patch;patch=1 \
121 file://wm97xx-lg13-r0-fix-r0.patch;patch=1 \
110 file://wm9712-suspend-cold-res-r2.patch;patch=1 \ 122 file://wm9712-suspend-cold-res-r2.patch;patch=1 \
111 file://sharpsl-pm-postresume-r1.patch;patch=1 \ 123 file://sharpsl-pm-postresume-r1.patch;patch=1 \
112 ${DOSRC}/wm97xx-dig-restore-r0.patch;patch=1 \
113 ${DOSRC}/wm97xx-miscdevs-resume-r0.patch;patch=1 \
114 file://wm9712-reset-loop-r2.patch;patch=1 \ 124 file://wm9712-reset-loop-r2.patch;patch=1 \
115 file://tosa-lcdnoise-r1.patch;patch=1 \ 125 file://tosa-lcdnoise-r1.patch;patch=1 \
116 file://wm97xx-lcdnoise-r0.patch;patch=1 " 126 file://tosa-lcdnoise-r1-fix-r0.patch;patch=1 \
127 file://arm-dma-coherent.patch;patch=1 \
128 file://usb-ohci-hooks-r3.patch;patch=1 \
129 file://tmio-ohci-r9.patch;patch=1 \
130 file://pxa2xx_udc_support_inverse_vbus.patch;patch=1 \
131 file://tosa_udc_use_gpio_vbus.patch;patch=1 \
132 "
117# ${DOSRC}/tosa-asoc-r1.patch;patch=1 " 133# ${DOSRC}/tosa-asoc-r1.patch;patch=1 "
118 134
119SRC_URI_append_htcuniversal ="\ 135SRC_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 @@
1require linux-rp.inc 1require linux-rp.inc
2 2
3PR = "r25" 3PR = "r26"
4 4
5# Handy URLs 5# Handy URLs
6# git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;protocol=git;tag=ef7d1b244fa6c94fb76d5f787b8629df64ea4046 6# git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;protocol=git;tag=ef7d1b244fa6c94fb76d5f787b8629df64ea4046
@@ -14,10 +14,15 @@ PR = "r25"
14# Patches submitted upstream are towards top of this list 14# Patches submitted upstream are towards top of this list
15# Hacks should clearly named and at the bottom 15# Hacks should clearly named and at the bottom
16SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \ 16SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
17 file://hrw-add-wcf11-to-hostap.patch;patch=1;status=pending \ 17 ${RPSRC}/pxa25x_suspend_fixes-r0.patch;patch=1;status=merged \
18 ${RPSRC}/lzo_jffs2-r3.patch;patch=1 \ 18 ${RPSRC}/lzo_jffs2-r3.patch;patch=1;status=merged \
19 ${RPSRC}/lzo_crypto-r2.patch;patch=1 \ 19 ${RPSRC}/lzo_jffs2_lzomode-r1.patch;patch=1;status=merged \
20 ${RPSRC}/lzo_jffs2_lzomode-r1.patch;patch=1 \ 20 ${RPSRC}/spitzkbd_fix-r0.patch;patch=1;status=merged \
21 file://uvesafb-0.1-rc3-2.6.22.patch;patch=1;status=merged \
22 ${RPSRC}/locomo_led_fix-r0.patch;patch=1;status=merged \
23 file://hrw-add-wcf11-to-hostap.patch;patch=1;status=merged \
24 ${RPSRC}/export_atags-r0a.patch;patch=1;status=pending \
25 ${RPSRC}/lzo_crypto-r2.patch;patch=1;status=pending \
21 ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \ 26 ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \
22 ${RPSRC}/hx2750_base-r29.patch;patch=1 \ 27 ${RPSRC}/hx2750_base-r29.patch;patch=1 \
23 ${RPSRC}/hx2750_bl-r9.patch;patch=1 \ 28 ${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 \
32 ${RPSRC}/usb_add_epalloc-r3.patch;patch=1 \ 37 ${RPSRC}/usb_add_epalloc-r3.patch;patch=1 \
33 ${RPSRC}/usb_pxa27x_udc-r6.patch;patch=1 \ 38 ${RPSRC}/usb_pxa27x_udc-r6.patch;patch=1 \
34 ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \ 39 ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \
35 ${RPSRC}/poodle_pm-r4.patch;patch=1 \
36 ${RPSRC}/pxa27x_overlay-r6.patch;patch=1 \ 40 ${RPSRC}/pxa27x_overlay-r6.patch;patch=1 \
37 ${RPSRC}/w100_extaccel-r1.patch;patch=1 \ 41 ${RPSRC}/w100_extaccel-r2.patch;patch=1 \
38 ${RPSRC}/w100_extmem-r1.patch;patch=1 \ 42 ${RPSRC}/w100_extmem-r1.patch;patch=1 \
39 ${RPSRC}/spitzkbd_fix-r0.patch;patch=1 \ 43 ${RPSRC}/poodle_pm-r4.patch;patch=1 \
40 ${RPSRC}/export_atags-r0.patch;patch=1 \
41 ${RPSRC}/pxa25x_suspend_fixes-r0.patch;patch=1 \
42 ${RPSRC}/poodle_lcd_hack-r0.patch;patch=1 \ 44 ${RPSRC}/poodle_lcd_hack-r0.patch;patch=1 \
43 ${RPSRC}/poodle_asoc_fix-r1.patch;patch=1 \ 45 ${RPSRC}/poodle_asoc_fix-r1.patch;patch=1 \
44 ${RPSRC}/locomo_led_fix-r0.patch;patch=1 \ 46 file://squashfs3.0-2.6.15.patch;patch=1;status=external \
45 file://w100fb-unused-var.patch;patch=1 \
46 file://hostap-monitor-mode.patch;patch=1 \
47 file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1 \
48 ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \ 47 ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \
49 ${RPSRC}/logo_oz-r2.patch.bz2;patch=1;status=unmergable \
50 ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \ 48 ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \
49 file://hostap-monitor-mode.patch;patch=1;status=unmergable \
50 file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1;status=unmergable \
51 ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \ 51 ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \
52 file://mmcsd_no_scr_check-r2.patch;patch=1 \ 52 ${RPSRC}/mmcsd_no_scr_check-r2.patch;patch=1;status=hack \
53 ${RPSRC}/integrator_rgb-r1.patch;patch=1;status=hack \ 53 ${RPSRC}/integrator_rgb-r1.patch;patch=1;status=hack \
54 ${RPSRC}/pxa_cf_initorder_hack-r1.patch;patch=1;status=hack \ 54 ${RPSRC}/pxa_cf_initorder_hack-r1.patch;patch=1;status=hack \
55 file://pxa-serial-hack.patch;patch=1;status=hack \ 55 file://pxa-serial-hack.patch;patch=1;status=hack \
56 file://connectplus-remove-ide-HACK.patch;patch=1;status=hack \ 56 file://connectplus-remove-ide-HACK.patch;patch=1;status=hack \
57 file://connectplus-prevent-oops-HACK.patch;patch=1;status=hack \ 57 file://connectplus-prevent-oops-HACK.patch;patch=1;status=hack \
58 file://squashfs3.0-2.6.15.patch;patch=1;status=external \
59 file://uvesafb-0.1-rc3-2.6.22.patch;patch=1;status=external \
60 file://htcuni.patch;patch=1 \ 58 file://htcuni.patch;patch=1 \
61 file://binutils-buildid-arm.patch;patch=1 \ 59 file://binutils-buildid-arm.patch;patch=1 \
60 file://versatile-armv6.patch;patch=1 \
62 file://defconfig-c7x0 \ 61 file://defconfig-c7x0 \
63 file://defconfig-hx2000 \ 62 file://defconfig-hx2000 \
64 file://defconfig-collie \ 63 file://defconfig-collie \