summaryrefslogtreecommitdiff
path: root/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
diff options
context:
space:
mode:
authorChris Larson <clarson@kergoth.com>2004-12-09 09:47:41 +0000
committerChris Larson <clarson@kergoth.com>2004-12-09 09:47:41 +0000
commit2c5b8ec6d95cf68650265941530e5ce38c8dd6d9 (patch)
treebf879bea7ef8517ba8c3d1286ef300401d3d484c /linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
parent101e2f1623def0a355d20aacb8bd93810703e834 (diff)
Merge oe-devel@oe-devel.bkbits.net:openembedded
into hyperion.kergoth.com:/home/kergoth/code/openembedded 2004/12/09 03:39:39-06:00 kergoth.com!kergoth Break people's builds again.. this time moving the packages into a packages/ subdir to clean things up a bit. BKrev: 41b81f3dvlp3rU7_8MUXLcI8LDdDoA
Diffstat (limited to 'linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch')
-rw-r--r--linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch20991
1 files changed, 0 insertions, 20991 deletions
diff --git a/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch b/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
deleted file mode 100644
index e8ed5c9d44..0000000000
--- a/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
+++ /dev/null
@@ -1,20991 +0,0 @@
---- linux-2.6.5/kernel/printk.c~heh 2004-04-03 22:38:24.000000000 -0500
-+++ linux-2.6.5/kernel/printk.c 2004-04-30 20:57:36.000000000 -0400
-@@ -832,3 +832,25 @@
- printk_ratelimit_burst);
- }
- EXPORT_SYMBOL(printk_ratelimit);
-+
-+#include <linux/sysrq.h>
-+
-+static void
-+show_msg_info(int key, struct pt_regs *regs, struct tty_struct *tty)
-+{
-+ call_console_drivers(log_end - logged_chars, log_end);
-+}
-+
-+static struct sysrq_key_op msg_info_op = {
-+ .handler = show_msg_info,
-+ .help_msg = "Dumpmsgs",
-+ .action_msg = "Kernel Messages",
-+};
-+
-+static int __init dbg_init(void)
-+{
-+ register_sysrq_key('d', &msg_info_op);
-+ return 0;
-+}
-+
-+__initcall(dbg_init);
---- linux-2.6.5/kernel/resource.c~heh 2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/kernel/resource.c 2004-04-30 20:57:36.000000000 -0400
-@@ -179,6 +179,8 @@
- {
- struct resource *tmp, **p;
-
-+ BUG_ON(old->child);
-+
- p = &old->parent->child;
- for (;;) {
- tmp = *p;
-@@ -409,6 +411,47 @@
- EXPORT_SYMBOL(adjust_resource);
-
- /*
-+ * Given an existing resource, change its start and size to match the
-+ * arguments. Returns -EBUSY if it can't fit. Existing children of
-+ * the resource are assumed to be immutable.
-+ */
-+int reallocate_resource(struct resource *res, unsigned long start, unsigned long size)
-+{
-+ struct resource *tmp, *parent = res->parent;
-+ unsigned long end = start + size - 1;
-+ int result = -EBUSY;
-+
-+ write_lock(&resource_lock);
-+
-+ if ((start < parent->start) || (end > parent->end))
-+ goto out;
-+
-+ for (tmp = res->child; tmp; tmp = tmp->sibling) {
-+ if ((tmp->start < start) || (tmp->end > end))
-+ goto out;
-+ }
-+
-+ if (res->sibling && (res->sibling->start <= end))
-+ goto out;
-+
-+ tmp = parent->child;
-+ if (tmp != res) {
-+ while (tmp->sibling != res)
-+ tmp = tmp->sibling;
-+ if (start <= tmp->end)
-+ goto out;
-+ }
-+
-+ res->start = start;
-+ res->end = end;
-+ result = 0;
-+
-+ out:
-+ write_unlock(&resource_lock);
-+ return result;
-+}
-+
-+/*
- * This is compatibility stuff for IO resources.
- *
- * Note how this, unlike the above, knows about
---- linux-2.6.5/include/asm-arm/mach/irq.h~heh 2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/mach/irq.h 2004-04-30 20:57:36.000000000 -0400
-@@ -14,6 +14,19 @@
- struct pt_regs;
- struct seq_file;
-
-+/*
-+ * Architectures are expected to define NR_IRQ_DEVICES and
-+ * NR_IRQ_DEVICE_SHIFT if they wish to use dynamic IRQs.
-+ */
-+#ifndef NR_IRQ_DEVICES
-+#define NR_IRQ_DEVICES 1
-+#endif
-+#define NR_IRQ_PER_DEVICE (1 << (NR_IRQ_DEVICE_SHIFT - 1))
-+
-+#define IRQ_DEVICE(i) ((i) >> NR_IRQ_DEVICE_SHIFT)
-+#define IRQ_INDEX(i) ((i) & (NR_IRQ_PER_GROUP - 1))
-+#define TO_IRQ(g,i) (((g) << NR_IRQ_DEVICE_SHIFT) + (i))
-+
- typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *);
- typedef void (*irq_control_t)(unsigned int);
-
---- linux-2.6.5/include/asm-arm/arch-pxa/uncompress.h~heh 2004-04-03 22:36:17.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/arch-pxa/uncompress.h 2004-04-30 20:57:36.000000000 -0400
-@@ -12,6 +12,7 @@
- #define FFUART ((volatile unsigned long *)0x40100000)
- #define BTUART ((volatile unsigned long *)0x40200000)
- #define STUART ((volatile unsigned long *)0x40700000)
-+#define HWUART ((volatile unsigned long *)0x41600000)
-
- #define UART FFUART
-
---- linux-2.6.5/include/asm-arm/arch-pxa/dma.h~heh 2004-04-03 22:38:18.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/arch-pxa/dma.h 2004-04-30 20:57:36.000000000 -0400
-@@ -22,11 +22,11 @@
- * Note: this structure must always be aligned to a 16-byte boundary.
- */
-
--typedef struct {
-- volatile u32 ddadr; /* Points to the next descriptor + flags */
-- volatile u32 dsadr; /* DSADR value for the current transfer */
-- volatile u32 dtadr; /* DTADR value for the current transfer */
-- volatile u32 dcmd; /* DCMD value for the current transfer */
-+typedef struct pxa_dma_desc {
-+ u32 ddadr; /* Points to the next descriptor + flags */
-+ u32 dsadr; /* DSADR value for the current transfer */
-+ u32 dtadr; /* DTADR value for the current transfer */
-+ u32 dcmd; /* DCMD value for the current transfer */
- } pxa_dma_desc;
-
- /*
---- linux-2.6.5/include/asm-arm/arch-pxa/serial.h~heh 2004-04-03 22:37:06.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/arch-pxa/serial.h 2004-04-30 20:57:36.000000000 -0400
-@@ -43,6 +43,15 @@
- io_type: SERIAL_IO_MEM, \
- irq: IRQ_BTUART, \
- flags: STD_COM_FLAGS, \
-+ }, { \
-+ type: PORT_PXA, \
-+ xmit_fifo_size: 64, \
-+ baud_base: BAUD_BASE, \
-+ iomem_base: &HWUART, \
-+ iomem_reg_shift: 2, \
-+ io_type: SERIAL_IO_MEM, \
-+ irq: IRQ_HWUART, \
-+ flags: STD_COM_FLAGS, \
- }
-
- #define EXTRA_SERIAL_PORT_DEFNS
---- linux-2.6.5/include/asm-arm/arch-pxa/pxa-regs.h~heh 2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/arch-pxa/pxa-regs.h 2004-04-30 20:57:36.000000000 -0400
-@@ -124,26 +124,26 @@
- #define DRCMR12 __REG(0x40000130) /* Request to Channel Map Register for AC97 audio transmit Request */
- #define DRCMR13 __REG(0x40000134) /* Request to Channel Map Register for SSP receive Request */
- #define DRCMR14 __REG(0x40000138) /* Request to Channel Map Register for SSP transmit Request */
--#define DRCMR15 __REG(0x4000013c) /* Reserved */
--#define DRCMR16 __REG(0x40000140) /* Reserved */
-+#define DRCMR15 __REG(0x4000013c) /* Request to Channel Map Register for NSSP receive Request */
-+#define DRCMR16 __REG(0x40000140) /* Request to Channel Map Register for NSSP transmit Request */
- #define DRCMR17 __REG(0x40000144) /* Request to Channel Map Register for ICP receive Request */
- #define DRCMR18 __REG(0x40000148) /* Request to Channel Map Register for ICP transmit Request */
- #define DRCMR19 __REG(0x4000014c) /* Request to Channel Map Register for STUART receive Request */
- #define DRCMR20 __REG(0x40000150) /* Request to Channel Map Register for STUART transmit Request */
- #define DRCMR21 __REG(0x40000154) /* Request to Channel Map Register for MMC receive Request */
- #define DRCMR22 __REG(0x40000158) /* Request to Channel Map Register for MMC transmit Request */
--#define DRCMR23 __REG(0x4000015c) /* Reserved */
--#define DRCMR24 __REG(0x40000160) /* Reserved */
-+#define DRCMR23 __REG(0x4000015c) /* Request to Channel Map Register for ASSP receive Request */
-+#define DRCMR24 __REG(0x40000160) /* Request to Channel Map Register for ASSP transmit Request */
- #define DRCMR25 __REG(0x40000164) /* Request to Channel Map Register for USB endpoint 1 Request */
- #define DRCMR26 __REG(0x40000168) /* Request to Channel Map Register for USB endpoint 2 Request */
- #define DRCMR27 __REG(0x4000016C) /* Request to Channel Map Register for USB endpoint 3 Request */
- #define DRCMR28 __REG(0x40000170) /* Request to Channel Map Register for USB endpoint 4 Request */
--#define DRCMR29 __REG(0x40000174) /* Reserved */
-+#define DRCMR29 __REG(0x40000174) /* Request to Channel Map Register for HWUART receive Request */
- #define DRCMR30 __REG(0x40000178) /* Request to Channel Map Register for USB endpoint 6 Request */
- #define DRCMR31 __REG(0x4000017C) /* Request to Channel Map Register for USB endpoint 7 Request */
- #define DRCMR32 __REG(0x40000180) /* Request to Channel Map Register for USB endpoint 8 Request */
- #define DRCMR33 __REG(0x40000184) /* Request to Channel Map Register for USB endpoint 9 Request */
--#define DRCMR34 __REG(0x40000188) /* Reserved */
-+#define DRCMR34 __REG(0x40000188) /* Request to Channel Map Register for HWUART transmit Request */
- #define DRCMR35 __REG(0x4000018C) /* Request to Channel Map Register for USB endpoint 11 Request */
- #define DRCMR36 __REG(0x40000190) /* Request to Channel Map Register for USB endpoint 12 Request */
- #define DRCMR37 __REG(0x40000194) /* Request to Channel Map Register for USB endpoint 13 Request */
-@@ -163,12 +163,16 @@
- #define DRCMRTXPCDR DRCMR12
- #define DRCMRRXSSDR DRCMR13
- #define DRCMRTXSSDR DRCMR14
-+#define DRCMRRXNSSPDR DRCMR15
-+#define DRCMRTXNSSPDR DRCMR16
- #define DRCMRRXICDR DRCMR17
- #define DRCMRTXICDR DRCMR18
- #define DRCMRRXSTRBR DRCMR19
- #define DRCMRTXSTTHR DRCMR20
- #define DRCMRRXMMC DRCMR21
- #define DRCMRTXMMC DRCMR22
-+#define DRCMRRXASSPDR DRCMR23
-+#define DRCMRTXASSPDR DRCMR24
-
- #define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */
- #define DRCMR_CHLNUM 0x0f /* mask for Channel Number (read / write) */
-@@ -303,6 +307,22 @@
- #define BTDLL __REG(0x40200000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
- #define BTDLH __REG(0x40200004) /* Divisor Latch High Register (DLAB = 1) (read/write) */
-
-+/* Hardware UART (HWUART) */
-+#define HWUART HWRBR
-+#define HWRBR __REG(0x41600000) /* Receive Buffer Register (read only) */
-+#define HWTHR __REG(0x41600000) /* Transmit Holding Register (write only) */
-+#define HWIER __REG(0x41600004) /* Interrupt Enable Register (read/write) */
-+#define HWIIR __REG(0x41600008) /* Interrupt ID Register (read only) */
-+#define HWFCR __REG(0x41600008) /* FIFO Control Register (write only) */
-+#define HWLCR __REG(0x4160000C) /* Line Control Register (read/write) */
-+#define HWMCR __REG(0x41600010) /* Modem Control Register (read/write) */
-+#define HWLSR __REG(0x41600014) /* Line Status Register (read only) */
-+#define HWMSR __REG(0x41600018) /* Reserved */
-+#define HWSPR __REG(0x4160001C) /* Scratch Pad Register (read/write) */
-+#define HWISR __REG(0x41600020) /* Infrared Selection Register (read/write) */
-+#define HWDLL __REG(0x41600000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
-+#define HWDLH __REG(0x41600004) /* Divisor Latch High Register (DLAB = 1) (read/write) */
-+
- /* Standard UART (STUART) */
- #define STUART STRBR
- #define STRBR __REG(0x40700000) /* Receive Buffer Register (read only) */
-@@ -1078,6 +1098,111 @@
-
-
- /*
-+ * NSSP Serial Port Registers (Network SSP)
-+ */
-+
-+#define NSSCR0 __REG(0x41400000) /* NSSP Control Register 0 */
-+#define NSSCR1 __REG(0x41400004) /* NSSP Control Register 1 */
-+#define NSSSR __REG(0x41400008) /* NSSP Status Register */
-+#define NSSITR __REG(0x4140000C) /* NSSP Interrupt Test Register */
-+#define NSSDR __REG(0x41400010) /* (Write / Read) NSSP Data Write Register/NSSP Data Read Register */
-+#define NSSTO __REG(0x41400028) /* NSSP Time Out Register */
-+#define NSSPSP __REG(0x4140002C) /* NSSP Programable Serial Port Register*/
-+
-+
-+/*
-+ * ASSP Serial Port Registers (Audio SSP)
-+ */
-+
-+#define ASSCR0 __REG(0x41500000) /* ASSP Control Register 0 */
-+#define ASSCR1 __REG(0x41500004) /* ASSP Control Register 1 */
-+#define ASSSR __REG(0x41500008) /* ASSP Status Register */
-+#define ASSITR __REG(0x4150000C) /* ASSP Interrupt Test Register */
-+#define ASSDR __REG(0x41500010) /* (Write / Read) ASSP Data Write Register/ASSP Data Read Register */
-+#define ASSTO __REG(0x41500028) /* ASSP Time Out Register */
-+#define ASSPSP __REG(0x4150002C) /* ASSP Programable Serial Port Register*/
-+
-+
-+/*
-+ * Bit definitions for SSP, NSSP and ASSP registers
-+ * - note that some bits are only available on the NSSP and ASSP
-+ */
-+
-+#define SSCR0_EDSS (1 << 20) /* ext. data size select */
-+#define SSCR0_SCR_MASK 0x000fff00 /* [19:8] secrial clock rate */
-+#define SSCR0_SCR(x) (((x)<<8) & XSSCR0_SCR_MASK)
-+#define SSCR0_SSE (1 << 7) /* sync ser port enable */
-+#define SSCR0_FRF_MASK 0x00000030 /* [5:4] frame format */
-+#define SSCR0_FRF(x) (((x)<<4) & XSSCR0_FRF_MASK)
-+#define SSCR0_FRF_SPI 0x00000000 /* ser peripheral i/f */
-+#define SSCR0_FRF_TISSP 0x00000010 /* TI sync ser port */
-+#define SSCR0_FRF_MICROWAVE 0x00000020 /* microwire */
-+#define SSCR0_FRF_PSP 0x00000030 /* prog ser protocol */
-+#define SSCR0_DSS_MASK 0x0000000f /* data size select */
-+#define SSCR0_DSS(x) ((x) & XSSCR0_DSS_MASK)
-+
-+#define SSCR1_TTELP (1 << 31) /* tx hi-z later phase */
-+#define SSCR1_TTE (1 << 30) /* tx hi-z enable */
-+#define SSCR1_EBCEI (1 << 29) /* bit count error int mask */
-+#define SSCR1_SCFR (1 << 28) /* slave clock free running */
-+#define SSCR1_SCLKDIR (1 << 25) /* ssp clock direction */
-+#define SSCR1_SFRMDIR (1 << 24) /* ssp frame direction */
-+#define SSCR1_RWOT (1 << 23) /* rx without transmit */
-+#define SSCR1_TSRE (1 << 21) /* tx req enable */
-+#define SSCR1_RSRE (1 << 20) /* rx req enable */
-+#define SSCR1_TINTE (1 << 19) /* timeout int enable */
-+#define SSCR1_STRF (1 << 15) /* select fifo for efwr */
-+#define SSCR1_EFWR (1 << 14) /* fifo write/read enable */
-+#define SSCR1_RFT_MASK 0x00003c00 /* [13:10] rx fifo threshold */
-+#define SSCR1_RFT(x) (((x)<<10) & XSSCR1_RFT_MASK)
-+#define SSCR1_TFT_MASK 0x000003c0 /* [9:6] tx fifo threshold */
-+#define SSCR1_TFT(x) (((x)<<6) & XSSCR1_TFT_MASK)
-+#define SSCR1_MWDS (1 << 5) /* microwire tx data size */
-+#define SSCR1_SPH (1 << 4) /* SPI SSPSCLK phase */
-+#define SSCR1_SPO (1 << 3) /* motorolla SPI polarity */
-+#define SSCR1_LBM (1 << 2) /* loop-back mode */
-+#define SSCR1_TIE (1 << 1) /* tx fifo int enable */
-+#define SSCR1_RIE (1 << 0) /* rx fifo int enable */
-+
-+#define SSPSP_DMYSTOP_MASK 0x01800000 /* [24:23] dummy stop */
-+#define SSPSP_DMYSTOP(x) (((x)<<23) & XSSPSP_DMYSTOP_MASK)
-+#define SSPSP_SFRMWDTH_MASK 0x007f0000 /* [22:16] serial frame width */
-+#define SSPSP_SFRMWDTH(x) (((x)<<16) & XSSPSP_SFRMWDTH_MASK)
-+#define SSPSP_SFRMDLY_MASK 0x0000fe00 /* [15:9] serial frame delay */
-+#define SSPSP_SFRMDLY(x) (((x)<<9) & XSSPSP_SFRMDLY_MASK)
-+#define SSPSP_DMYSTRT_MASK 0x00000180 /* [8:7] dummy start */
-+#define SSPSP_DMYSTRT(x) (((x)<<7) & XSSPSP_DMYSTRT_MASK)
-+#define SSPSP_STRTDLY_MASK 0x00000070 /* [6:4] three-bit start delay */
-+#define SSPSP_STRTDLY(x) (((x)<<4) & XSSPSP_STRTDLY_MASK)
-+#define SSPSP_ETDS (1 << 3) /* end of tx data state */
-+#define SSPSP_SFRMP (1 << 2) /* serial frame polarity */
-+#define SSPSP_SCMODE_MASK 0x00000003 /* bit-rate clock mode */
-+#define SSPSP_SCMODE(x) ((x) & XSSPSP_SCMODE_MASK)
-+
-+#define SSTO_TIMEOUT_MASK 0x00ffffff /* [23:0] timeout */
-+#define SSTO_TIMEOUT(x) ((x) & XSSTO_TIMEOUT_MASK)
-+
-+#define SSITR_TROR (1 << 7) /* test rx fifo overrun */
-+#define SSITR_TRFS (1 << 6) /* test rx fifo serv req */
-+#define SSITR_TTFS (1 << 5) /* test tx fifo serv req */
-+
-+#define SSSR_BCE (1 << 23) /* bit count error */
-+#define SSSR_CSS (1 << 22) /* clock sync stat */
-+#define SSSR_TUR (1 << 21) /* tx fifo underrun */
-+#define SSSR_TINT (1 << 19) /* rx timeout int */
-+#define SSSR_RFL_MASK 0x0000f000 /* rx fifo level */
-+#define SSSR_RFL(x) (((x)<<16) & XSSSR_RFL_MASK)
-+#define SSSR_TFL_MASK 0x00000f00 /* tx fifo level */
-+#define SSSR_TFL(x) (((x)<<8) & XSSSR_TFL_MASK)
-+#define SSSR_ROR (1 << 7) /* rx fifo overrun */
-+#define SSSR_RFS (1 << 6) /* rx fifo serv request */
-+#define SSSR_TFS (1 << 5) /* tx fifo serv req */
-+#define SSSR_BSY (1 << 4) /* SSP busy */
-+#define SSSR_RNE (1 << 3) /* rx fifo not empty */
-+#define SSSR_TNF (1 << 2) /* tx fifo not full */
-+
-+
-+/*
- * MultiMediaCard (MMC) controller
- */
-
-@@ -1122,6 +1247,7 @@
- #define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */
- #define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */
- #define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */
-+#define CKEN4_HWUART (1 << 4) /* HWUART Unit Clock Enable */
- #define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */
- #define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */
- #define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */
---- linux-2.6.5/include/asm-arm/page.h~heh 2004-04-03 22:36:25.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/page.h 2004-04-30 20:57:36.000000000 -0400
-@@ -92,6 +92,14 @@
- # endif
- #endif
-
-+#ifdef CONFIG_CPU_COPY_V6
-+# ifdef _USER
-+# define MULTI_USER 1
-+# else
-+# define _USER v6
-+# endif
-+#endif
-+
- #ifndef _USER
- #error Unknown user operations model
- #endif
---- linux-2.6.5/include/asm-arm/thread_info.h~heh 2004-04-03 22:37:06.000000000 -0500
-+++ linux-2.6.5/include/asm-arm/thread_info.h 2004-04-30 20:57:36.000000000 -0400
-@@ -108,8 +108,8 @@
- #define TI_CPU 20
- #define TI_CPU_DOMAIN 24
- #define TI_CPU_SAVE 28
--#define TI_USED_MATH 76
--#define TI_FPSTATE (TI_USED_MATH+16)
-+#define TI_USED_CP 76
-+#define TI_FPSTATE (TI_USED_CP+16)
-
- #endif
-
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/asm-arm/rtc.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,45 @@
-+/*
-+ * linux/include/asm-arm/rtc.h
-+ *
-+ * Copyright (C) 2003 Deep Blue Solutions Ltd.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#ifndef ASMARM_RTC_H
-+#define ASMARM_RTC_H
-+
-+struct module;
-+
-+struct rtc_ops {
-+ struct module *owner;
-+ int (*open)(void);
-+ void (*release)(void);
-+ int (*ioctl)(unsigned int, unsigned long);
-+
-+ void (*read_time)(struct rtc_time *);
-+ int (*set_time)(struct rtc_time *);
-+ void (*read_alarm)(struct rtc_wkalrm *);
-+ int (*set_alarm)(struct rtc_wkalrm *);
-+ int (*proc)(char *buf);
-+};
-+
-+void rtc_time_to_tm(unsigned long, struct rtc_time *);
-+int rtc_tm_to_time(struct rtc_time *, unsigned long *);
-+void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
-+void rtc_update(unsigned long, unsigned long);
-+int register_rtc(struct rtc_ops *);
-+void unregister_rtc(struct rtc_ops *);
-+
-+static inline int rtc_periodic_alarm(struct rtc_time *tm)
-+{
-+ return (tm->tm_year == -1) ||
-+ ((unsigned)tm->tm_mon >= 12) ||
-+ ((unsigned)(tm->tm_mday - 1) >= 31) ||
-+ ((unsigned)tm->tm_hour > 23) ||
-+ ((unsigned)tm->tm_min > 59) ||
-+ ((unsigned)tm->tm_sec > 59);
-+}
-+
-+#endif
---- linux-2.6.5/include/linux/serial.h~heh 2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/include/linux/serial.h 2004-04-30 20:57:36.000000000 -0400
-@@ -81,17 +81,6 @@
- #define SERIAL_IO_HUB6 1
- #define SERIAL_IO_MEM 2
-
--struct serial_uart_config {
-- char *name;
-- int dfl_xmit_fifo_size;
-- int flags;
--};
--
--#define UART_CLEAR_FIFO 0x01
--#define UART_USE_FIFO 0x02
--#define UART_STARTECH 0x04
--#define UART_NATSEMI 0x08
--
- /*
- * Definitions for async_struct (and serial_struct) flags field
- */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/i2c-pxa.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,76 @@
-+/*
-+ * i2c_pxa.h
-+ *
-+ * Copyright (C) 2002 Intrinsyc Software Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+#ifndef _I2C_PXA_H_
-+#define _I2C_PXA_H_
-+
-+struct i2c_algo_pxa_data
-+{
-+ void (*write_byte) (u8 value);
-+ u8 (*read_byte) (void);
-+ void (*start) (void);
-+ void (*repeat_start) (void);
-+ void (*stop) (void);
-+ void (*abort) (void);
-+ int (*wait_bus_not_busy) (void);
-+ int (*wait_for_interrupt) (int wait_type);
-+ void (*transfer) (int lastbyte, int receive, int midbyte);
-+ void (*reset) (void);
-+
-+ int udelay;
-+ int timeout;
-+};
-+
-+#define DEF_TIMEOUT 3
-+#define BUS_ERROR (-EREMOTEIO)
-+#define ACK_DELAY 0 /* time to delay before checking bus error */
-+#define MAX_MESSAGES 65536 /* maximum number of messages to send */
-+
-+#define I2C_SLEEP_TIMEOUT 2 /* time to sleep for on i2c transactions */
-+#define I2C_RETRY (-2000) /* an error has occurred retry transmit */
-+#define I2C_TRANSMIT 1
-+#define I2C_RECEIVE 0
-+#define I2C_PXA_SLAVE_ADDR 0x1 /* slave pxa unit address */
-+#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */
-+/* ICR initialize bit values
-+*
-+* 15. FM 0 (100 Khz operation)
-+* 14. UR 0 (No unit reset)
-+* 13. SADIE 0 (Disables the unit from interrupting on slave addresses
-+* matching its slave address)
-+* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration
-+* in master mode)
-+* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode)
-+* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent)
-+* 9. IRFIE 1 (Enable interrupts from full buffer received)
-+* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty)
-+* 7. GCD 1 (Disables i2c unit response to general call messages as a slave)
-+* 6. IUE 0 (Disable unit until we change settings)
-+* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL)
-+* 4. MA 0 (Only send stop with the ICR stop bit)
-+* 3. TB 0 (We are not transmitting a byte initially)
-+* 2. ACKNAK 0 (Send an ACK after the unit receives a byte)
-+* 1. STOP 0 (Do not send a STOP)
-+* 0. START 0 (Do not send a START)
-+*
-+*/
-+
-+#define I2C_ISR_INIT 0x7FF /* status register init */
-+/* I2C status register init values
-+ *
-+ * 10. BED 1 (Clear bus error detected)
-+ * 9. SAD 1 (Clear slave address detected)
-+ * 7. IRF 1 (Clear IDBR Receive Full)
-+ * 6. ITE 1 (Clear IDBR Transmit Empty)
-+ * 5. ALD 1 (Clear Arbitration Loss Detected)
-+ * 4. SSD 1 (Clear Slave Stop Detected)
-+ */
-+
-+#endif
---- linux-2.6.5/include/linux/ioport.h~heh 2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/include/linux/ioport.h 2004-04-30 20:57:36.000000000 -0400
-@@ -99,6 +99,7 @@
- void (*alignf)(void *, struct resource *,
- unsigned long, unsigned long),
- void *alignf_data);
-+extern int reallocate_resource(struct resource *res, unsigned long start, unsigned long size);
- int adjust_resource(struct resource *res, unsigned long start,
- unsigned long size);
-
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/switches.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,74 @@
-+/*
-+ * linux/include/linux/switches.h
-+ *
-+ * Copyright (C) 2000 John Dorsey
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 23 October 2000 - created.
-+ */
-+
-+#if !defined(_LINUX_SWITCHES_H)
-+#define _LINUX_SWITCHES_H
-+
-+#define SWITCHES_MASK_SIZE (128)
-+
-+typedef unsigned long switches_bitfield;
-+
-+#define SWITCHES_BITS (sizeof(switches_bitfield) * 8)
-+#define SWITCHES_NUM_FIELDS (SWITCHES_MASK_SIZE / SWITCHES_BITS)
-+#define SWITCHES_FIELD_SELECT(i) ((i) / SWITCHES_BITS)
-+#define SWITCHES_FIELD_MASK(i) ((switches_bitfield)(1 << (i) % \
-+ SWITCHES_BITS))
-+
-+typedef struct switches_mask_t {
-+ unsigned int count;
-+ switches_bitfield events[SWITCHES_NUM_FIELDS];
-+ switches_bitfield states[SWITCHES_NUM_FIELDS];
-+} switches_mask_t;
-+
-+#define SWITCHES_ZERO(m) \
-+do { \
-+ unsigned int sz_i; \
-+ (m)->count = 0; \
-+ for(sz_i = 0; sz_i < SWITCHES_NUM_FIELDS; ++sz_i) \
-+ (m)->events[sz_i] = (m)->states[sz_i] = 0; \
-+} while (0)
-+
-+/* `s' is the state of the switch, either 0 or non-zero: */
-+#define SWITCHES_SET(m, i, s) \
-+do { \
-+ ((m)->events[SWITCHES_FIELD_SELECT((i))] |= \
-+ SWITCHES_FIELD_MASK((i))); \
-+ if(s) \
-+ ((m)->states[SWITCHES_FIELD_SELECT((i))] |= \
-+ SWITCHES_FIELD_MASK((i))); \
-+ else \
-+ ((m)->states[SWITCHES_FIELD_SELECT((i))] &= \
-+ ~SWITCHES_FIELD_MASK((i))); \
-+ ++((m)->count); \
-+} while (0)
-+
-+/* Should only use to clear an event set by SWITCHES_SET(): */
-+#define SWITCHES_CLEAR(m, i) \
-+do { \
-+ ((m)->events[SWITCHES_FIELD_SELECT((i))] &= \
-+ ~SWITCHES_FIELD_MASK((i))); \
-+ ((m)->states[SWITCHES_FIELD_SELECT((i))] &= \
-+ ~SWITCHES_FIELD_MASK((i))); \
-+ --((m)->count); \
-+}
-+
-+#define SWITCHES_COUNT(m) ((m)->count)
-+
-+/* Returns 0 or non-zero: */
-+#define SWITCHES_EVENT(m, i) \
-+((m)->events[SWITCHES_FIELD_SELECT((i))] & SWITCHES_FIELD_MASK((i)))
-+
-+/* Returns 0 or non-zero: */
-+#define SWITCHES_STATE(m, i) \
-+((m)->states[SWITCHES_FIELD_SELECT((i))] & SWITCHES_FIELD_MASK((i)))
-+
-+#endif /* !defined(_LINUX_SWITCHES_H) */
---- linux-2.6.5/include/linux/serial_reg.h~heh 2004-04-03 22:37:38.000000000 -0500
-+++ linux-2.6.5/include/linux/serial_reg.h 2004-04-30 20:57:36.000000000 -0400
-@@ -121,6 +121,7 @@
- /*
- * These are the definitions for the Modem Control Register
- */
-+#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */
- #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
- #define UART_MCR_OUT2 0x08 /* Out2 complement */
- #define UART_MCR_OUT1 0x04 /* Out1 complement */
-@@ -156,6 +157,21 @@
- #define UART_FCR_PXAR32 0xc0 /* receive FIFO treshold = 32 */
-
- /*
-+ * The Intel PXA2xx chip defines those bits
-+ */
-+#define UART_IER_DMAE 0x80 /* DMA Requests Enable */
-+#define UART_IER_UUE 0x40 /* UART Unit Enable */
-+#define UART_IER_NRZE 0x20 /* NRZ coding Enable */
-+#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */
-+
-+#define UART_IIR_TOD 0x08 /* Character Timeout Indication Detected */
-+
-+#define UART_FCR_PXAR1 0x00 /* receive FIFO treshold = 1 */
-+#define UART_FCR_PXAR8 0x40 /* receive FIFO treshold = 8 */
-+#define UART_FCR_PXAR16 0x80 /* receive FIFO treshold = 16 */
-+#define UART_FCR_PXAR32 0xc0 /* receive FIFO treshold = 32 */
-+
-+/*
- * These are the definitions for the Extended Features Register
- * (StarTech 16C660 only, when DLAB=1)
- */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/mmc/card.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,83 @@
-+/*
-+ * linux/include/linux/mmc/card.h
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * Card driver specific definitions.
-+ */
-+#ifndef LINUX_MMC_CARD_H
-+#define LINUX_MMC_CARD_H
-+
-+#include <linux/mmc/mmc.h>
-+
-+struct mmc_cid {
-+ unsigned int manfid;
-+ unsigned int serial;
-+ char prod_name[8];
-+ unsigned char hwrev;
-+ unsigned char fwrev;
-+ unsigned char month;
-+ unsigned char year;
-+};
-+
-+struct mmc_csd {
-+ unsigned char mmc_prot;
-+ unsigned short cmdclass;
-+ unsigned short tacc_clks;
-+ unsigned int tacc_ns;
-+ unsigned int max_dtr;
-+ unsigned int read_blkbits;
-+ unsigned int capacity;
-+};
-+
-+struct mmc_host;
-+
-+/*
-+ * MMC device
-+ */
-+struct mmc_card {
-+ struct list_head node; /* node in hosts devices list */
-+ struct mmc_host *host; /* the host this device belongs to */
-+ struct device dev; /* the device */
-+ unsigned int rca; /* relative card address of device */
-+ unsigned int state; /* (our) card state */
-+#define MMC_STATE_PRESENT (1<<0)
-+#define MMC_STATE_DEAD (1<<1)
-+ struct mmc_cid cid; /* card identification */
-+ struct mmc_csd csd; /* card specific */
-+};
-+
-+#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
-+#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
-+
-+#define mmc_card_name(c) ((c)->cid.prod_name)
-+#define mmc_card_id(c) ((c)->dev.bus_id)
-+
-+#define mmc_list_to_card(l) container_of(l, struct mmc_card, node)
-+#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev)
-+#define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d)
-+
-+/*
-+ * MMC device driver (e.g., Flash card, I/O card...)
-+ */
-+struct mmc_driver {
-+ struct device_driver drv;
-+ int (*probe)(struct mmc_card *);
-+ void (*remove)(struct mmc_card *);
-+ int (*suspend)(struct mmc_card *, u32);
-+ int (*resume)(struct mmc_card *);
-+};
-+
-+extern int mmc_register_driver(struct mmc_driver *);
-+extern void mmc_unregister_driver(struct mmc_driver *);
-+
-+static inline int mmc_card_claim_host(struct mmc_card *card)
-+{
-+ return __mmc_claim_host(card->host, card);
-+}
-+
-+#define mmc_card_release_host(c) mmc_release_host((c)->host)
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/mmc/mmc.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,88 @@
-+/*
-+ * linux/include/linux/mmc/mmc.h
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#ifndef MMC_H
-+#define MMC_H
-+
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/device.h>
-+
-+struct request;
-+struct mmc_data;
-+struct mmc_request;
-+
-+struct mmc_command {
-+ u32 opcode;
-+ u32 arg;
-+ u32 resp[4];
-+ unsigned int flags; /* expected response type */
-+#define MMC_RSP_NONE (0 << 0)
-+#define MMC_RSP_SHORT (1 << 0)
-+#define MMC_RSP_LONG (2 << 0)
-+#define MMC_RSP_MASK (3 << 0)
-+#define MMC_RSP_CRC (1 << 3) /* expect valid crc */
-+#define MMC_RSP_BUSY (1 << 4) /* card may send busy */
-+
-+ unsigned int retries; /* max number of retries */
-+ unsigned int error; /* command error */
-+
-+#define MMC_ERR_NONE 0
-+#define MMC_ERR_TIMEOUT 1
-+#define MMC_ERR_BADCRC 2
-+#define MMC_ERR_FIFO 3
-+#define MMC_ERR_FAILED 4
-+#define MMC_ERR_INVALID 5
-+
-+ struct mmc_data *data; /* data segment associated with cmd */
-+ struct mmc_request *req; /* assoicated request */
-+};
-+
-+struct mmc_data {
-+ unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
-+ unsigned int timeout_clks; /* data timeout (in clocks) */
-+ unsigned int blksz_bits; /* data block size */
-+ unsigned int blocks; /* number of blocks */
-+ struct request *rq; /* request structure */
-+ unsigned int error; /* data error */
-+ unsigned int flags;
-+
-+#define MMC_DATA_WRITE (1 << 8)
-+#define MMC_DATA_READ (1 << 9)
-+#define MMC_DATA_STREAM (1 << 10)
-+
-+ unsigned int bytes_xfered;
-+
-+ struct mmc_command *stop; /* stop command */
-+ struct mmc_request *req; /* assoicated request */
-+};
-+
-+struct mmc_request {
-+ struct mmc_command *cmd;
-+ struct mmc_data *data;
-+ struct mmc_command *stop;
-+
-+ void *done_data; /* completion data */
-+ void (*done)(struct mmc_request *);/* completion function */
-+};
-+
-+struct mmc_host;
-+struct mmc_card;
-+
-+extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
-+extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
-+
-+extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
-+
-+static inline void mmc_claim_host(struct mmc_host *host)
-+{
-+ __mmc_claim_host(host, (struct mmc_card *)-1);
-+}
-+
-+extern void mmc_release_host(struct mmc_host *host);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/mmc/host.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,67 @@
-+/*
-+ * linux/include/linux/mmc/host.h
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * Host driver specific definitions.
-+ */
-+#ifndef LINUX_MMC_HOST_H
-+#define LINUX_MMC_HOST_H
-+
-+#include <linux/mmc/mmc.h>
-+
-+struct mmc_ios {
-+ unsigned int clock; /* clock rate */
-+ unsigned short vdd; /* supply (units of 10mV) */
-+ unsigned char bus_mode; /* command output mode */
-+
-+#define MMC_BUSMODE_OPENDRAIN 1
-+#define MMC_BUSMODE_PUSHPULL 2
-+
-+ unsigned char power_mode; /* power supply mode */
-+
-+#define MMC_POWER_OFF 0
-+#define MMC_POWER_UP 1
-+#define MMC_POWER_ON 2
-+};
-+
-+struct mmc_host_ops {
-+ void (*request)(struct mmc_host *host, struct mmc_request *req);
-+ void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
-+};
-+
-+struct mmc_card;
-+
-+struct mmc_host {
-+ struct device *dev;
-+ struct mmc_host_ops *ops;
-+ unsigned int f_min;
-+ unsigned int f_max;
-+ u32 ocr_avail;
-+
-+ /* private data */
-+ unsigned int host_num; /* host number */
-+ struct mmc_ios ios; /* current io bus settings */
-+ u32 ocr; /* the current OCR setting */
-+
-+ struct list_head cards; /* devices attached to this host */
-+
-+ wait_queue_head_t wq;
-+ spinlock_t lock; /* card_busy lock */
-+ struct mmc_card *card_busy; /* the MMC card claiming host */
-+ struct mmc_card *card_selected; /* the selected MMC card */
-+};
-+
-+extern int mmc_init_host(struct mmc_host *);
-+extern int mmc_add_host(struct mmc_host *);
-+extern void mmc_remove_host(struct mmc_host *);
-+extern int mmc_suspend_host(struct mmc_host *, u32);
-+extern int mmc_resume_host(struct mmc_host *);
-+
-+extern void mmc_detect_change(struct mmc_host *);
-+extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
-+
-+#endif
-+
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/mmc/protocol.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,203 @@
-+/*
-+ * Header for MultiMediaCard (MMC)
-+ *
-+ * Copyright 2002 Hewlett-Packard Company
-+ *
-+ * Use consistent with the GNU GPL is permitted,
-+ * provided that this copyright notice is
-+ * preserved in its entirety in all copies and derived works.
-+ *
-+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
-+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
-+ * FITNESS FOR ANY PARTICULAR PURPOSE.
-+ *
-+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
-+ *
-+ * Based strongly on code by:
-+ *
-+ * Author: Yong-iL Joh <tolkien@mizi.com>
-+ * Date : $Date$
-+ *
-+ * Author: Andrew Christian
-+ * 15 May 2002
-+ */
-+
-+#ifndef MMC_MMC_PROTOCOL_H
-+#define MMC_MMC_PROTOCOL_H
-+
-+/* Standard MMC commands (3.1) type argument response */
-+ /* class 1 */
-+#define MMC_GO_IDLE_STATE 0 /* bc */
-+#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
-+#define MMC_ALL_SEND_CID 2 /* bcr R2 */
-+#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
-+#define MMC_SET_DSR 4 /* bc [31:16] RCA */
-+#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
-+#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
-+#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
-+#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
-+#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
-+#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
-+#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
-+
-+ /* class 2 */
-+#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
-+#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
-+#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
-+
-+ /* class 3 */
-+#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
-+
-+ /* class 4 */
-+#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
-+#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
-+#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
-+#define MMC_PROGRAM_CID 26 /* adtc R1 */
-+#define MMC_PROGRAM_CSD 27 /* adtc R1 */
-+
-+ /* class 6 */
-+#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
-+#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
-+#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
-+
-+ /* class 5 */
-+#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
-+#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
-+#define MMC_ERASE 37 /* ac R1b */
-+
-+ /* class 9 */
-+#define MMC_FAST_IO 39 /* ac <Complex> R4 */
-+#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
-+
-+ /* class 7 */
-+#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
-+
-+ /* class 8 */
-+#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
-+#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */
-+
-+/*
-+ MMC status in R1
-+ Type
-+ e : error bit
-+ s : status bit
-+ r : detected and set for the actual command response
-+ x : detected and set during command execution. the host must poll
-+ the card by sending status command in order to read these bits.
-+ Clear condition
-+ a : according to the card state
-+ b : always related to the previous command. Reception of
-+ a valid command will clear it (with a delay of one command)
-+ c : clear by read
-+ */
-+
-+#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
-+#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
-+#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
-+#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
-+#define R1_ERASE_PARAM (1 << 27) /* ex, c */
-+#define R1_WP_VIOLATION (1 << 26) /* erx, c */
-+#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
-+#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
-+#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
-+#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
-+#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
-+#define R1_CC_ERROR (1 << 20) /* erx, c */
-+#define R1_ERROR (1 << 19) /* erx, c */
-+#define R1_UNDERRUN (1 << 18) /* ex, c */
-+#define R1_OVERRUN (1 << 17) /* ex, c */
-+#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
-+#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
-+#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
-+#define R1_ERASE_RESET (1 << 13) /* sr, c */
-+#define R1_STATUS(x) (x & 0xFFFFE000)
-+#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
-+#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
-+#define R1_APP_CMD (1 << 7) /* sr, c */
-+
-+/* These are unpacked versions of the actual responses */
-+
-+struct _mmc_csd {
-+ u8 csd_structure;
-+ u8 spec_vers;
-+ u8 taac;
-+ u8 nsac;
-+ u8 tran_speed;
-+ u16 ccc;
-+ u8 read_bl_len;
-+ u8 read_bl_partial;
-+ u8 write_blk_misalign;
-+ u8 read_blk_misalign;
-+ u8 dsr_imp;
-+ u16 c_size;
-+ u8 vdd_r_curr_min;
-+ u8 vdd_r_curr_max;
-+ u8 vdd_w_curr_min;
-+ u8 vdd_w_curr_max;
-+ u8 c_size_mult;
-+ union {
-+ struct { /* MMC system specification version 3.1 */
-+ u8 erase_grp_size;
-+ u8 erase_grp_mult;
-+ } v31;
-+ struct { /* MMC system specification version 2.2 */
-+ u8 sector_size;
-+ u8 erase_grp_size;
-+ } v22;
-+ } erase;
-+ u8 wp_grp_size;
-+ u8 wp_grp_enable;
-+ u8 default_ecc;
-+ u8 r2w_factor;
-+ u8 write_bl_len;
-+ u8 write_bl_partial;
-+ u8 file_format_grp;
-+ u8 copy;
-+ u8 perm_write_protect;
-+ u8 tmp_write_protect;
-+ u8 file_format;
-+ u8 ecc;
-+};
-+
-+#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */
-+#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */
-+#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */
-+#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */
-+#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */
-+#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */
-+#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */
-+#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */
-+#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
-+#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
-+#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
-+#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
-+#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
-+#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
-+#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
-+#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
-+#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
-+#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
-+#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
-+#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
-+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
-+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
-+#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
-+#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
-+#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
-+
-+
-+/*
-+ * CSD field definitions
-+ */
-+
-+#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
-+#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
-+#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */
-+
-+#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
-+#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
-+#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
-+#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
-+
-+#endif /* MMC_MMC_PROTOCOL_H */
-+
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/l3/algo-bit.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,39 @@
-+/*
-+ * linux/include/linux/l3/algo-bit.h
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * L3 Bus bit-banging algorithm. Derived from i2c-algo-bit.h by
-+ * Simon G. Vogl.
-+ */
-+#ifndef L3_ALGO_BIT_H
-+#define L3_ALGO_BIT_H 1
-+
-+#include <linux/l3/l3.h>
-+
-+struct l3_algo_bit_data {
-+ void (*setdat) (void *data, int state);
-+ void (*setclk) (void *data, int state);
-+ void (*setmode)(void *data, int state);
-+ void (*setdir) (void *data, int in); /* set data direction */
-+ int (*getdat) (void *data);
-+
-+ void *data;
-+
-+ /* bus timings (us) */
-+ int data_hold;
-+ int data_setup;
-+ int clock_high;
-+ int mode_hold;
-+ int mode_setup;
-+ int mode;
-+};
-+
-+int l3_bit_add_bus(struct l3_adapter *);
-+int l3_bit_del_bus(struct l3_adapter *);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/l3/l3.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,95 @@
-+/*
-+ * linux/include/linux/l3/l3.h
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * Derived from i2c.h by Simon G. Vogl
-+ */
-+#ifndef L3_H
-+#define L3_H
-+
-+struct l3_msg {
-+ unsigned char addr; /* slave address */
-+ unsigned char flags;
-+#define L3_M_RD 0x01
-+#define L3_M_NOADDR 0x02
-+ unsigned short len; /* msg length */
-+ unsigned char *buf; /* pointer to msg data */
-+};
-+
-+#ifdef __KERNEL__
-+
-+#include <linux/types.h>
-+#include <linux/list.h>
-+
-+struct l3_adapter;
-+
-+struct l3_algorithm {
-+ /* textual description */
-+ char name[32];
-+
-+ /* perform bus transactions */
-+ int (*xfer)(struct l3_adapter *, struct l3_msg msgs[], int num);
-+};
-+
-+struct semaphore;
-+
-+/*
-+ * l3_adapter is the structure used to identify a physical L3 bus along
-+ * with the access algorithms necessary to access it.
-+ */
-+struct l3_adapter {
-+ /*
-+ * This name is used to uniquely identify the adapter.
-+ * It should be the same as the module name.
-+ */
-+ char name[32];
-+
-+ /*
-+ * the algorithm to access the bus
-+ */
-+ struct l3_algorithm *algo;
-+
-+ /*
-+ * Algorithm specific data
-+ */
-+ void *algo_data;
-+
-+ /*
-+ * This may be NULL, or should point to the module struct
-+ */
-+ struct module *owner;
-+
-+ /*
-+ * private data for the adapter
-+ */
-+ void *data;
-+
-+ /*
-+ * Our lock. Unlike the i2c layer, we allow this to be used for
-+ * other stuff, like the i2c layer lock. Some people implement
-+ * i2c stuff using the same signals as the l3 bus.
-+ */
-+ struct semaphore *lock;
-+
-+ /*
-+ * List of all adapters.
-+ */
-+ struct list_head adapters;
-+};
-+
-+extern int l3_add_adapter(struct l3_adapter *);
-+extern int l3_del_adapter(struct l3_adapter *);
-+extern void l3_put_adapter(struct l3_adapter *);
-+extern struct l3_adapter *l3_get_adapter(const char *name);
-+
-+extern int l3_write(struct l3_adapter *, int, const char *, int);
-+extern int l3_read(struct l3_adapter *, int, char *, int);
-+
-+#endif
-+
-+#endif /* L3_H */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/include/linux/l3/uda1341.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,61 @@
-+/*
-+ * linux/include/linux/l3/uda1341.h
-+ *
-+ * Philips UDA1341 mixer device driver
-+ *
-+ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License.
-+ */
-+
-+#define UDA1341_NAME "uda1341"
-+
-+struct uda1341_cfg {
-+ unsigned int fs:16;
-+ unsigned int format:3;
-+};
-+
-+#define FMT_I2S 0
-+#define FMT_LSB16 1
-+#define FMT_LSB18 2
-+#define FMT_LSB20 3
-+#define FMT_MSB 4
-+#define FMT_LSB16MSB 5
-+#define FMT_LSB18MSB 6
-+#define FMT_LSB20MSB 7
-+
-+#define L3_UDA1341_CONFIGURE 0x13410001
-+
-+struct l3_gain {
-+ unsigned int left:8;
-+ unsigned int right:8;
-+ unsigned int unused:8;
-+ unsigned int channel:8;
-+};
-+
-+#define L3_SET_VOLUME 0x13410002
-+#define L3_SET_TREBLE 0x13410003
-+#define L3_SET_BASS 0x13410004
-+#define L3_SET_GAIN 0x13410005
-+
-+struct l3_agc {
-+ unsigned int level:8;
-+ unsigned int enable:1;
-+ unsigned int attack:7;
-+ unsigned int decay:8;
-+ unsigned int channel:8;
-+};
-+
-+#define L3_INPUT_AGC 0x13410006
-+
-+struct uda1341;
-+
-+int uda1341_configure(struct uda1341 *uda, struct uda1341_cfg *conf);
-+int uda1341_mixer_ctl(struct uda1341 *uda, int cmd, void *arg);
-+int uda1341_open(struct uda1341 *uda);
-+void uda1341_close(struct uda1341 *uda);
-+
-+struct uda1341 *uda1341_attach(const char *adapter);
-+void uda1341_detach(struct uda1341 *uda);
-+
---- linux-2.6.5/include/linux/i2c-id.h~heh 2004-04-03 22:36:16.000000000 -0500
-+++ linux-2.6.5/include/linux/i2c-id.h 2004-04-30 20:57:36.000000000 -0400
-@@ -187,6 +187,7 @@
- #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */
- #define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */
-
-+#define I2C_ALGO_PXA 0x200000 /* Intel PXA I2C algorithm */
- #define I2C_ALGO_EXP 0x800000 /* experimental */
-
- #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */
---- linux-2.6.5/include/linux/serial_core.h~heh 2004-04-03 22:36:18.000000000 -0500
-+++ linux-2.6.5/include/linux/serial_core.h 2004-04-30 20:57:36.000000000 -0400
-@@ -17,7 +17,7 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-- * $Id$
-+ * $Id$
- */
-
- /*
-@@ -159,8 +159,6 @@
- spinlock_t lock; /* port lock */
- unsigned int iobase; /* in/out[bwl] */
- char *membase; /* read/write[bwl] */
-- unsigned int irq; /* irq number */
-- unsigned int uartclk; /* base uart clock */
- unsigned char fifosize; /* tx fifo size */
- unsigned char x_char; /* xon/xoff char */
- unsigned char regshift; /* reg offset shift */
-@@ -172,6 +170,7 @@
-
- unsigned int read_status_mask; /* driver specific */
- unsigned int ignore_status_mask; /* driver specific */
-+
- struct uart_info *info; /* pointer to parent info */
- struct uart_icount icount; /* statistics */
-
-@@ -182,7 +181,6 @@
-
- unsigned int flags;
-
--#define UPF_HUP_NOTIFY (1 << 0)
- #define UPF_FOURPORT (1 << 1)
- #define UPF_SAK (1 << 2)
- #define UPF_SPD_MASK (0x1030)
-@@ -212,9 +210,12 @@
- unsigned int timeout; /* character-based timeout */
- unsigned int type; /* port type */
- struct uart_ops *ops;
-+ unsigned int uartclk; /* base uart clock */
- unsigned int custom_divisor;
-+ unsigned int irq; /* irq number */
- unsigned int line; /* port index */
- unsigned long mapbase; /* for ioremap */
-+ struct device *dev; /* parent device */
- unsigned char hub6; /* this should be in the 8250 driver */
- unsigned char unused[3];
- };
---- linux-2.6.5/include/linux/vmalloc.h~heh 2004-04-03 22:38:23.000000000 -0500
-+++ linux-2.6.5/include/linux/vmalloc.h 2004-04-30 20:57:36.000000000 -0400
-@@ -35,6 +35,8 @@
- * Lowlevel-APIs (not for driver use!)
- */
- extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
-+extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
-+ unsigned long start, unsigned long end);
- extern struct vm_struct *remove_vm_area(void *addr);
- extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
- struct page ***pages);
---- linux-2.6.5/include/linux/mm.h~heh 2004-04-03 22:36:15.000000000 -0500
-+++ linux-2.6.5/include/linux/mm.h 2004-04-30 20:57:36.000000000 -0400
-@@ -655,5 +655,12 @@
- int in_gate_area(struct task_struct *task, unsigned long addr);
- #endif
-
-+#ifndef __arm__
-+#define memc_update_addr(x,y,z)
-+#define memc_update_mm(x)
-+#define memc_clear(x,y)
-+#endif
-+
- #endif /* __KERNEL__ */
- #endif /* _LINUX_MM_H */
-+
---- linux-2.6.5/init/do_mounts.c~heh 2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/init/do_mounts.c 2004-04-30 20:57:36.000000000 -0400
-@@ -391,7 +391,7 @@
- root_device_name += 5;
- }
-
-- is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
-+ is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR || MAJOR(ROOT_DEV) == 31;
-
- if (initrd_load())
- goto out;
---- linux-2.6.5/fs/binfmt_aout.c~heh 2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/fs/binfmt_aout.c 2004-04-30 20:57:36.000000000 -0400
-@@ -432,7 +432,11 @@
- else
- send_sig(SIGTRAP, current, 0);
- }
-+#ifndef __arm__
- return 0;
-+#else
-+ return regs->ARM_r0;
-+#endif
- }
-
- static int load_aout_library(struct file *file)
-@@ -462,8 +466,11 @@
-
- /* For QMAGIC, the starting address is 0x20 into the page. We mask
- this off to get the starting address for the page */
--
-- start_addr = ex.a_entry & 0xfffff000;
-+#ifndef __arm__
-+ start_addr = ex.a_entry & 0xfffff000;
-+#else
-+ start_addr = ex.a_entry & 0xffff8000;
-+#endif
-
- if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
- static unsigned long error_time;
---- linux-2.6.5/mm/slab.c~heh 2004-04-03 22:37:41.000000000 -0500
-+++ linux-2.6.5/mm/slab.c 2004-04-30 20:57:36.000000000 -0400
-@@ -2115,12 +2115,12 @@
- *
- * Called with disabled ints.
- */
--static inline void __cache_free (kmem_cache_t *cachep, void* objp)
-+static inline void __cache_free (kmem_cache_t *cachep, void* objp, void *caller)
- {
- struct array_cache *ac = ac_data(cachep);
-
- check_irq_off();
-- objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
-+ objp = cache_free_debugcheck(cachep, objp, caller /*__builtin_return_address(0)*/);
-
- if (likely(ac->avail < ac->limit)) {
- STATS_INC_FREEHIT(cachep);
-@@ -2289,7 +2289,7 @@
- unsigned long flags;
-
- local_irq_save(flags);
-- __cache_free(cachep, objp);
-+ __cache_free(cachep, objp, __builtin_return_address(0));
- local_irq_restore(flags);
- }
-
-@@ -2312,7 +2312,7 @@
- local_irq_save(flags);
- kfree_debugcheck(objp);
- c = GET_PAGE_CACHE(virt_to_page(objp));
-- __cache_free(c, (void*)objp);
-+ __cache_free(c, (void*)objp, __builtin_return_address(0));
- local_irq_restore(flags);
- }
-
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/Documentation/l3/structure 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,36 @@
-+L3 Bus Driver
-+-------------
-+
-+The structure of the driver is as follows:
-+
-+ +----------+ +----------+ +----------+
-+ | client 1 | | client 2 | | client 3 |
-+ +-----^----+ +----^-----+ +----^-----+
-+ | | |
-+ +-----v--------------v---------------v-----+
-+ | |
-+ +-----^-------+ +-------^-----+
-+ | | core | |
-+ +-----v----+ | | +----v-----+
-+ | device | | | | device |
-+ | driver 1 | | | | driver 2 |
-+ +-----^----+ | | +----^-----+
-+ | | services | |
-+ +-----v-------+ +-------v-----+
-+ | |
-+ +-----------------^----^-------------------+
-+ | |
-+ | +-v---------+
-+ | | algorithm |
-+ | | driver |
-+ | +-v---------+
-+ | |
-+ +-v----v-+
-+ | bus |
-+ | driver |
-+ +--------+
-+
-+Clients talk to the core to attach device drivers and bus adapters, and
-+to instruct device drivers to perform actions. Device drivers then talk
-+to the core to perform L3 bus transactions via the algorithm driver and
-+ultimately bus driver.
---- linux-2.6.5/arch/arm/kernel/debug.S~heh 2004-04-03 22:36:55.000000000 -0500
-+++ linux-2.6.5/arch/arm/kernel/debug.S 2004-04-30 20:57:36.000000000 -0400
-@@ -192,6 +192,20 @@
-
- @ if all ports are inactive, then there is nothing we can do
- moveq pc, lr
-+ ldr r1, [\rx, #UTCR2]
-+ teq r1, #5
-+ movne r1, #0
-+ strne r1, [\rx, #UTCR3]
-+ movne r1, #8
-+ strne r1, [\rx, #UTCR0]
-+ movne r1, #5
-+ strne r1, [\rx, #UTCR2]
-+ movne r1, #0
-+ strne r1, [\rx, #UTCR1]
-+ movne r1, #3
-+ strne r1, [\rx, #UTCR3]
-+ movne r1, #255
-+ strne r1, [\rx, #UTSR0]
- .endm
-
- .macro senduart,rd,rx
-@@ -287,7 +301,7 @@
-
- #elif defined(CONFIG_ARCH_INTEGRATOR)
-
--#include <asm/hardware/serial_amba.h>
-+#include <asm/hardware/amba_serial.h>
-
- .macro addruart,rx
- mrc p15, 0, \rx, c1, c0
-@@ -298,7 +312,7 @@
- .endm
-
- .macro senduart,rd,rx
-- strb \rd, [\rx, #AMBA_UARTDR]
-+ strb \rd, [\rx, #UART01x_DR]
- .endm
-
- .macro waituart,rd,rx
---- linux-2.6.5/arch/arm/kernel/entry-armv.S~heh 2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/arch/arm/kernel/entry-armv.S 2004-04-30 20:57:36.000000000 -0400
-@@ -1181,6 +1181,9 @@
- * get out of that mode without clobbering one register.
- */
- vector_FIQ: disable_fiq
-+ mrs r13, spsr
-+ orr r13, r13, #PSR_F_BIT
-+ msr spsr, r13
- subs pc, lr, #4
-
- /*=============================================================================
---- linux-2.6.5/arch/arm/kernel/irq.c~heh 2004-04-03 22:36:12.000000000 -0500
-+++ linux-2.6.5/arch/arm/kernel/irq.c 2004-04-30 20:57:36.000000000 -0400
-@@ -47,12 +47,36 @@
- #define MAX_IRQ_CNT 100000
-
- static volatile unsigned long irq_err_count;
--static spinlock_t irq_controller_lock;
- static LIST_HEAD(irq_pending);
-
- struct irqdesc irq_desc[NR_IRQS];
- void (*init_arch_irq)(void) __initdata = NULL;
-
-+#if NR_IRQ_DEVICES > 1
-+struct irq_device {
-+ spinlock_t lock;
-+ int nr_irqs;
-+ struct irq_desc *irqs;
-+};
-+
-+static struct irq_device irq_devices[NR_IRQ_DEVICES] = {
-+ [0] = {
-+ .lock = SPIN_LOCK_UNLOCKED,
-+ .nr_irqs = NR_IRQS,
-+ .irqs = irq_desc,
-+ },
-+};
-+#define IRQ_LOCK(irq) (&irq_devices[IRQ_DEVICE(irq)].lock)
-+#define IRQ_DESC(irq) (&irq_devices[IRQ_DEVICE(irq)].irqs[IRQ_INDEX(irq)])
-+#define IRQ_VALID(irq) (IRQ_DEVICE(irq) < NR_IRQ_DEVICES && \
-+ IRQ_INDEX(irq) < irq_devices[IRQ_DEVICE(irq)].nr_irqs)
-+#else
-+static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
-+#define IRQ_LOCK(irq) (&irq_controller_lock)
-+#define IRQ_DESC(irq) (&irq_desc[irq])
-+#define IRQ_VALID(irq) ((irq) < NR_IRQS)
-+#endif
-+
- /*
- * Dummy mask/unmask handler
- */
-@@ -95,13 +119,13 @@
- */
- void disable_irq(unsigned int irq)
- {
-- struct irqdesc *desc = irq_desc + irq;
-+ struct irqdesc *desc = IRQ_DESC(irq);
- unsigned long flags;
-
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- desc->disable_depth++;
- list_del_init(&desc->pend);
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- /**
-@@ -116,10 +140,10 @@
- */
- void enable_irq(unsigned int irq)
- {
-- struct irqdesc *desc = irq_desc + irq;
-+ struct irqdesc *desc = IRQ_DESC(irq);
- unsigned long flags;
-
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- if (unlikely(!desc->disable_depth)) {
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
-@@ -140,7 +164,7 @@
- list_add(&desc->pend, &irq_pending);
- }
- }
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- /*
-@@ -148,24 +172,24 @@
- */
- void enable_irq_wake(unsigned int irq)
- {
-- struct irqdesc *desc = irq_desc + irq;
-+ struct irqdesc *desc = IRQ_DESC(irq);
- unsigned long flags;
-
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- if (desc->chip->wake)
- desc->chip->wake(irq, 1);
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- void disable_irq_wake(unsigned int irq)
- {
-- struct irqdesc *desc = irq_desc + irq;
-+ struct irqdesc *desc = IRQ_DESC(irq);
- unsigned long flags;
-
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- if (desc->chip->wake)
- desc->chip->wake(irq, 0);
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- int show_interrupts(struct seq_file *p, void *v)
-@@ -175,8 +199,8 @@
- unsigned long flags;
-
- if (i < NR_IRQS) {
-- spin_lock_irqsave(&irq_controller_lock, flags);
-- action = irq_desc[i].action;
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
-+ action = IRQ_DESC(i)->action;
- if (!action)
- goto unlock;
-
-@@ -187,7 +211,7 @@
-
- seq_putc(p, '\n');
- unlock:
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- } else if (i == NR_IRQS) {
- #ifdef CONFIG_ARCH_ACORN
- show_fiq_list(p, v);
-@@ -259,7 +283,7 @@
- unsigned int status;
- int retval = 0;
-
-- spin_unlock(&irq_controller_lock);
-+ spin_unlock(IRQ_LOCK(irq));
-
- if (!(action->flags & SA_INTERRUPT))
- local_irq_enable();
-@@ -274,7 +298,7 @@
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
-
-- spin_lock_irq(&irq_controller_lock);
-+ spin_lock_irq(IRQ_LOCK(irq));
-
- return retval;
- }
-@@ -455,7 +479,7 @@
- desc = &bad_irq_desc;
-
- irq_enter();
-- spin_lock(&irq_controller_lock);
-+ spin_lock(IRQ_LOCK(irq));
- desc->handle(irq, desc, regs);
-
- /*
-@@ -464,7 +488,7 @@
- if (!list_empty(&irq_pending))
- do_pending_irqs(regs);
-
-- spin_unlock(&irq_controller_lock);
-+ spin_unlock(IRQ_LOCK(irq));
- irq_exit();
- }
-
-@@ -473,7 +497,7 @@
- struct irqdesc *desc;
- unsigned long flags;
-
-- if (irq >= NR_IRQS) {
-+ if (!IRQ_VALID(irq)) {
- printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq);
- return;
- }
-@@ -481,12 +505,12 @@
- if (handle == NULL)
- handle = do_bad_IRQ;
-
-- desc = irq_desc + irq;
-+ desc = IRQ_DESC(irq);
-
- if (is_chained && desc->chip == &bad_chip)
- printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq);
-
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- if (handle == do_bad_IRQ) {
- desc->chip->mask(irq);
- desc->chip->ack(irq);
-@@ -499,7 +523,7 @@
- desc->disable_depth = 0;
- desc->chip->unmask(irq);
- }
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- void set_irq_chip(unsigned int irq, struct irqchip *chip)
-@@ -507,7 +531,7 @@
- struct irqdesc *desc;
- unsigned long flags;
-
-- if (irq >= NR_IRQS) {
-+ if (!IRQ_VALID(irq)) {
- printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
- return;
- }
-@@ -515,10 +539,10 @@
- if (chip == NULL)
- chip = &bad_chip;
-
-- desc = irq_desc + irq;
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ desc = IRQ_DESC(irq);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- desc->chip = chip;
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- int set_irq_type(unsigned int irq, unsigned int type)
-@@ -527,16 +551,21 @@
- unsigned long flags;
- int ret = -ENXIO;
-
-- if (irq >= NR_IRQS) {
-+ if (!IRQ_VALID(irq)) {
- printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
- return -ENODEV;
- }
-
-- desc = irq_desc + irq;
-+ desc = IRQ_DESC(irq);
-+ if (!desc->action && desc->handle != do_bad_IRQ) {
-+ printk(KERN_ERR "Setting type of unclaimed IRQ%d from ", irq);
-+ print_symbol("%s\n", (unsigned long)__builtin_return_address(0));
-+ }
-+
- if (desc->chip->type) {
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- ret = desc->chip->type(irq, type);
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- return ret;
-@@ -547,17 +576,17 @@
- struct irqdesc *desc;
- unsigned long flags;
-
-- if (irq >= NR_IRQS) {
-+ if (!IRQ_VALID(irq)) {
- printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
- return;
- }
-
-- desc = irq_desc + irq;
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ desc = IRQ_DESC(irq);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- desc->valid = (iflags & IRQF_VALID) != 0;
- desc->probe_ok = (iflags & IRQF_PROBE) != 0;
- desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0;
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- }
-
- int setup_irq(unsigned int irq, struct irqaction *new)
-@@ -587,13 +616,13 @@
- /*
- * The following block of code has to be executed atomically
- */
-- desc = irq_desc + irq;
-- spin_lock_irqsave(&irq_controller_lock, flags);
-+ desc = IRQ_DESC(irq);
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- return -EBUSY;
- }
-
-@@ -618,7 +647,7 @@
- }
- }
-
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
- return 0;
- }
-
-@@ -659,7 +688,7 @@
- unsigned long retval;
- struct irqaction *action;
-
-- if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
-+ if (!IRQ_VALID(irq) || !IRQ_DESC(irq)->valid || !handler ||
- (irq_flags & SA_SHIRQ && !dev_id))
- return -EINVAL;
-
-@@ -700,14 +729,14 @@
- struct irqaction * action, **p;
- unsigned long flags;
-
-- if (irq >= NR_IRQS || !irq_desc[irq].valid) {
-+ if (!IRQ_VALID(irq) || !IRQ_DESC(irq)->valid) {
- printk(KERN_ERR "Trying to free IRQ%d\n",irq);
- dump_stack();
- return;
- }
-
-- spin_lock_irqsave(&irq_controller_lock, flags);
-- for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
-+ spin_lock_irqsave(IRQ_LOCK(irq), flags);
-+ for (p = &IRQ_DESC(irq)->action; (action = *p) != NULL; p = &action->next) {
- if (action->dev_id != dev_id)
- continue;
-
-@@ -715,7 +744,7 @@
- *p = action->next;
- break;
- }
-- spin_unlock_irqrestore(&irq_controller_lock, flags);
-+ spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
-
- if (!action) {
- printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
-@@ -747,19 +776,18 @@
- * first snaffle up any unassigned but
- * probe-able interrupts
- */
-- spin_lock_irq(&irq_controller_lock);
- for (i = 0; i < NR_IRQS; i++) {
-- if (!irq_desc[i].probe_ok || irq_desc[i].action)
-- continue;
--
-- irq_desc[i].probing = 1;
-- irq_desc[i].triggered = 0;
-- if (irq_desc[i].chip->type)
-- irq_desc[i].chip->type(i, IRQT_PROBE);
-- irq_desc[i].chip->unmask(i);
-- irqs += 1;
-+ spin_lock_irq(IRQ_LOCK(i));
-+ if (irq_desc[i].probe_ok && !irq_desc[i].action) {
-+ irq_desc[i].probing = 1;
-+ irq_desc[i].triggered = 0;
-+ if (irq_desc[i].chip->type)
-+ irq_desc[i].chip->type(i, IRQT_PROBE);
-+ irq_desc[i].chip->unmask(i);
-+ irqs += 1;
-+ }
-+ spin_unlock_irq(IRQ_LOCK(i));
- }
-- spin_unlock_irq(&irq_controller_lock);
-
- /*
- * wait for spurious interrupts to mask themselves out again
-@@ -770,14 +798,14 @@
- /*
- * now filter out any obviously spurious interrupts
- */
-- spin_lock_irq(&irq_controller_lock);
- for (i = 0; i < NR_IRQS; i++) {
-+ spin_lock_irq(IRQ_LOCK(i));
- if (irq_desc[i].probing && irq_desc[i].triggered) {
- irq_desc[i].probing = 0;
- irqs -= 1;
- }
-+ spin_unlock_irq(IRQ_LOCK(i));
- }
-- spin_unlock_irq(&irq_controller_lock);
-
- return irqs;
- }
-@@ -788,11 +816,13 @@
- {
- unsigned int mask = 0, i;
-
-- spin_lock_irq(&irq_controller_lock);
-- for (i = 0; i < 16 && i < NR_IRQS; i++)
-- if (irq_desc[i].probing && irq_desc[i].triggered)
-+ for (i = 0; i < 16 && i < NR_IRQS; i++) {
-+ struct irqdesc *desc = IRQ_DESC(i);
-+ spin_lock_irq(IRQ_LOCK(i));
-+ if (desc->probing && desc->triggered)
- mask |= 1 << i;
-- spin_unlock_irq(&irq_controller_lock);
-+ spin_unlock_irq(IRQ_LOCK(i));
-+ }
-
- up(&probe_sem);
-
-@@ -813,23 +843,21 @@
- * look at the interrupts, and find exactly one
- * that we were probing has been triggered
- */
-- spin_lock_irq(&irq_controller_lock);
- for (i = 0; i < NR_IRQS; i++) {
-- if (irq_desc[i].probing &&
-- irq_desc[i].triggered) {
-+ struct irqdesc *desc = IRQ_DESC(i);
-+
-+ spin_lock_irq(IRQ_LOCK(i));
-+ if (desc->probing && desc->triggered) {
- if (irq_found != NO_IRQ) {
-+ spin_unlock_irq(IRQ_LOCK(i));
- irq_found = NO_IRQ;
-- goto out;
-+ break;
- }
- irq_found = i;
- }
-+ spin_unlock_irq(IRQ_LOCK(i));
- }
-
-- if (irq_found == -1)
-- irq_found = NO_IRQ;
--out:
-- spin_unlock_irq(&irq_controller_lock);
--
- up(&probe_sem);
-
- return irq_found;
---- linux-2.6.5/arch/arm/kernel/bios32.c~heh 2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/arch/arm/kernel/bios32.c 2004-04-30 20:57:36.000000000 -0400
-@@ -565,8 +565,6 @@
- if (hw->postinit)
- hw->postinit();
-
-- pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
--
- list_for_each_entry(sys, &hw->buses, node) {
- struct pci_bus *bus = sys->bus;
-
-@@ -581,6 +579,11 @@
- pci_bus_assign_resources(bus);
-
- /*
-+ * Fixup IRQs.
-+ */
-+ pci_bus_fixup_irqs(bus, pcibios_swizzle, pcibios_map_irq);
-+
-+ /*
- * Tell drivers about devices found.
- */
- pci_bus_add_devices(bus);
---- linux-2.6.5/arch/arm/kernel/traps.c~heh 2004-04-03 22:36:57.000000000 -0500
-+++ linux-2.6.5/arch/arm/kernel/traps.c 2004-04-30 20:57:36.000000000 -0400
-@@ -206,33 +206,43 @@
- c_backtrace(fp, 0x10);
- }
-
--spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
--
--/*
-- * This function is protected against re-entrancy.
-- */
--NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
-+static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
- {
-- struct task_struct *tsk = current;
-+ struct task_struct *tsk = thread->task;
- static int die_counter;
-
-- console_verbose();
-- spin_lock_irq(&die_lock);
-- bust_spinlocks(1);
--
- printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter);
- print_modules();
- printk("CPU: %d\n", smp_processor_id());
- show_regs(regs);
- printk("Process %s (pid: %d, stack limit = 0x%p)\n",
-- tsk->comm, tsk->pid, tsk->thread_info + 1);
-+ tsk->comm, tsk->pid, thread + 1);
-
- if (!user_mode(regs) || in_interrupt()) {
- dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info);
- dump_backtrace(regs, tsk);
- dump_instr(regs);
- }
-+}
-+
-+void nmi_watchdog(struct thread_info *thread, struct pt_regs *regs)
-+{
-+ __die("NMI watchdog", 0, thread, regs);
-+}
-
-+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
-+
-+/*
-+ * This function is protected against re-entrancy.
-+ */
-+NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
-+{
-+ struct thread_info *thread = current_thread_info();
-+
-+ console_verbose();
-+ spin_lock_irq(&die_lock);
-+ bust_spinlocks(1);
-+ __die(str, err, thread, regs);
- bust_spinlocks(0);
- spin_unlock_irq(&die_lock);
- do_exit(SIGSEGV);
---- linux-2.6.5/arch/arm/Kconfig~heh 2004-04-03 22:37:07.000000000 -0500
-+++ linux-2.6.5/arch/arm/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -297,7 +297,7 @@
-
- config CPU_FREQ
- bool "Support CPU clock change (EXPERIMENTAL)"
-- depends on (ARCH_SA1100 || ARCH_INTEGRATOR) && EXPERIMENTAL
-+ depends on (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_PXA) && EXPERIMENTAL
- help
- CPU clock scaling allows you to change the clock speed of the
- running CPU on the fly. This is a nice method to save battery power,
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/fastfpe/entry.S 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,294 @@
-+/*
-+At entry the registers contain the following information:
-+
-+r14 return address for undefined exception return
-+r9 return address for return from exception
-+r13 user registers on stack, offset 0 up to offset 4*15 contains
-+ registers r0..15, then the psr
-+r10 FP workspace 35 words (init, reg[8][4], fpsr, fpcr)
-+
-+*/
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .data
-+fp_const:
-+ .word 0, 0x00000000, 0, 0x80000000 @ 0
-+ .word 0, 0x80000000, 0, 0 @ 1
-+ .word 0, 0x80000000, 0, 1 @ 2
-+ .word 0, 0xc0000000, 0, 1 @ 3
-+ .word 0, 0x80000000, 0, 2 @ 4
-+ .word 0, 0xa0000000, 0, 2 @ 5
-+ .word 0, 0x80000000, 0, -1 @ 0.5
-+ .word 0, 0xa0000000, 0, 3 @ 10
-+fp_undef:
-+ .word 0
-+fp_cond:
-+ .word 0xf0f0 @ eq
-+ .word 0x0f0f @ ne
-+ .word 0xcccc @ cs
-+ .word 0x3333 @ cc
-+ .word 0xff00 @ mi
-+ .word 0x00ff @ pl
-+ .word 0xaaaa @ vs
-+ .word 0x5555 @ vc
-+ .word 0x0c0c @ hi
-+ .word 0xf3f3 @ ls
-+ .word 0xaa55 @ ge
-+ .word 0x55aa @ lt
-+ .word 0x0a05 @ gt
-+ .word 0xf5fa @ le
-+ .word 0xffff @ al
-+ .word 0x0000 @ nv
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .text
-+ .globl fastfpe_enter
-+fastfpe_enter:
-+ ldr r4,=fp_undef
-+ str r14,[r4] @ to free one register
-+ add r10,r10,#4 @ to make the code simpler
-+ mov r4, r0 @ r4=trapped instruction
-+ and r1,r4,#0x00000f00 @ r1=coprocessor << 8
-+next_enter:
-+ cmp r1,#1<<8 @ copro 1 ?
-+ beq copro_1
-+ cmp r1,#2<<8
-+ movne pc,r14
-+
-+copro_2:
-+ and r1,r4,#0x0f000000
-+ cmp r1,#0x0c000000 @ CPDT with post indexing
-+ cmpne r1,#0x0d000000 @ CPDT with pre indexing
-+ beq CPDT_M_enter
-+ mov pc,r14
-+
-+copro_1:
-+ and r1,r4,#0x0f000000
-+ cmp r1,#0x0e000000 @ CPDO
-+ beq CPDO_CPRT_enter
-+ cmp r1,#0x0c000000 @ CPDT with post indexing
-+ cmpne r1,#0x0d000000 @ CPDT with pre indexing
-+ beq CPDT_1_enter
-+ mov pc,r14
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl fastfpe_next
-+fastfpe_next:
-+ ldr r5,[r13,#60]
-+next_after_cond:
-+__x1:
-+ ldrt r4,[r5],#4
-+
-+ ldr r0,=fp_cond @ check condition of next instruction
-+ ldr r1,[r13,#64] @ psr containing flags
-+ mov r2,r4,lsr#28
-+ mov r1,r1,lsr#28
-+ ldr r0,[r0,r2,lsl#2]
-+ mov r0,r0,lsr r1
-+ tst r0,#1
-+ beq next_after_cond @ must not necessarily have been an
-+ @ FP instruction !
-+ and r1,r4,#0x0f000000 @ Test for copro instruction
-+ cmp r1,#0x0c000000
-+ rsbgts r0,r1,#0x0e000000 @ cmpgt #0x0e000000,r1
-+ movlt pc,r9 @ next is no copro instruction, return
-+
-+ ands r1,r4,#0x00000f00 @ r1 = coprocessor << 8
-+ cmpne r1,#3<<8
-+ movge pc,r9 @ copro = 0 or >=3, return
-+
-+ str r5,[r13,#60] @ save updated pc
-+ b next_enter
-+
-+/*---------------------------------------------------------------------------*/
-+
-+undefined:
-+ ldr r4,=fp_undef
-+ ldr pc,[r4]
-+
-+/*---------------------------------------------------------------------------*/
-+
-+CPDT_1_enter:
-+ and r5,r4,#0x000f0000 @ r5=base register number << 16
-+ ldr r6,[r13,r5,lsr#14] @ r6=base address
-+ cmp r5,#0x000f0000 @ base register = pc ?
-+ addeq r6,r6,#4
-+ and r7,r4,#0x000000ff @ r7=offset value
-+
-+ tst r4,#0x00800000 @ up or down?
-+ addne r7,r6,r7,lsl#2
-+ subeq r7,r6,r7,lsl#2 @ r6=base address +/- offset
-+ tst r4,#0x01000000 @ preindexing ?
-+ movne r6,r7
-+ tst r4,#0x00200000 @ write back ?
-+ cmpne r5,#0x000f0000 @ base register = pc ?
-+ strne r7,[r13,r5,lsr#14]
-+
-+ and r0,r4,#0x00007000 @ r0=fp register number << 12
-+ add r0,r10,r0,lsr#8 @ r0=address of fp register
-+ mov r1,#0
-+ tst r4,#0x00008000
-+ orrne r1,r1,#1 @ T0
-+ tst r4,#0x00400000
-+ orrne r1,r1,#2 @ T1
-+ tst r4,#0x00100000
-+ orrne r1,r1,#4 @ L/S
-+
-+ add pc,pc,r1,lsl#2
-+ mov r0,r0
-+ b CPDT_store_single @ these functions get
-+ b CPDT_store_double @ r0=address of fp register
-+ b CPDT_store_extended @ r6=address of data
-+ b undefined @ CPDT_store_decimal
-+ b CPDT_load_single
-+ b CPDT_load_double
-+ b CPDT_load_extended
-+ b undefined @ CPDT_load_decimal
-+
-+/*---------------------------------------------------------------------------*/
-+
-+CPDT_M_enter:
-+ and r5,r4,#0x000f0000 @ r5=base register number << 16
-+ ldr r6,[r13,r5,lsr#14] @ r6=base address
-+ cmp r5,#0x000f0000 @ base register = pc ?
-+ addeq r6,r6,#4
-+ and r7,r4,#0x000000ff @ r7=offset value
-+
-+ tst r4,#0x00800000 @ up or down?
-+ addne r7,r6,r7,lsl#2
-+ subeq r7,r6,r7,lsl#2 @ r7=base address +/- offset
-+ tst r4,#0x01000000 @ preindexing ?
-+ movne r6,r7
-+ tst r4,#0x00200000 @ write back ?
-+ cmpne r5,#0x000f0000 @ base register = pc ?
-+ strne r7,[r13,r5,lsr#14]
-+
-+ and r0,r4,#0x00007000 @ r0=fp register number << 12
-+ and r1,r4,#0x00008000
-+ mov r1,r1,lsr#15 @ N0
-+ and r2,r4,#0x00400000
-+ orrs r1,r1,r2,lsr#21 @ N1
-+ addeq r1,r1,#4 @ r1=register count
-+
-+ tst r4,#0x00100000 @ load/store
-+ beq CPDT_sfm
-+ b CPDT_lfm
-+
-+/*---------------------------------------------------------------------------*/
-+
-+CPDO_CPRT_enter:
-+ tst r4,#0x00000010
-+ bne CPRT_enter
-+
-+ and r0,r4,#0x00007000
-+ add r0,r10,r0,lsr#8 @ r0=address of Fd
-+ and r1,r4,#0x00070000
-+ add r1,r10,r1,lsr#12 @ r1=address of Fn
-+ tst r4,#0x00000008
-+ bne CPDO_const
-+ and r2,r4,#0x00000007
-+ add r2,r10,r2,lsl#4 @ r2=address of Fm
-+
-+CPDO_constback:
-+ and r3,r4,#0x00f00000
-+ tst r4,#0x00008000
-+ orrne r3,r3,#0x01000000
-+
-+ add pc,pc,r3,lsr#18
-+ mov r0,r0
-+ b CPDO_adf
-+ b CPDO_muf
-+ b CPDO_suf
-+ b CPDO_rsf
-+ b CPDO_dvf
-+ b CPDO_rdf
-+ b undefined
-+ b undefined
-+ b undefined @ CPDO_rmf
-+ b CPDO_muf
-+ b CPDO_dvf
-+ b CPDO_rdf
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b CPDO_mvf
-+ b CPDO_mnf
-+ b CPDO_abs
-+ b CPDO_rnd
-+ b CPDO_sqt
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b CPDO_rnd
-+ b fastfpe_next
-+
-+CPDO_const:
-+ ldr r2,=fp_const
-+ and r3,r4,#0x00000007
-+ add r2,r2,r3,lsl#4
-+ b CPDO_constback
-+
-+/*---------------------------------------------------------------------------*/
-+
-+CPRT_enter:
-+ and r0,r4,#0x0000f000 @ r0=Rd<<12
-+ and r1,r4,#0x00070000
-+ add r1,r10,r1,lsr#12 @ r1=address of Fn
-+ tst r4,#0x00000008
-+ bne CPRT_const
-+ and r2,r4,#0x00000007
-+ add r2,r10,r2,lsl#4 @ r2=address of Fm
-+
-+CPRT_constback:
-+ and r3,r4,#0x00f00000
-+
-+ add pc,pc,r3,lsr#18
-+ mov r0,r0
-+ b CPRT_flt
-+ b CPRT_fix
-+ b CPRT_wfs
-+ b CPRT_rfs
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b undefined
-+ b CPRT_cmf
-+ b undefined
-+ b CPRT_cnf
-+ b undefined
-+ b CPRT_cmf
-+ b undefined
-+ b CPRT_cnf
-+
-+CPRT_const:
-+ ldr r2,=fp_const
-+ and r3,r4,#0x00000007
-+ add r2,r2,r3,lsl#4
-+ b CPRT_constback
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ @ The fetch of the next instruction to emulate could fault
-+
-+ .section .fixup,"ax"
-+ .align
-+__f1:
-+ mov pc,r9
-+ .previous
-+ .section __ex_table,"a"
-+ .align 3
-+ .long __x1,__f1
-+ .previous
-+
-+/*---------------------------------------------------------------------------*/
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/fastfpe/module.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,62 @@
-+/*
-+ Fast Floating Point Emulator
-+ (c) Peter Teichmann <mail@peter-teichmann.de>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+
-+#ifndef MODULE
-+#define kern_fp_enter fp_enter
-+
-+extern char fpe_type[];
-+#endif
-+
-+static void (*orig_fp_enter)(void); /* old kern_fp_enter value */
-+extern void (*kern_fp_enter)(void); /* current FP handler */
-+extern void fastfpe_enter(void); /* forward declarations */
-+
-+static int __init fpe_init(void)
-+{
-+ if (fpe_type[0] && strcmp(fpe_type, "fastfpe"))
-+ return 0;
-+
-+ printk("Fast Floating Point Emulator V0.9 (c) Peter Teichmann.\n");
-+
-+ /* Save pointer to the old FP handler and then patch ourselves in */
-+ orig_fp_enter = kern_fp_enter;
-+ kern_fp_enter = fastfpe_enter;
-+
-+ return 0;
-+}
-+
-+static void __exit fpe_exit(void)
-+{
-+ /* Restore the values we saved earlier. */
-+ kern_fp_enter = orig_fp_enter;
-+}
-+
-+module_init(fpe_init);
-+module_exit(fpe_exit);
-+
-+MODULE_AUTHOR("Peter Teichmann <mail@peter-teichmann.de>");
-+MODULE_DESCRIPTION("Fast floating point emulator with full precision");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/fastfpe/CPDO.S 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,682 @@
-+/*
-+The FP structure has 4 words reserved for each register, the first is used just
-+for the sign in bit 31, the second and third are for the mantissa (unsigned
-+integer, high 32 bit first) and the fourth is the exponent (signed integer).
-+The mantissa is always normalized.
-+
-+If the exponent is 0x80000000, that is the most negative value, the number
-+represented is 0 and both mantissa words are also 0.
-+
-+If the exponent is 0x7fffffff, that is the biggest positive value, the number
-+represented is infinity if the high 32 mantissa bit are also 0, otherwise it is
-+a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
-+
-+Decimal and packed decimal numbers are not supported yet.
-+
-+The parameters to these functions are r0=destination pointer, r1 and r2
-+source pointers. r4 is the instruction. They may use r0-r8 and r14. They return
-+to fastfpe_next, except CPDO_rnf_core which expects the return address in r14.
-+*/
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_adf
-+CPDO_adf:
-+ ldmia r1,{r1,r3,r5,r7}
-+ ldmia r2,{r2,r4,r6,r8}
-+
-+ cmp r7,#0x7fffffff
-+ cmpne r8,#0x7fffffff
-+ beq CPDO_adf_extra
-+
-+ cmp r1,r2
-+ bne CPDO_suf_s
-+
-+CPDO_adf_s:
-+ subs r2,r7,r8
-+ bge CPDO_adf_2nd
-+
-+ mov r7,r8
-+ rsb r2,r2,#0
-+ cmp r2,#32
-+ ble CPDO_adf_1st2
-+
-+ sub r2,r2,#32
-+ cmp r2,#32
-+ movgt r2,#32
-+ mov r5,r3,lsr r2
-+ mov r3,#0
-+ b CPDO_adf_add
-+
-+CPDO_adf_1st2:
-+ rsb r8,r2,#32
-+ mov r5,r5,lsr r2
-+ orr r5,r5,r3,lsl r8
-+ mov r3,r3,lsr r2 @ 1. op normalized
-+ b CPDO_adf_add
-+
-+CPDO_adf_2nd:
-+ cmp r2,#32
-+ ble CPDO_adf_2nd2
-+
-+ sub r2,r2,#32
-+ cmp r2,#32
-+ movgt r2,#32
-+ mov r6,r4,lsr r2
-+ mov r4,#0
-+ b CPDO_adf_add
-+
-+CPDO_adf_2nd2:
-+ rsb r8,r2,#32
-+ mov r6,r6,lsr r2
-+ orr r6,r6,r4,lsl r8
-+ mov r4,r4,lsr r2 @ 2. op normalized
-+
-+CPDO_adf_add:
-+ adds r5,r5,r6
-+ adcs r3,r3,r4 @ do addition
-+ bcc CPDO_adf_end
-+
-+ add r7,r7,#1
-+ movs r3,r3,rrx
-+ mov r5,r5,rrx @ correct for overflow
-+
-+CPDO_adf_end:
-+ cmp r7,#0x20000000
-+ bge CPDO_inf
-+
-+ stmia r0,{r1,r3,r5,r7}
-+ b fastfpe_next
-+
-+CPDO_adf_extra:
-+ cmp r7,#0x7fffffff @ was it the 1st ?
-+ bne CPDO_infnan_2 @ no it was the 2nd
-+ cmp r8,#0x7fffffff @ if 1st, 2nd too ?
-+ bne CPDO_infnan_1 @ no only 1st
-+ cmp r3,#0
-+ cmpeq r4,#0
-+ bne CPDO_nan_12
-+ b CPDO_inf
-+
-+/*---------------------------------------------------------------------------*/
-+
-+CPDO_infnan_1:
-+ stmia r0,{r1,r3,r5,r7}
-+ b fastfpe_next
-+
-+CPDO_infnan_2:
-+ stmia r0,{r2,r4,r6,r8}
-+ b fastfpe_next
-+
-+CPDO_nan_12:
-+ orr r2,r3,r4
-+ b CPDO_inf_1
-+
-+CPDO_nan:
-+ mov r2,#0x40000000 @ create non signalling NaN
-+ b CPDO_inf_1
-+
-+CPDO_inf:
-+ mov r2,#0
-+CPDO_inf_1:
-+ mov r3,#0
-+ mov r4,#0x7fffffff
-+CPDO_store_1234:
-+ stmia r0,{r1,r2,r3,r4}
-+ b fastfpe_next
-+
-+CPDO_zero:
-+ mov r1,#0
-+CPDO_zero_1:
-+ mov r2,#0
-+ mov r3,#0
-+ mov r4,#0x80000000
-+ stmia r0,{r1,r2,r3,r4}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_suf
-+CPDO_suf:
-+ ldmia r1,{r1,r3,r5,r7}
-+ ldmia r2,{r2,r4,r6,r8}
-+
-+CPDO_suf_l:
-+ cmp r7,#0x7fffffff
-+ cmpne r8,#0x7fffffff
-+ beq CPDO_suf_extra
-+
-+ cmp r1,r2
-+ bne CPDO_adf_s
-+
-+CPDO_suf_s:
-+ subs r2,r7,r8 @ determine greater number
-+ bgt CPDO_suf_2nd @ first number is greater
-+ blt CPDO_suf_1st @ second number is greater
-+ cmp r3,r4 @ also mantissa is important
-+ cmpeq r5,r6
-+ bhi CPDO_suf_2nd @ first number is greater
-+ beq CPDO_zero
-+
-+CPDO_suf_1st:
-+ eor r1,r1,#0x80000000 @ second number is greater, invert sign
-+ mov r7,r8
-+ rsb r2,r2,#0
-+ cmp r2,#32
-+ ble CPDO_suf_1st2
-+
-+ sub r2,r2,#32
-+ cmp r2,#32
-+ movgt r2,#32
-+ mov r5,r3,lsr r2
-+ mov r3,#0
-+ b CPDO_suf_1st_sub
-+
-+CPDO_suf_1st2:
-+ rsb r8,r2,#32
-+ mov r5,r5,lsr r2
-+ orr r5,r5,r3,lsl r8
-+ mov r3,r3,lsr r2 @ 1. op normalized
-+
-+CPDO_suf_1st_sub:
-+ subs r5,r6,r5 @ do subtraction
-+ sbc r3,r4,r3
-+ b CPDO_suf_norm
-+
-+CPDO_suf_2nd:
-+ cmp r2,#32
-+ ble CPDO_suf_2nd2
-+
-+ sub r2,r2,#32
-+ cmp r2,#32
-+ movgt r2,#32
-+ mov r6,r4,lsr r2
-+ mov r4,#0
-+ b CPDO_suf_2nd_sub
-+
-+CPDO_suf_2nd2:
-+ rsb r8,r2,#32
-+ mov r6,r6,lsr r2
-+ orr r6,r6,r4,lsl r8
-+ mov r4,r4,lsr r2 @ 2. op normalized
-+
-+CPDO_suf_2nd_sub:
-+ subs r5,r5,r6
-+ sbc r3,r3,r4 @ do subtraction
-+
-+CPDO_suf_norm:
-+ teq r3,#0 @ normalize 32bit
-+ moveq r3,r5
-+ moveq r5,#0
-+ subeq r7,r7,#32
-+
-+ cmp r3,#0x00010000 @ 16bit
-+ movcc r3,r3,lsl#16
-+ orrcc r3,r3,r5,lsr#16
-+ movcc r5,r5,lsl#16
-+ subcc r7,r7,#16
-+
-+ cmp r3,#0x01000000 @ 8bit
-+ movcc r3,r3,lsl#8
-+ orrcc r3,r3,r5,lsr#24
-+ movcc r5,r5,lsl#8
-+ subcc r7,r7,#8
-+
-+ cmp r3,#0x10000000 @ 4bit
-+ movcc r3,r3,lsl#4
-+ orrcc r3,r3,r5,lsr#28
-+ movcc r5,r5,lsl#4
-+ subcc r7,r7,#4
-+
-+ cmp r3,#0x40000000 @ 2bit
-+ movcc r3,r3,lsl#2
-+ orrcc r3,r3,r5,lsr#30
-+ movcc r5,r5,lsl#2
-+ subcc r7,r7,#2
-+
-+ cmp r3,#0x80000000 @ 1bit
-+ movcc r3,r3,lsl#1
-+ orrcc r3,r3,r5,lsr#31
-+ movcc r5,r5,lsl#1
-+ subcc r7,r7,#1
-+
-+ cmp r7,#0xe0000000
-+ ble CPDO_zero_1
-+
-+ stmia r0,{r1,r3,r5,r7}
-+ b fastfpe_next
-+
-+CPDO_suf_extra:
-+ cmp r7,#0x7fffffff @ was it the 1st ?
-+ eorne r2,r2,#0x80000000 @ change sign, might have been INF
-+ bne CPDO_infnan_2 @ no it was the 2nd
-+ cmp r8,#0x7fffffff @ if 1st, 2nd too ?
-+ bne CPDO_infnan_1 @ no only 1st
-+ cmp r3,#0
-+ cmpeq r4,#0
-+ bne CPDO_nan_12
-+ b CPDO_nan @ here is difference with adf !
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_rsf
-+CPDO_rsf:
-+ mov r3,r2
-+ ldmia r1,{r2,r4,r6,r8}
-+ ldmia r3,{r1,r3,r5,r7}
-+ b CPDO_suf_l
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_muf
-+CPDO_muf:
-+ ldmia r1,{r1,r3,r5,r7}
-+ ldmia r2,{r2,r4,r6,r8}
-+
-+ cmp r7,#0x7fffffff
-+ cmpne r8,#0x7fffffff
-+ beq CPDO_muf_extra
-+
-+ eor r1,r1,r2
-+ adds r8,r7,r8
-+ bvs CPDO_zero_1
-+
-+ umull r7,r2,r3,r4
-+ umull r14,r3,r6,r3
-+ adds r7,r7,r3 @ r2|r7|r14 = r2|r7|#0 + #0|r3|r14
-+ adc r2,r2,#0
-+ umull r4,r3,r5,r4
-+ adds r14,r14,r4 @ r2|r7|r14 += #0|r3|r4
-+ adcs r7,r7,r3
-+ adc r2,r2,#0
-+ umull r4,r3,r5,r6
-+ adds r14,r14,r3 @ r2|r7|r14 += #0|#0|r3
-+ adcs r7,r7,#0
-+ adcs r2,r2,#0
-+
-+ bpl CPDO_muf_norm
-+
-+ add r8,r8,#1
-+ b CPDO_muf_end
-+
-+CPDO_muf_norm:
-+ adds r14,r14,r14
-+ adcs r7,r7,r7
-+ adcs r2,r2,r2
-+
-+CPDO_muf_end:
-+ cmp r8,#0x20000000
-+ bge CPDO_inf
-+ cmp r8,#0xe0000000
-+ ble CPDO_zero_1
-+ stmia r0,{r1,r2,r7,r8}
-+ b fastfpe_next
-+
-+CPDO_muf_extra:
-+ cmp r7,#0x7fffffff @ was it the first?
-+ bne CPDO_muf_extra_2nd @ no, so it was the second
-+ cmp r8,#0x7fffffff @ yes, second too?
-+ bne CPDO_muf_extra_1st @ no, only first
-+ orr r3,r3,r4 @ if both inf -> inf, otherwise nan
-+ eor r1,r1,r2 @ sign for the inf case
-+ b CPDO_infnan_1
-+
-+CPDO_muf_extra_1st:
-+ cmp r3,#0 @ is it a nan?
-+ bne CPDO_infnan_1
-+ cmp r8,#0x80000000 @ is the second 0?
-+ beq CPDO_nan
-+ eor r1,r1,r2 @ correct sign for inf
-+ b CPDO_inf
-+
-+CPDO_muf_extra_2nd:
-+ cmp r4,#0 @ is it a nan?
-+ bne CPDO_infnan_2
-+ cmp r7,#0x80000000 @ is the first 0?
-+ beq CPDO_nan
-+ eor r1,r1,r2 @ correct sign for inf
-+ b CPDO_inf
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_dvf
-+CPDO_dvf:
-+ ldmia r1,{r1,r3,r5,r7}
-+ ldmia r2,{r2,r4,r6,r8}
-+
-+CPDO_dvf_l:
-+ cmp r7,#0x7fffffff
-+ cmpne r8,#0x7fffffff
-+ beq CPDO_dvf_extra
-+ cmp r8,#0x80000000
-+ beq CPDO_dvf_by0
-+
-+ eor r1,r1,r2
-+ cmp r7,#0x80000000
-+ beq CPDO_zero_1
-+
-+ sub r8,r7,r8
-+
-+ mov r2,#0
-+ mov r7,#1
-+
-+ cmp r3,r4
-+ cmpeq r5,r6
-+ bcs CPDO_dvf_loop_
-+
-+ sub r8,r8,#1
-+
-+CPDO_dvf_loop:
-+ adds r5,r5,r5
-+ adcs r3,r3,r3
-+ bcs CPDO_dvf_anyway
-+CPDO_dvf_loop_:
-+ subs r5,r5,r6
-+ sbcs r3,r3,r4
-+ bcs CPDO_dvf_okay
-+
-+ adds r5,r5,r6
-+ adc r3,r3,r4
-+ adds r7,r7,r7
-+ adcs r2,r2,r2
-+ bcc CPDO_dvf_loop
-+ b CPDO_dvf_end
-+
-+CPDO_dvf_anyway:
-+ adcs r7,r7,r7
-+ adcs r2,r2,r2
-+ bcs CPDO_dvf_end
-+ subs r5,r5,r6
-+ sbc r3,r3,r4
-+ b CPDO_dvf_loop
-+
-+CPDO_dvf_okay:
-+ adcs r7,r7,r7
-+ adcs r2,r2,r2
-+ bcc CPDO_dvf_loop
-+
-+CPDO_dvf_end:
-+ b CPDO_muf_end
-+
-+CPDO_dvf_by0:
-+ cmp R7,#0x80000000
-+ beq CPDO_nan @ first also 0 -> nan
-+ eor r1,r1,r2 @ otherwise calculatesign for inf
-+ b CPDO_inf
-+
-+CPDO_dvf_extra:
-+ cmp r7,#0x7fffffff @ was it the first?
-+ bne CPDO_dvf_extra_2nd @ no, so it was the second
-+ cmp r8,#0x7fffffff @ yes, second too?
-+ bne CPDO_dvf_extra_1st @ no, only first
-+ orrs r3,r3,r4
-+ beq CPDO_nan @ if both inf -> create nan
-+ b CPDO_nan_12 @ otherwise keep nan
-+
-+CPDO_dvf_extra_1st:
-+ eor r1,r1,r2 @ correct sign for inf
-+ b CPDO_infnan_1
-+
-+CPDO_dvf_extra_2nd:
-+ cmp r4,#0 @ is it a nan?
-+ bne CPDO_infnan_2
-+ eor r1,r1,r2 @ correct sign for zero
-+ b CPDO_zero_1
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_rdf
-+CPDO_rdf:
-+ mov r3,r2
-+ ldmia r1,{r2,r4,r6,r8}
-+ ldmia r3,{r1,r3,r5,r7}
-+ b CPDO_dvf_l
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_rmf
-+CPDO_rmf:
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_mvf
-+CPDO_mvf:
-+ ldmia r2,{r1,r2,r3,r4}
-+ stmia r0,{r1,r2,r3,r4}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_mnf
-+CPDO_mnf:
-+ ldmia r2,{r1,r2,r3,r4}
-+ eor r1,r1,#0x80000000
-+ stmia r0,{r1,r2,r3,r4}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_abs
-+CPDO_abs:
-+ ldmia r2,{r1,r2,r3,r4}
-+ bic r1,r1,#0x80000000
-+ stmia r0,{r1,r2,r3,r4}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_sqt
-+CPDO_sqt:
-+ ldmia r2,{r1,r2,r3,r4}
-+ cmp r1,#0
-+ bne CPDO_nan
-+ cmp r4,#0x7fffffff
-+ beq CPDO_store_1234
-+
-+ tst r4,r4,lsr#1 @carry=exponent bit 0
-+ bcc CPDO_sqt_exponenteven
-+ adds r3,r3,r3
-+ adcs r2,r2,r2 @carry is needed in loop!
-+CPDO_sqt_exponenteven:
-+ mov r4,r4,asr #1
-+ str r4,[r0,#12]
-+
-+ mov r4,#0x80000000
-+ mov r5,#0
-+ sub r2,r2,#0x80000000
-+
-+ mov r8,#0x40000000
-+ mov r14,#0x80000000
-+
-+ mov r1,#1
-+ b CPDO_sqt_loop1_first
-+CPDO_sqt_loop1:
-+ adds r3,r3,r3
-+ adcs r2,r2,r2
-+CPDO_sqt_loop1_first:
-+ add r6,r4,r8,lsr r1 @r7 const = r5
-+ bcs CPDO_sqt_loop1_1
-+ cmp r2,r6
-+ cmpeq r3,r5 @r5 for r7
-+ bcc CPDO_sqt_loop1_0
-+CPDO_sqt_loop1_1:
-+ orr r4,r4,r14,lsr r1
-+ subs r3,r3,r5 @r5 for r7
-+ sbc r2,r2,r6
-+CPDO_sqt_loop1_0:
-+ add r1,r1,#1
-+ cmp r1,#30
-+ ble CPDO_sqt_loop1
-+
-+ adds r3,r3,r3
-+ adcs r2,r2,r2
-+ bcs CPDO_sqt_between_1
-+ adds r7,r5,#0x80000000
-+ adc r6,r4,#0
-+ cmp r2,r6
-+ cmpeq r3,r7
-+ bcc CPDO_sqt_between_0
-+CPDO_sqt_between_1:
-+ orr r4,r4,#0x00000001
-+ subs r3,r3,r5
-+ sbc r2,r2,r4
-+ subs r3,r3,#0x80000000
-+ sbc r2,r2,#0
-+CPDO_sqt_between_0:
-+ mov r1,#0
-+
-+CPDO_sqt_loop2:
-+ adds r3,r3,r3
-+ adcs r2,r2,r2
-+ bcs CPDO_sqt_loop2_1
-+ adds r7,r5,r8,lsr r1
-+ adc r6,r4,#0
-+ cmp r2,r6
-+ cmpeq r3,r7
-+ bcc CPDO_sqt_loop2_0
-+CPDO_sqt_loop2_1:
-+ orr r5,r5,r14,lsr r1
-+ subs r3,r3,r5
-+ sbc r2,r2,r4
-+ subs r3,r3,r8,lsr r1
-+ sbc r2,r2,#0
-+CPDO_sqt_loop2_0:
-+ add r1,r1,#1
-+ cmp r1,#30
-+ ble CPDO_sqt_loop2
-+
-+ adds r3,r3,r3
-+ adcs r2,r2,r2
-+ bcs CPDO_sqt_after_1
-+ cmp r2,r6
-+ cmpeq r3,r7
-+ bcc CPDO_sqt_after_0
-+CPDO_sqt_after_1:
-+ orr r5,r5,#0x00000001
-+CPDO_sqt_after_0:
-+
-+ mov r1,#0
-+ stmia r0,{r1,r4,r5}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_rnd
-+CPDO_rnd:
-+ ldmia r2,{r1,r2,r3,r5}
-+ bl CPDO_rnd_core
-+
-+CPDO_rnd_store:
-+ stmia r0,{r1,r2,r3,r5}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDO_rnd_core
-+CPDO_rnd_core:
-+ and r4,r4,#0x00000060
-+ add pc,pc,r4,lsr#3
-+ mov r0,r0
-+ b CPDO_rnd_N
-+ b CPDO_rnd_P
-+ b CPDO_rnd_M
-+ b CPDO_rnd_Z
-+
-+CPDO_rnd_N:
-+ cmp r5,#-1
-+ blt CPDO_rnd_zero
-+ cmp r5,#63
-+ movge pc,r14
-+ mov r4,#0x40000000
-+ cmp r5,#31
-+ bge CPDO_rnd_N_2
-+
-+ adds r2,r2,r4,lsr r5
-+ bcc CPDO_rnd_end
-+ b CPDO_rnd_end_norm
-+
-+CPDO_rnd_N_2:
-+CPDO_rnd_P_2:
-+ sub r6,r5,#32
-+ adds r3,r3,r4,ror r6 @ror ist needed to handle a -1 correctly
-+ adcs r2,r2,#0
-+ bcc CPDO_rnd_end
-+ b CPDO_rnd_end_norm
-+
-+CPDO_rnd_P:
-+ tst r1,#0x80000000
-+ bne CPDO_rnd_M_entry
-+CPDO_rnd_P_entry:
-+ cmp r5,#0
-+ blt CPDO_rnd_P_small
-+ cmp r5,#63
-+ movge pc,r14
-+ mov r4,#0x7fffffff
-+ cmp r5,#32
-+ bge CPDO_rnd_P_2
-+
-+ adds r3,r3,#0xffffffff
-+ adcs r2,r2,r4,lsr r5
-+ bcc CPDO_rnd_end
-+ b CPDO_rnd_end_norm
-+
-+CPDO_rnd_P_small:
-+ cmp r5,#0x80000000
-+ moveq pc,r14
-+ b CPDO_rnd_one
-+
-+CPDO_rnd_M:
-+ tst r1,#0x80000000
-+ bne CPDO_rnd_P_entry
-+CPDO_rnd_M_entry:
-+ cmp r5,#0
-+ blt CPDO_rnd_zero
-+ cmp r5,#63
-+ movge pc,r14
-+
-+ b CPDO_rnd_end
-+
-+CPDO_rnd_Z:
-+ cmp r5,#0
-+ blt CPDO_rnd_zero
-+ cmp r5,#63
-+ movge pc,r14
-+ b CPDO_rnd_end
-+
-+CPDO_rnd_end_norm:
-+ add r5,r5,#1
-+ movs r2,r2,rrx
-+ mov r3,r3,rrx
-+CPDO_rnd_end:
-+ rsbs r4,r5,#31
-+ bmi CPDO_rnd_end_2
-+ mov r3,#0
-+ mov r2,r2,lsr r4
-+ mov r2,r2,lsl r4
-+ mov pc,r14
-+
-+CPDO_rnd_end_2:
-+ rsb r4,r5,#63
-+ mov r3,r3,lsr r4
-+ mov r3,r3,lsl r4
-+ mov pc,r14
-+
-+CPDO_rnd_one:
-+ mov r2,#0x80000000
-+ mov r3,#0
-+ mov r5,#0
-+ mov pc,r14
-+
-+CPDO_rnd_zero:
-+ mov r1,#0
-+ mov r2,#0
-+ mov r3,#0
-+ mov r5,#0x80000000
-+ mov pc,r14
-+
-+/*---------------------------------------------------------------------------*/
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/fastfpe/CPRT.S 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,185 @@
-+/*
-+The FP structure has 4 words reserved for each register, the first is used
-+just
-+for the sign in bit 31, the second and third are for the mantissa (unsigned
-+integer, high 32 bit first) and the fourth is the exponent (signed integer).
-+The mantissa is always normalized.
-+
-+If the exponent is 0x80000000, that is the most negative value, the number
-+represented is 0 and both mantissa words are also 0.
-+
-+If the exponent is 0x7fffffff, that is the biggest positive value, the
-+number
-+represented is infinity if the high 32 mantissa bit are also 0, otherwise it
-+is
-+a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
-+
-+Decimal and packed decimal numbers are not supported yet.
-+*/
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .text
-+ .globl CPRT_flt
-+CPRT_flt:
-+ add r0,r13,r0,lsr#10
-+ ldr r2,[r0]
-+ mov r3,#0
-+ cmp r2,#0
-+ beq CPRT_flt_zero
-+
-+ ands r0,r2,#0x80000000
-+ rsbne r2,r2,#0
-+ mov r4,#31
-+
-+ cmp r2,#0x00010000
-+ movcc r2,r2,lsl#16
-+ subcc r4,r4,#16
-+
-+ cmp r2,#0x01000000
-+ movcc r2,r2,lsl#8
-+ subcc r4,r4,#8
-+
-+ cmp r2,#0x10000000
-+ movcc r2,r2,lsl#4
-+ subcc r4,r4,#4
-+
-+ cmp r2,#0x40000000
-+ movcc r2,r2,lsl#2
-+ subcc r4,r4,#2
-+
-+ cmp r2,#0x80000000
-+ movcc r2,r2,lsl#1
-+ subcc r4,r4,#1
-+
-+ stmia r1,{r0,r2,r3,r4}
-+ b fastfpe_next
-+
-+CPRT_flt_zero:
-+ mov r0,#0
-+ mov r4,#0x80000000
-+ stmia r1,{r0,r2,r3,r4}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPRT_fix
-+CPRT_fix:
-+ ldmia r2,{r1,r2,r3,r5}
-+ bl CPDO_rnd_core
-+
-+CPRT_back:
-+ add r0,r13,r0,lsr#10
-+ cmp r5,#0
-+ blt CPRT_int_zero
-+ cmp r5,#30
-+ bgt CPRT_overflow
-+
-+ rsb r5,r5,#31
-+ mov r2,r2,lsr r5
-+ tst r1,#0x80000000
-+ rsbne r2,r2,#0
-+
-+ str r2,[r0]
-+ b fastfpe_next
-+
-+CPRT_int_zero:
-+ mov r2,#0
-+ str r2,[r0]
-+ b fastfpe_next
-+
-+CPRT_overflow:
-+ mov r2,#0x80000000
-+ tst r1,#0x80000000
-+ subeq r2,r2,#1
-+ str r2,[r0]
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPRT_wfs
-+CPRT_wfs:
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPRT_rfs
-+CPRT_rfs:
-+ add r0,r13,r0,lsr#10
-+ mov r1,#0x02000000 @ Software Emulation, not Acorn FPE
-+ str r1,[r0]
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPRT_cmf
-+CPRT_cmf:
-+ ldmia r1,{r1,r3,r5,r7}
-+ ldmia r2,{r2,r4,r6,r8}
-+
-+CPRT_cmf_e:
-+ ldr r0,[r13,#16*4]
-+
-+ cmp r7,#0x7fffffff
-+ bic r0,r0,#0xf0000000
-+
-+ cmpeq r3,#0xffffffff
-+ beq CPRT_cmf_unordered
-+ cmp r8,#0x7fffffff
-+ cmpeq r4,#0xffffffff
-+ beq CPRT_cmf_unordered
-+
-+ cmp r1,r2
-+ beq CPRT_cmf_equalsign
-+ b CPRT_cmf_sign
-+
-+CPRT_cmf_equalsign:
-+ cmp r7,r8
-+ beq CPRT_cmf_equalexponent
-+ bgt CPRT_cmf_sign
-+ b CPRT_cmf_signb
-+
-+CPRT_cmf_equalexponent:
-+ cmp r3,r4
-+ cmpeq r5,r6
-+ beq CPRT_cmf_equal
-+ bhi CPRT_cmf_sign
-+ b CPRT_cmf_signb
-+
-+CPRT_cmf_sign:
-+ cmp r7,#0x80000000 @ (0.0 == -0.0)?
-+ cmpeq r7,r8
-+ beq CPRT_cmf_equal
-+ tst r1,#0x80000000
-+ orreq r0,r0,#0x20000000
-+ orrne r0,r0,#0x80000000
-+ str r0,[r13,#16*4]
-+ b fastfpe_next
-+
-+CPRT_cmf_signb:
-+ tst r1,#0x80000000
-+ orrne r0,r0,#0x20000000
-+ orreq r0,r0,#0x80000000
-+ str r0,[r13,#16*4]
-+ b fastfpe_next
-+
-+CPRT_cmf_equal:
-+ orr r0,r0,#0x60000000
-+ str r0,[r13,#16*4]
-+ b fastfpe_next
-+
-+CPRT_cmf_unordered:
-+ orr r0,r0,#0x10000000
-+ str r0,[r13,#16*4]
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPRT_cnf
-+CPRT_cnf:
-+ ldmia r1,{r1,r3,r5,r7}
-+ ldmia r2,{r2,r4,r6,r8}
-+ eor r2,r2,#0x80000000
-+ b CPRT_cmf_e
-+
-+/*---------------------------------------------------------------------------*/
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/fastfpe/CPDT.S 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,430 @@
-+/*
-+The FP structure has 4 words reserved for each register, the first is used just
-+for the sign in bit 31, the second and third are for the mantissa (unsigned
-+integer, high 32 bit first) and the fourth is the exponent (signed integer).
-+The mantissa is always normalized.
-+
-+If the exponent is 0x80000000, that is the most negative value, the number
-+represented is 0 and both mantissa words are also 0.
-+
-+If the exponent is 0x7fffffff, that is the biggest positive value, the number
-+represented is infinity if the high 32 mantissa bit are also 0, otherwise it is
-+a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
-+
-+Decimal and packed decimal numbers are not supported yet.
-+*/
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_load_single
-+CPDT_load_single:
-+ ldr r1,[r6]
-+
-+ and r2,r1,#0x80000000 @ r2 = sign
-+
-+ mov r5,r1,lsr#23
-+ bics r5,r5,#0x100
-+ beq CPDT_ls_e0 @ exponent = 0; zero/denormalized
-+ teq r5,#255
-+ beq CPDT_ls_e255 @ exponent = 255; infinity/NaN
-+
-+ sub r5,r5,#127 @ r5 = exponent, remove normalized bias
-+
-+ mov r3,r1,lsl#8
-+ orr r3,r3,#0x80000000
-+ mov r4,#0 @ r3,r4 = mantissa
-+
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+CPDT_ls_e0:
-+ movs r3,r1,lsl#9
-+ beq CPDT_load_zero
-+
-+ mov r5,#-127
-+
-+CPDT_ls_e0_norm:
-+ tst r3,#0x80000000
-+ subeq r5,r5,#1
-+ moveq r3,r3,lsl#1
-+ beq CPDT_ls_e0_norm
-+
-+ mov r4,#0
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+CPDT_ls_e255:
-+ mov r3,r1,lsl#9
-+ mov r4,#0
-+ mov r5,#0x7fffffff
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+CPDT_load_zero:
-+ mov r3,#0
-+ mov r4,#0
-+ mov r5,#0x80000000
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_load_double
-+CPDT_load_double:
-+ ldr r1,[r6]
-+ ldr r6,[r6,#4]
-+
-+ and r2,r1,#0x80000000 @ r2 = sign
-+
-+ mov r5,r1,lsr#20
-+ bics r5,r5,#0x800
-+ beq CPDT_ld_e0 @ exponent = 0; zero/denormalized
-+ add r4,r5,#1
-+ teq r4,#2048
-+ beq CPDT_ld_e2047 @ exponent = 2047; infinity/NaN
-+
-+ add r5,r5,#1
-+ sub r5,r5,#1024 @ r5 = exponent, remove normalized bias
-+
-+ mov r3,r1,lsl#11
-+ orr r3,r3,#0x80000000
-+ orr r3,r3,r6,lsr #21
-+ mov r4,r6,lsl#11 @ r3,r4 = mantissa
-+
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+CPDT_ld_e0:
-+ mov r3,r1,lsl#12
-+ orr r3,r3,r6,lsr#20
-+ movs r4,r6,lsl#12
-+ teqeq r3,#0
-+ beq CPDT_load_zero
-+
-+ mov r5,#1
-+ sub r5,r5,#1024
-+
-+CPDT_ld_e0_norm:
-+ tst r3,#0x80000000
-+ subeq r5,r5,#1
-+ moveqs r4,r4,lsl#1
-+ adceq r3,r3,r3
-+ beq CPDT_ld_e0_norm
-+
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+CPDT_ld_e2047:
-+ mov r3,r1,lsl#12
-+ orr r3,r3,r6,lsr#1
-+ bic r6,r6,#0x80000000
-+ orr r3,r3,r6 @ to get all fraction bits !
-+ mov r4,#0
-+ mov r5,#0x7fffffff
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_load_extended
-+CPDT_load_extended:
-+ ldr r1,[r6]
-+ ldr r3,[r6,#4]
-+ ldr r4,[r6,#8]
-+
-+ and r2,r1,#0x80000000
-+ bics r5,r1,#0x80000000
-+ beq CPDT_le_e0
-+ add r1,r5,#1
-+ teq r4,#32768
-+ beq CPDT_le_e32767
-+
-+ add r5,r5,#1
-+ sub r5,r5,#16384
-+
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+CPDT_le_e0:
-+ teq r3,#0
-+ teqeq r4,#0
-+ beq CPDT_load_zero
-+
-+ mov r5,#2
-+ sub r5,r5,#16384
-+ b CPDT_ld_e0_norm
-+
-+CPDT_le_e32767:
-+ mov r3,r3,lsl#1
-+ orr r3,r3,r4,lsr#1
-+ bic r4,r4,#0x80000000
-+ orr r3,r3,r4
-+ mov r5,#0x7fffffff
-+ stmia r0,{r2-r5}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_load_decimal
-+CPDT_load_decimal:
-+
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_store_single
-+CPDT_store_single:
-+ ldmia r0,{r1-r4}
-+
-+ cmp r4,#-127
-+ ble CPDT_ss_e0
-+ cmp r4,#128
-+ bge CPDT_ss_e255
-+
-+ adds r2,r2,#1<<7 @ round to nearest
-+ bcs CPDT_ss_rnd_ovfl @ very very seldom taken
-+
-+CPDT_ss_store:
-+ add r4,r4,#127
-+ orr r1,r1,r4,lsl#23
-+
-+ bic r2,r2,#0x80000000
-+ orr r1,r1,r2,lsr#8
-+
-+ str r1,[r6]
-+ b fastfpe_next
-+
-+CPDT_ss_rnd_ovfl:
-+ add r4,r4,#1
-+ cmp r4,#128
-+ bge CPDT_ss_e255
-+
-+ mov r2,#0x80000000
-+ mov r3,#0
-+ b CPDT_ss_store
-+
-+CPDT_ss_e0:
-+ cmp r4,#-150
-+ ble CPDT_ss_zero
-+
-+ add r4,r4,#126
-+CPDT_ss_unnormalize:
-+ mov r2,r2,lsr#1
-+ adds r4,r4,#1
-+ bne CPDT_ss_unnormalize
-+
-+ orr r1,r1,r2,lsr#8
-+
-+CPDT_ss_zero:
-+ str r1,[r6]
-+ b fastfpe_next
-+
-+CPDT_ss_e255:
-+ cmp r4,#0x7fffffff
-+ bne CPDT_ss_inf
-+ cmp r2,#0
-+ beq CPDT_ss_inf
-+
-+ orr r1,r1,#0x00200000 @ for safety so that it is not INF
-+ orr r1,r1,r2,lsr#9 @ get highest bit of mantissa
-+
-+CPDT_ss_inf:
-+ orr r1,r1,#0x7f000000
-+ orr r1,r1,#0x00800000
-+ str r1,[r6]
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_store_double
-+CPDT_store_double:
-+ ldmia r0,{r1-r4}
-+
-+ cmp r4,#1024 @ this check has to be first, or
-+ bge CPDT_sd_e2047 @ overflow can occur on second !
-+ add r0,r4,#3
-+ cmp r0,#-1023+3 @ cmp with -1023
-+ ble CPDT_sd_e0
-+
-+ adds r3,r3,#1<<10 @ round to nearest
-+ adcs r2,r2,#0
-+ bcs CPDT_sd_rnd_ovfl @ very very seldom taken
-+
-+CPDT_sd_store:
-+ sub r4,r4,#1
-+ add r4,r4,#1024
-+ orr r1,r1,r4,lsl#20
-+
-+ bic r2,r2,#0x80000000
-+ orr r1,r1,r2,lsr#11
-+
-+ mov r2,r2,lsl#21
-+ orr r2,r2,r3,lsr#11
-+
-+ stmia r6,{r1,r2}
-+ b fastfpe_next
-+
-+CPDT_sd_rnd_ovfl:
-+ add r4,r4,#1
-+ cmp r4,#1024
-+ bge CPDT_sd_e2047
-+
-+ mov r2,#0x80000000
-+ mov r3,#0
-+ b CPDT_sd_store
-+
-+CPDT_sd_e0:
-+ add r0,r4,#1075-1024
-+ cmp r0,#-1024
-+ ble CPDT_sd_zero
-+
-+ add r4,r4,#1024
-+ sub r4,r4,#2
-+CPDT_sd_unnormalize:
-+ movs r2,r2,lsr#1
-+ mov r3,r3,rrx
-+ adds r4,r4,#1
-+ bne CPDT_sd_unnormalize
-+
-+ orr r1,r1,r2,lsr#11
-+ mov r2,r2,lsl#21
-+ orr r2,r2,r3,lsr#11
-+
-+ stmia r6,{r1,r2}
-+ b fastfpe_next
-+
-+CPDT_sd_zero:
-+ mov r2,#0
-+ stmia r6,{r1,r2}
-+ b fastfpe_next
-+
-+CPDT_sd_e2047:
-+ cmp r4,#0x7fffffff
-+ bne CPDT_sd_inf
-+ cmp r2,#0
-+ beq CPDT_sd_inf
-+
-+ orr r1,r1,#0x00040000 @ for safety so that it is not INF
-+ orr r1,r1,r2,lsr#12 @ get highest bit of mantissa
-+
-+CPDT_sd_inf:
-+ orr r1,r1,#0x7f000000
-+ orr r1,r1,#0x00f00000
-+ stmia r6,{r1,r2}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_store_extended
-+CPDT_store_extended:
-+ ldmia r0,{r1-r4}
-+
-+ cmp r4,#16384 @ this check has to be first, or
-+ bge CPDT_se_e32767 @ overflow can occur with second !
-+ add r0,r4,#63
-+ cmp r0,#-16383+63
-+ ble CPDT_se_e0
-+
-+ sub r4,r4,#1
-+ add r4,r4,#16384
-+ orr r1,r1,r4
-+
-+ stmia r6,{r1-r3}
-+ b fastfpe_next
-+
-+CPDT_se_e0:
-+ add r0,r4,#16446-16384
-+ cmp r0,#-16384
-+ ble CPDT_se_zero
-+
-+ add r4,r4,#16384
-+ sub r4,r4,#2
-+CPDT_se_unnormalize:
-+ movs r2,r2,lsr#1
-+ mov r3,r3,rrx
-+ adds r4,r4,#1
-+ bne CPDT_se_unnormalize
-+
-+ stmia r6,{r1-r3}
-+ b fastfpe_next
-+
-+CPDT_se_zero:
-+ mov r2,#0
-+ mov r3,#0
-+ stmia r6,{r1-r3}
-+ b fastfpe_next
-+
-+CPDT_se_e32767:
-+ cmp r4,#0x7fffffff
-+ bne CPDT_se_inf
-+ cmp r2,#0
-+ beq CPDT_se_inf
-+
-+ mov r2,r2,lsl#1
-+ orr r2,r2,#0x20000000
-+
-+CPDT_se_inf:
-+ orr r1,r1,#0x00007f00
-+ orr r1,r1,#0x000000ff
-+ stmia r6,{r1-r3}
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_store_decimal
-+CPDT_store_decimal:
-+
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_sfm
-+CPDT_sfm:
-+ add r2,r10,r0,lsr#8
-+ ldr r4,[r2,#0]
-+ ldr r3,[r2,#4]
-+ bic r3,r3,#0x80000000
-+ orr r3,r3,r4
-+ str r3,[r6],#4
-+ ldr r3,[r2,#8]
-+ str r3,[r6],#4
-+ ldr r3,[r2,#12]
-+ str r3,[r6],#4
-+
-+ add r0,r0,#1<<12
-+ and r0,r0,#7<<12
-+ subs r1,r1,#1
-+ bne CPDT_sfm
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
-+
-+ .globl CPDT_lfm
-+CPDT_lfm:
-+ add r2,r10,r0,lsr#8
-+ ldr r4,[r6],#4
-+ and r3,r4,#0x80000000
-+ str r3,[r2,#0]
-+ ldr r3,[r6],#4
-+ str r3,[r2,#8]
-+ ldr r3,[r6],#4
-+ str r3,[r2,#12]
-+
-+ cmp r3,#0x80000000 @ does the exp indicate zero?
-+ biceq r4,r4,#0x80000000 @ if so, indicate 'denormalized'
-+ beq CPDT_lfm_storer4
-+ cmp r3,#0x7fffffff @ does the exp indicate inf or NaN?
-+ biceq r4,r4,#0x80000000 @ if so, indicate 'denormalized'
-+ beq CPDT_lfm_storer4
-+ orrne r4,r4,#0x80000000 @ otherwise, set normalized bit
-+
-+CPDT_lfm_storer4:
-+ str r4,[r2,#4]
-+
-+ add r0,r0,#1<<12
-+ and r0,r0,#7<<12
-+ subs r1,r1,#1
-+ bne CPDT_lfm
-+ b fastfpe_next
-+
-+/*---------------------------------------------------------------------------*/
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/fastfpe/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,14 @@
-+#
-+# linux/arch/arm/fastfpe/Makefile
-+#
-+# Copyright (C) Peter Teichmann
-+#
-+
-+obj-y :=
-+obj-m :=
-+obj-n :=
-+obj- :=
-+
-+fastfpe-objs := module.o entry.o CPDO.o CPRT.o CPDT.o
-+
-+obj-$(CONFIG_FPE_FASTFPE) += fastfpe.o
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/common/rtctime.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,482 @@
-+/*
-+ * linux/arch/arm/common/rtctime.c
-+ *
-+ * Copyright (C) 2003 Deep Blue Solutions Ltd.
-+ * Based on sa1100-rtc.c, Nils Faerber, CIH, Nicolas Pitre.
-+ * Based on rtc.c by Paul Gortmaker
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/time.h>
-+#include <linux/rtc.h>
-+#include <linux/poll.h>
-+#include <linux/proc_fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/spinlock.h>
-+#include <linux/device.h>
-+
-+#include <asm/rtc.h>
-+#include <asm/semaphore.h>
-+
-+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
-+static struct fasync_struct *rtc_async_queue;
-+
-+/*
-+ * rtc_lock protects rtc_irq_data
-+ */
-+static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
-+static unsigned long rtc_irq_data;
-+
-+/*
-+ * rtc_sem protects rtc_inuse and rtc_ops
-+ */
-+static DECLARE_MUTEX(rtc_sem);
-+static unsigned long rtc_inuse;
-+static struct rtc_ops *rtc_ops;
-+
-+#define rtc_epoch 1900UL
-+
-+static const unsigned char days_in_month[] = {
-+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-+};
-+
-+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
-+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
-+
-+static int month_days(unsigned int month, unsigned int year)
-+{
-+ return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
-+}
-+
-+/*
-+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
-+ */
-+void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
-+{
-+ int days, month, year;
-+
-+ days = time / 86400;
-+ time -= days * 86400;
-+
-+ tm->tm_wday = (days + 4) % 7;
-+
-+ year = 1970 + days / 365;
-+ days -= (year - 1970) * 365
-+ + LEAPS_THRU_END_OF(year - 1)
-+ - LEAPS_THRU_END_OF(1970 - 1);
-+ if (days < 0) {
-+ year -= 1;
-+ days += 365 + LEAP_YEAR(year);
-+ }
-+ tm->tm_year = year - 1900;
-+ tm->tm_yday = days + 1;
-+
-+ for (month = 0; month < 11; month++) {
-+ int newdays;
-+
-+ newdays = days - month_days(month, year);
-+ if (newdays < 0)
-+ break;
-+ days = newdays;
-+ }
-+ tm->tm_mon = month;
-+ tm->tm_mday = days + 1;
-+
-+ tm->tm_hour = time / 3600;
-+ time -= tm->tm_hour * 3600;
-+ tm->tm_min = time / 60;
-+ tm->tm_sec = time - tm->tm_min * 60;
-+}
-+
-+/*
-+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
-+ */
-+int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
-+{
-+ unsigned int yrs = tm->tm_year + 1900;
-+
-+ *time = 0;
-+
-+ if (yrs < 1970 ||
-+ tm->tm_mon >= 12 ||
-+ tm->tm_mday < 1 ||
-+ tm->tm_mday > month_days(tm->tm_mon, yrs) ||
-+ tm->tm_hour >= 24 ||
-+ tm->tm_min >= 60 ||
-+ tm->tm_sec >= 60)
-+ return -EINVAL;
-+
-+ *time = mktime(yrs, tm->tm_mon + 1, tm->tm_mday,
-+ tm->tm_hour, tm->tm_min, tm->tm_sec);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Calculate the next alarm time given the requested alarm time mask
-+ * and the current time.
-+ *
-+ * FIXME: for now, we just copy the alarm time because we're lazy (and
-+ * is therefore buggy - setting a 10am alarm at 8pm will not result in
-+ * the alarm triggering.)
-+ */
-+void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
-+{
-+ next->tm_year = now->tm_year;
-+ next->tm_mon = now->tm_mon;
-+ next->tm_mday = now->tm_mday;
-+ next->tm_hour = alrm->tm_hour;
-+ next->tm_min = alrm->tm_min;
-+ next->tm_sec = alrm->tm_sec;
-+}
-+
-+static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
-+{
-+ memset(tm, 0, sizeof(struct rtc_time));
-+ ops->read_time(tm);
-+}
-+
-+static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
-+{
-+ return ops->set_time(tm);
-+}
-+
-+static inline void rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
-+{
-+ memset(alrm, 0, sizeof(struct rtc_wkalrm));
-+ ops->read_alarm(alrm);
-+}
-+
-+static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
-+{
-+ return ops->set_alarm(alrm);
-+}
-+
-+void rtc_update(unsigned long num, unsigned long events)
-+{
-+ spin_lock(&rtc_lock);
-+ rtc_irq_data = (rtc_irq_data + (num << 8)) | events;
-+ spin_unlock(&rtc_lock);
-+
-+ wake_up_interruptible(&rtc_wait);
-+ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
-+}
-+
-+
-+static ssize_t
-+rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ unsigned long data;
-+ ssize_t ret;
-+
-+ if (count < sizeof(unsigned long))
-+ return -EINVAL;
-+
-+ add_wait_queue(&rtc_wait, &wait);
-+ do {
-+ __set_current_state(TASK_INTERRUPTIBLE);
-+
-+ spin_lock_irq(&rtc_lock);
-+ data = rtc_irq_data;
-+ rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+
-+ if (data != 0) {
-+ ret = 0;
-+ break;
-+ }
-+ if (file->f_flags & O_NONBLOCK) {
-+ ret = -EAGAIN;
-+ break;
-+ }
-+ if (signal_pending(current)) {
-+ ret = -ERESTARTSYS;
-+ break;
-+ }
-+ schedule();
-+ } while (1);
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&rtc_wait, &wait);
-+
-+ if (ret == 0) {
-+ ret = put_user(data, (unsigned long *)buf);
-+ if (ret == 0)
-+ ret = sizeof(unsigned long);
-+ }
-+ return ret;
-+}
-+
-+static unsigned int rtc_poll(struct file *file, poll_table *wait)
-+{
-+ unsigned long data;
-+
-+ poll_wait(file, &rtc_wait, wait);
-+
-+ spin_lock_irq(&rtc_lock);
-+ data = rtc_irq_data;
-+ spin_unlock_irq(&rtc_lock);
-+
-+ return data != 0 ? POLLIN | POLLRDNORM : 0;
-+}
-+
-+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ struct rtc_ops *ops = file->private_data;
-+ struct rtc_time tm;
-+ struct rtc_wkalrm alrm;
-+ int ret;
-+
-+ switch (cmd) {
-+ case RTC_ALM_READ:
-+ rtc_read_alarm(ops, &alrm);
-+ ret = copy_to_user((void *)arg, &alrm.time, sizeof(tm));
-+ if (ret)
-+ ret = -EFAULT;
-+ break;
-+
-+ case RTC_ALM_SET:
-+ ret = copy_from_user(&alrm.time, (void *)arg, sizeof(tm));
-+ alrm.enabled = 0;
-+ alrm.pending = 0;
-+ alrm.time.tm_mday = -1;
-+ alrm.time.tm_mon = -1;
-+ alrm.time.tm_year = -1;
-+ alrm.time.tm_wday = -1;
-+ alrm.time.tm_yday = -1;
-+ alrm.time.tm_isdst = -1;
-+ if (ret == 0)
-+ ret = rtc_set_alarm(ops, &alrm);
-+ else
-+ ret = -EFAULT;
-+ break;
-+
-+ case RTC_RD_TIME:
-+ rtc_read_time(ops, &tm);
-+ ret = copy_to_user((void *)arg, &tm, sizeof(tm));
-+ if (ret)
-+ ret = -EFAULT;
-+ break;
-+
-+ case RTC_SET_TIME:
-+ if (!capable(CAP_SYS_TIME)) {
-+ ret = -EACCES;
-+ break;
-+ }
-+ ret = copy_from_user(&tm, (void *)arg, sizeof(tm));
-+ if (ret == 0)
-+ ret = rtc_set_time(ops, &tm);
-+ else
-+ ret = -EFAULT;
-+ break;
-+
-+#ifndef rtc_epoch
-+ case RTC_EPOCH_SET:
-+ /*
-+ * There were no RTC clocks before 1900.
-+ */
-+ if (arg < 1900) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ if (!capable(CAP_SYS_TIME)) {
-+ ret = -EACCES;
-+ break;
-+ }
-+ rtc_epoch = arg;
-+ ret = 0;
-+ break;
-+#endif
-+
-+ case RTC_EPOCH_READ:
-+ ret = put_user(rtc_epoch, (unsigned long *)arg);
-+ break;
-+
-+ case RTC_WKALM_SET:
-+ ret = copy_from_user(&alrm, (void *)arg, sizeof(alrm));
-+ if (ret == 0)
-+ ret = rtc_set_alarm(ops, &alrm);
-+ else
-+ ret = -EFAULT;
-+ break;
-+
-+ case RTC_WKALM_RD:
-+ rtc_read_alarm(ops, &alrm);
-+ ret = copy_to_user((void *)arg, &alrm, sizeof(alrm));
-+ if (ret)
-+ ret = -EFAULT;
-+ break;
-+
-+ default:
-+ ret = ops->ioctl(cmd, arg);
-+ }
-+ return ret;
-+}
-+
-+static int rtc_open(struct inode *inode, struct file *file)
-+{
-+ int ret;
-+
-+ down(&rtc_sem);
-+
-+ if (rtc_inuse) {
-+ ret = -EBUSY;
-+ } else if (!rtc_ops || !try_module_get(rtc_ops->owner)) {
-+ ret = -ENODEV;
-+ } else {
-+ file->private_data = rtc_ops;
-+
-+ ret = rtc_ops->open ? rtc_ops->open() : 0;
-+ if (ret == 0) {
-+ spin_lock_irq(&rtc_lock);
-+ rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+
-+ rtc_inuse = 1;
-+ }
-+ }
-+ up(&rtc_sem);
-+
-+ return ret;
-+}
-+
-+static int rtc_release(struct inode *inode, struct file *file)
-+{
-+ struct rtc_ops *ops = file->private_data;
-+
-+ if (ops->release)
-+ ops->release();
-+
-+ spin_lock_irq(&rtc_lock);
-+ rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+
-+ module_put(rtc_ops->owner);
-+ rtc_inuse = 0;
-+
-+ return 0;
-+}
-+
-+static int rtc_fasync(int fd, struct file *file, int on)
-+{
-+ return fasync_helper(fd, file, on, &rtc_async_queue);
-+}
-+
-+static struct file_operations rtc_fops = {
-+ .owner = THIS_MODULE,
-+ .llseek = no_llseek,
-+ .read = rtc_read,
-+ .poll = rtc_poll,
-+ .ioctl = rtc_ioctl,
-+ .open = rtc_open,
-+ .release = rtc_release,
-+ .fasync = rtc_fasync,
-+};
-+
-+static struct miscdevice rtc_miscdev = {
-+ .minor = RTC_MINOR,
-+ .name = "rtc",
-+ .fops = &rtc_fops,
-+};
-+
-+
-+static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
-+{
-+ struct rtc_ops *ops = data;
-+ struct rtc_wkalrm alrm;
-+ struct rtc_time tm;
-+ char *p = page;
-+ int len;
-+
-+ rtc_read_time(ops, &tm);
-+
-+ p += sprintf(p,
-+ "rtc_time\t: %02d:%02d:%02d\n"
-+ "rtc_date\t: %04d-%02d-%02d\n"
-+ "rtc_epoch\t: %04lu\n",
-+ tm.tm_hour, tm.tm_min, tm.tm_sec,
-+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-+ rtc_epoch);
-+
-+ rtc_read_alarm(ops, &alrm);
-+ p += sprintf(p, "alrm_time\t: ");
-+ if ((unsigned int)alrm.time.tm_hour <= 24)
-+ p += sprintf(p, "%02d:", alrm.time.tm_hour);
-+ else
-+ p += sprintf(p, "**:");
-+ if ((unsigned int)alrm.time.tm_min <= 59)
-+ p += sprintf(p, "%02d:", alrm.time.tm_min);
-+ else
-+ p += sprintf(p, "**:");
-+ if ((unsigned int)alrm.time.tm_sec <= 59)
-+ p += sprintf(p, "%02d\n", alrm.time.tm_sec);
-+ else
-+ p += sprintf(p, "**\n");
-+
-+ p += sprintf(p, "alrm_date\t: ");
-+ if ((unsigned int)alrm.time.tm_year <= 200)
-+ p += sprintf(p, "%04d-", alrm.time.tm_year + 1900);
-+ else
-+ p += sprintf(p, "****-");
-+ if ((unsigned int)alrm.time.tm_mon <= 11)
-+ p += sprintf(p, "%02d-", alrm.time.tm_mon + 1);
-+ else
-+ p += sprintf(p, "**-");
-+ if ((unsigned int)alrm.time.tm_mday <= 31)
-+ p += sprintf(p, "%02d\n", alrm.time.tm_mday);
-+ else
-+ p += sprintf(p, "**\n");
-+ p += sprintf(p, "alrm_wakeup\t: %s\n", alrm.enabled ? "yes" : "no");
-+ p += sprintf(p, "alrm_pending\t: %s\n", alrm.pending ? "yes" : "no");
-+
-+ if (ops->proc)
-+ p += ops->proc(p);
-+
-+ len = (p - page) - off;
-+ if (len < 0)
-+ len = 0;
-+ *eof = len <= count;
-+ *start = page + off;
-+
-+ return len;
-+}
-+
-+int register_rtc(struct rtc_ops *ops)
-+{
-+ int ret = -EBUSY;
-+
-+ down(&rtc_sem);
-+ if (rtc_ops == NULL) {
-+ rtc_ops = ops;
-+
-+ ret = misc_register(&rtc_miscdev);
-+ if (ret == 0)
-+ create_proc_read_entry("driver/rtc", 0, 0,
-+ rtc_read_proc, ops);
-+ }
-+ up(&rtc_sem);
-+
-+ return ret;
-+}
-+
-+void unregister_rtc(struct rtc_ops *rtc)
-+{
-+ down(&rtc_sem);
-+ if (rtc == rtc_ops) {
-+ remove_proc_entry("driver/rtc", NULL);
-+ misc_deregister(&rtc_miscdev);
-+ rtc_ops = NULL;
-+ }
-+ up(&rtc_sem);
-+}
-+
-+EXPORT_SYMBOL(rtc_time_to_tm);
-+EXPORT_SYMBOL(rtc_tm_to_time);
-+EXPORT_SYMBOL(rtc_update);
-+EXPORT_SYMBOL(register_rtc);
-+EXPORT_SYMBOL(unregister_rtc);
---- linux-2.6.5/arch/arm/common/Makefile~heh 2004-04-03 22:36:57.000000000 -0500
-+++ linux-2.6.5/arch/arm/common/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -2,7 +2,7 @@
- # Makefile for the linux kernel.
- #
-
--obj-y += platform.o
-+obj-y += platform.o rtctime.o
- obj-$(CONFIG_ARM_AMBA) += amba.o
- obj-$(CONFIG_ICST525) += icst525.o
- obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o
---- linux-2.6.5/arch/arm/mach-pxa/generic.c~heh 2004-04-03 22:36:53.000000000 -0500
-+++ linux-2.6.5/arch/arm/mach-pxa/generic.c 2004-04-30 20:57:36.000000000 -0400
-@@ -132,7 +132,7 @@
- /* virtual physical length type */
- { 0xf6000000, 0x20000000, 0x01000000, MT_DEVICE }, /* PCMCIA0 IO */
- { 0xf7000000, 0x30000000, 0x01000000, MT_DEVICE }, /* PCMCIA1 IO */
-- { 0xf8000000, 0x40000000, 0x01400000, MT_DEVICE }, /* Devs */
-+ { 0xf8000000, 0x40000000, 0x01800000, MT_DEVICE }, /* Devs */
- { 0xfa000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */
- { 0xfc000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */
- { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE } /* UNCACHED_PHYS_0 */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-pxa/cpu-pxa.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,322 @@
-+/*
-+ * linux/arch/arm/mach-pxa/cpu-pxa.c
-+ *
-+ * Copyright (C) 2002,2003 Intrinsyc Software
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * History:
-+ * 31-Jul-2002 : Initial version [FB]
-+ * 29-Jan-2003 : added PXA255 support [FB]
-+ * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.)
-+ *
-+ * Note:
-+ * This driver may change the memory bus clock rate, but will not do any
-+ * platform specific access timing changes... for example if you have flash
-+ * memory connected to CS0, you will need to register a platform specific
-+ * notifier which will adjust the memory access strobes to maintain a
-+ * minimum strobe width.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/cpufreq.h>
-+
-+#include <asm/hardware.h>
-+
-+#define DEBUG 0
-+
-+#ifdef DEBUG
-+ static unsigned int freq_debug = DEBUG;
-+ MODULE_PARM(freq_debug, "i");
-+ MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
-+#else
-+ #define freq_debug 0
-+#endif
-+
-+typedef struct
-+{
-+ unsigned int khz;
-+ unsigned int membus;
-+ unsigned int cccr;
-+ unsigned int div2;
-+} pxa_freqs_t;
-+
-+/* Define the refresh period in mSec for the SDRAM and the number of rows */
-+#define SDRAM_TREF 64 /* standard 64ms SDRAM */
-+#define SDRAM_ROWS 4096 /* 64MB=8192 32MB=4096 */
-+#define MDREFR_DRI(x) ((x*SDRAM_TREF)/(SDRAM_ROWS*32))
-+
-+#define CCLKCFG_TURBO 0x1
-+#define CCLKCFG_FCS 0x2
-+#define PXA25x_MIN_FREQ 99500
-+#define PXA25x_MAX_FREQ 398100
-+#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2)
-+#define MDREFR_DRI_MASK 0xFFF
-+
-+
-+/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
-+static pxa_freqs_t pxa255_run_freqs[] =
-+{
-+ /* CPU MEMBUS CCCR DIV2*/
-+ { 99500, 99500, 0x121, 1}, /* run= 99, turbo= 99, PXbus=50, SDRAM=50 */
-+ {132700, 132700, 0x123, 1}, /* run=133, turbo=133, PXbus=66, SDRAM=66 */
-+ {199100, 99500, 0x141, 0}, /* run=199, turbo=199, PXbus=99, SDRAM=99 */
-+ {265400, 132700, 0x143, 1}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */
-+ {331800, 165900, 0x145, 1}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */
-+ {398100, 99500, 0x161, 0}, /* run=398, turbo=398, PXbus=196, SDRAM=99 */
-+ {0,}
-+};
-+#define NUM_RUN_FREQS (sizeof(pxa255_run_freqs)/sizeof(pxa_freqs_t))
-+
-+static struct cpufreq_frequency_table pxa255_run_freq_table[NUM_RUN_FREQS+1];
-+
-+/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
-+static pxa_freqs_t pxa255_turbo_freqs[] =
-+{
-+ /* CPU MEMBUS CCCR DIV2*/
-+ { 99500, 99500, 0x121, 1}, /* run=99, turbo= 99, PXbus=50, SDRAM=50 */
-+ {199100, 99500, 0x221, 0}, /* run=99, turbo=199, PXbus=50, SDRAM=99 */
-+ {298500, 99500, 0x321, 0}, /* run=99, turbo=287, PXbus=50, SDRAM=99 */
-+ {298600, 99500, 0x1c1, 0}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */
-+ {398100, 99500, 0x241, 0}, /* run=199, turbo=398, PXbus=99, SDRAM=99 */
-+ {0,}
-+};
-+#define NUM_TURBO_FREQS (sizeof(pxa255_turbo_freqs)/sizeof(pxa_freqs_t))
-+
-+static struct cpufreq_frequency_table pxa255_turbo_freq_table[NUM_TURBO_FREQS+1];
-+
-+/* find a valid frequency point */
-+static int pxa_verify_policy(struct cpufreq_policy *policy)
-+{
-+ int ret;
-+ struct cpufreq_frequency_table *pxa_freqs_table;
-+
-+ if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
-+ pxa_freqs_table = pxa255_run_freq_table;
-+ } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
-+ pxa_freqs_table = pxa255_turbo_freq_table;
-+ } else if (policy->policy == CPUFREQ_POLICY_GOVERNOR) {
-+ pxa_freqs_table = pxa255_run_freq_table;
-+ } else {
-+ printk("CPU PXA: Unknown policy found. "
-+ "Using CPUFREQ_POLICY_PERFORMANCE\n");
-+ pxa_freqs_table = pxa255_run_freq_table;
-+ }
-+ ret=cpufreq_frequency_table_verify(policy, pxa_freqs_table);
-+
-+ if(freq_debug) {
-+ printk("Verified CPU policy: %dKhz min to %dKhz max\n",
-+ policy->min, policy->max);
-+ }
-+
-+ return ret;
-+}
-+
-+static int pxa_set_target(struct cpufreq_policy *policy,
-+ unsigned int target_freq,
-+ unsigned int relation)
-+{
-+ int idx;
-+ unsigned long cpus_allowed;
-+ int cpu = policy->cpu;
-+ struct cpufreq_freqs freqs;
-+ pxa_freqs_t *pxa_freq_settings;
-+ struct cpufreq_frequency_table *pxa_freqs_table;
-+ unsigned long flags;
-+ unsigned int unused;
-+ unsigned int preset_mdrefr, postset_mdrefr;
-+
-+ /*
-+ * Save this threads cpus_allowed mask.
-+ */
-+ cpus_allowed = current->cpus_allowed;
-+
-+ /*
-+ * Bind to the specified CPU. When this call returns,
-+ * we should be running on the right CPU.
-+ */
-+ set_cpus_allowed(current, 1 << cpu);
-+ BUG_ON(cpu != smp_processor_id());
-+
-+ /* Get the current policy */
-+ if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
-+ pxa_freq_settings = pxa255_run_freqs;
-+ pxa_freqs_table = pxa255_run_freq_table;
-+ }else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
-+ pxa_freq_settings = pxa255_turbo_freqs;
-+ pxa_freqs_table = pxa255_turbo_freq_table;
-+ }else if (policy->policy == CPUFREQ_POLICY_GOVERNOR) {
-+ pxa_freq_settings = pxa255_run_freqs;
-+ pxa_freqs_table = pxa255_run_freq_table;
-+ }else {
-+ printk("CPU PXA: Unknown policy found. "
-+ "Using CPUFREQ_POLICY_PERFORMANCE\n");
-+ pxa_freq_settings = pxa255_run_freqs;
-+ pxa_freqs_table = pxa255_run_freq_table;
-+ }
-+
-+ /* Lookup the next frequency */
-+ if (cpufreq_frequency_table_target(policy, pxa_freqs_table,
-+ target_freq, relation, &idx)) {
-+ return -EINVAL;
-+ }
-+
-+ freqs.old = policy->cur;
-+ freqs.new = pxa_freq_settings[idx].khz;
-+ freqs.cpu = policy->cpu;
-+ if(freq_debug) {
-+ printk(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n",
-+ freqs.new/1000, (pxa_freq_settings[idx].div2) ?
-+ (pxa_freq_settings[idx].membus/2000) :
-+ (pxa_freq_settings[idx].membus/1000));
-+ }
-+
-+ void *ramstart = phys_to_virt(0xa0000000);
-+
-+ /*
-+ * Tell everyone what we're about to do...
-+ * you should add a notify client with any platform specific
-+ * Vcc changing capability
-+ */
-+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-+
-+ /* Calculate the next MDREFR. If we're slowing down the SDRAM clock
-+ * we need to preset the smaller DRI before the change. If we're speeding
-+ * up we need to set the larger DRI value after the change.
-+ */
-+ preset_mdrefr = postset_mdrefr = MDREFR;
-+ if((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa_freq_settings[idx].membus)) {
-+ preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) |
-+ MDREFR_DRI(pxa_freq_settings[idx].membus);
-+ }
-+ postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) |
-+ MDREFR_DRI(pxa_freq_settings[idx].membus);
-+
-+ /* If we're dividing the memory clock by two for the SDRAM clock, this
-+ * must be set prior to the change. Clearing the divide must be done
-+ * after the change.
-+ */
-+ if(pxa_freq_settings[idx].div2) {
-+ preset_mdrefr |= MDREFR_DB2_MASK;
-+ postset_mdrefr |= MDREFR_DB2_MASK;
-+ } else {
-+ postset_mdrefr &= ~MDREFR_DB2_MASK;
-+ }
-+
-+ local_irq_save(flags);
-+
-+ /* Set new the CCCR */
-+ CCCR = pxa_freq_settings[idx].cccr;
-+
-+ __asm__ __volatile__(" \
-+ ldr r4, [%1] ; /* load MDREFR */ \
-+ b 2f ; \
-+ .align 5 ; \
-+1: \
-+ str %4, [%1] ; /* preset the MDREFR */ \
-+ mcr p14, 0, %2, c6, c0, 0 ; /* set CCLKCFG[FCS] */ \
-+ str %5, [%1] ; /* postset the MDREFR */ \
-+ \
-+ b 3f ; \
-+2: b 1b ; \
-+3: nop ; \
-+ "
-+ : "=&r" (unused)
-+ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart), \
-+ "r" (preset_mdrefr), "r" (postset_mdrefr)
-+ : "r4", "r5");
-+ local_irq_restore(flags);
-+
-+ /*
-+ * Restore the CPUs allowed mask.
-+ */
-+ set_cpus_allowed(current, cpus_allowed);
-+
-+ /*
-+ * Tell everyone what we've just done...
-+ * you should add a notify client with any platform specific
-+ * SDRAM refresh timer adjustments
-+ */
-+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-+
-+ return 0;
-+}
-+
-+static int pxa_cpufreq_init(struct cpufreq_policy *policy)
-+{
-+ unsigned long cpus_allowed;
-+ unsigned int cpu = policy->cpu;
-+ int i;
-+
-+ cpus_allowed = current->cpus_allowed;
-+
-+ set_cpus_allowed(current, 1 << cpu);
-+ BUG_ON(cpu != smp_processor_id());
-+
-+ /* set default policy and cpuinfo */
-+ policy->policy = CPUFREQ_POLICY_PERFORMANCE;
-+ policy->cpuinfo.max_freq = PXA25x_MAX_FREQ;
-+ policy->cpuinfo.min_freq = PXA25x_MIN_FREQ;
-+ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
-+ policy->cur = get_clk_frequency_khz(0); /* current freq */
-+ policy->min = policy->max = policy->cur;
-+
-+ /* Generate the run cpufreq_frequency_table struct */
-+ for(i=0;i<NUM_RUN_FREQS;i++) {
-+ pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
-+ pxa255_run_freq_table[i].index = i;
-+ }
-+ pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
-+ /* Generate the turbo cpufreq_frequency_table struct */
-+ for(i=0;i<NUM_TURBO_FREQS;i++) {
-+ pxa255_turbo_freq_table[i].frequency = pxa255_turbo_freqs[i].khz;
-+ pxa255_turbo_freq_table[i].index = i;
-+ }
-+ pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
-+
-+ set_cpus_allowed(current, cpus_allowed);
-+ printk(KERN_INFO "PXA CPU frequency change support initialized\n");
-+
-+ return 0;
-+}
-+
-+static struct cpufreq_driver pxa_cpufreq_driver = {
-+ .verify = pxa_verify_policy,
-+ .target = pxa_set_target,
-+ .init = pxa_cpufreq_init,
-+ .name = "PXA25x",
-+};
-+
-+static int __init pxa_cpu_init(void)
-+{
-+ return cpufreq_register_driver(&pxa_cpufreq_driver);
-+}
-+
-+static void __exit pxa_cpu_exit(void)
-+{
-+ cpufreq_unregister_driver(&pxa_cpufreq_driver);
-+}
-+
-+
-+MODULE_AUTHOR ("Intrinsyc Software Inc.");
-+MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture");
-+MODULE_LICENSE("GPL");
-+module_init(pxa_cpu_init);
-+module_exit(pxa_cpu_exit);
-+
---- linux-2.6.5/arch/arm/boot/compressed/misc.c~heh 2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/arch/arm/boot/compressed/misc.c 2004-04-30 20:57:36.000000000 -0400
-@@ -113,7 +113,7 @@
- * gzip delarations
- */
- #define OF(args) args
--#define STATIC static
-+#define STATIC
-
- typedef unsigned char uch;
- typedef unsigned short ush;
-@@ -122,12 +122,12 @@
- #define WSIZE 0x8000 /* Window size must be at least 32k, */
- /* and a power of two */
-
--static uch *inbuf; /* input buffer */
--static uch window[WSIZE]; /* Sliding window buffer */
-+unsigned char *inbuf; /* input buffer */
-+unsigned char window[WSIZE]; /* Sliding window buffer */
-
--static unsigned insize; /* valid bytes in inbuf */
--static unsigned inptr; /* index of next byte to be processed in inbuf */
--static unsigned outcnt; /* bytes in output buffer */
-+unsigned int insize; /* valid bytes in inbuf */
-+unsigned int inptr; /* index of next byte to be processed in inbuf */
-+unsigned int outcnt; /* bytes in output buffer */
-
- /* gzip flag byte */
- #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-@@ -166,9 +166,9 @@
- extern char input_data[];
- extern char input_data_end[];
-
--static uch *output_data;
--static ulg output_ptr;
--static ulg bytes_out;
-+unsigned char *output_data;
-+unsigned long output_ptr;
-+unsigned long bytes_out;
-
- static void *malloc(int size);
- static void free(void *where);
-@@ -179,8 +179,8 @@
- static void puts(const char *);
-
- extern int end;
--static ulg free_mem_ptr;
--static ulg free_mem_ptr_end;
-+unsigned long free_mem_ptr;
-+unsigned long free_mem_ptr_end;
-
- #define HEAP_SIZE 0x2000
-
---- linux-2.6.5/arch/arm/mm/ioremap.c~heh 2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/arch/arm/mm/ioremap.c 2004-04-30 20:57:36.000000000 -0400
-@@ -13,15 +13,18 @@
- * virtual space. One should *only* use readl, writel, memcpy_toio and
- * so on with such remapped areas.
- *
-- * Because the ARM only has a 32-bit address space we can't address the
-- * whole of the (physical) PCI space at once. PCI huge-mode addressing
-- * allows us to circumvent this restriction by splitting PCI space into
-- * two 2GB chunks and mapping only one at a time into processor memory.
-- * We use MMU protection domains to trap any attempt to access the bank
-- * that is not currently mapped. (This isn't fully implemented yet.)
-+ * ioremap support tweaked to allow support for large page mappings. We
-+ * have several issues that needs to be resolved first however:
-+ *
-+ * 1. We need set_pte, or something like set_pte to understand large
-+ * page mappings.
-+ *
-+ * 2. we need the unmap_* functions to likewise understand large page
-+ * mappings.
- */
- #include <linux/errno.h>
- #include <linux/mm.h>
-+#include <linux/slab.h>
- #include <linux/vmalloc.h>
-
- #include <asm/page.h>
-@@ -29,31 +32,162 @@
- #include <asm/io.h>
- #include <asm/tlbflush.h>
-
--static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
-- unsigned long phys_addr, pgprot_t pgprot)
-+extern rwlock_t vmlist_lock;
-+extern struct vm_struct *vmlist;
-+
-+static struct vm_struct *
-+get_io_vm_area(unsigned long size, unsigned long align, unsigned long flags)
- {
-+ struct vm_struct **p, *tmp, *area;
-+ unsigned long addr;
-+
-+ area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL);
-+ if (!area)
-+ return NULL;
-+
-+ align -= 1;
-+
-+ size += PAGE_SIZE;
-+ addr = VMALLOC_START;
-+ write_lock(&vmlist_lock);
-+ for (p = &vmlist; (tmp = *p); p = &tmp->next) {
-+ if ((unsigned long)tmp->addr < addr)
-+ continue;
-+ if ((size + addr) < addr)
-+ goto out;
-+ if (size + addr <= (unsigned long) tmp->addr)
-+ break;
-+ addr = tmp->size + (unsigned long) tmp->addr;
-+ if ((addr + align) < addr)
-+ goto out;
-+ addr = (addr + align) & ~align;
-+ if (addr > VMALLOC_END - size)
-+ goto out;
-+ }
-+ area->flags = flags;
-+ area->addr = (void *)addr;
-+ area->size = size;
-+ area->next = *p;
-+ *p = area;
-+ write_unlock(&vmlist_lock);
-+ return area;
-+
-+out:
-+ write_unlock(&vmlist_lock);
-+ kfree(area);
-+ return NULL;
-+}
-+
-+static inline void unmap_area_pte(pmd_t *pmd, unsigned long address, unsigned long size)
-+{
-+ pte_t *ptep;
- unsigned long end;
-
-+ if (pmd_none(*pmd))
-+ return;
-+ if (pmd_bad(*pmd)) {
-+ pmd_ERROR(*pmd);
-+ pmd_clear(pmd);
-+ return;
-+ }
-+ ptep = pte_offset_kernel(pmd, address);
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
-- if (address >= end)
-- BUG();
- do {
-- if (!pte_none(*pte)) {
-- printk("remap_area_pte: page already exists\n");
-- BUG();
-+ pte_t pte;
-+ pte = ptep_get_and_clear(ptep);
-+ address += PAGE_SIZE;
-+ ptep++;
-+ if (pte_none(pte))
-+ continue;
-+ if (pte_present(pte)) {
-+ unsigned long pfn = pte_pfn(pte);
-+ struct page *page;
-+
-+ if (!pfn_valid(pfn))
-+ continue;
-+ page = pfn_to_page(pfn);
-+ if (!PageReserved(page))
-+ __free_page(page);
-+ continue;
- }
-- set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot));
-+ printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
-+ } while (address < end);
-+}
-+
-+static inline void unmap_area_pmd(pgd_t *dir, unsigned long address, unsigned long size)
-+{
-+ pmd_t *pmd;
-+ unsigned long end;
-+
-+ if (pgd_none(*dir))
-+ return;
-+ if (pgd_bad(*dir)) {
-+ pgd_ERROR(*dir);
-+ pgd_clear(dir);
-+ return;
-+ }
-+ pmd = pmd_offset(dir, address);
-+ address &= ~PGDIR_MASK;
-+ end = address + size;
-+ if (end > PGDIR_SIZE)
-+ end = PGDIR_SIZE;
-+ do {
-+ unmap_area_pte(pmd, address, end - address);
-+ address = (address + PMD_SIZE) & PMD_MASK;
-+ pmd++;
-+ } while (address < end);
-+}
-+
-+static void
-+unmap_area_pages(unsigned long address, unsigned long size)
-+{
-+ unsigned long start = address;
-+ unsigned long end = address + size;
-+ pgd_t *dir;
-+
-+ dir = pgd_offset_k(address);
-+ flush_cache_vunmap(start, end);
-+ do {
-+ unmap_area_pmd(dir, address, end - address);
-+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
-+ dir++;
-+ } while (address && (address < end));
-+ flush_tlb_kernel_range(start, end);
-+}
-+
-+static inline void
-+remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
-+ unsigned long pfn, pgprot_t pgprot)
-+{
-+ unsigned long end;
-+
-+ address &= ~PMD_MASK;
-+ end = address + size;
-+ if (end > PMD_SIZE)
-+ end = PMD_SIZE;
-+ BUG_ON(address >= end);
-+ do {
-+ if (!pte_none(*pte))
-+ goto bad;
-+
-+ set_pte(pte, pfn_pte(pfn, pgprot));
- address += PAGE_SIZE;
-- phys_addr += PAGE_SIZE;
-+ pfn++;
- pte++;
- } while (address && (address < end));
-+ return;
-+
-+ bad:
-+ printk("remap_area_pte: page already exists\n");
-+ BUG();
- }
-
--static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
-- unsigned long phys_addr, unsigned long flags)
-+static inline int
-+remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
-+ unsigned long pfn, unsigned long flags)
- {
- unsigned long end;
- pgprot_t pgprot;
-@@ -64,51 +198,53 @@
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
-
-- phys_addr -= address;
-- if (address >= end)
-- BUG();
-+ pfn -= address >> PAGE_SHIFT;
-+ BUG_ON(address >= end);
-
- pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
- do {
- pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
- if (!pte)
- return -ENOMEM;
-- remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
-+ remap_area_pte(pte, address, end - address, pfn + (address >> PAGE_SHIFT), pgprot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
- }
-
--static int remap_area_pages(unsigned long address, unsigned long phys_addr,
-- unsigned long size, unsigned long flags)
-+static int
-+remap_area_pages(unsigned long start, unsigned long pfn,
-+ unsigned long size, unsigned long flags)
- {
-- int error;
-+ unsigned long address = start;
-+ unsigned long end = start + size;
-+ int err = 0;
- pgd_t * dir;
-- unsigned long end = address + size;
-
-- phys_addr -= address;
-+ pfn -= address >> PAGE_SHIFT;
- dir = pgd_offset(&init_mm, address);
-- flush_cache_all();
-- if (address >= end)
-- BUG();
-+ BUG_ON(address >= end);
- spin_lock(&init_mm.page_table_lock);
- do {
-- pmd_t *pmd;
-- pmd = pmd_alloc(&init_mm, dir, address);
-- error = -ENOMEM;
-- if (!pmd)
-+ pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
-+ if (!pmd) {
-+ err = -ENOMEM;
- break;
-+ }
- if (remap_area_pmd(pmd, address, end - address,
-- phys_addr + address, flags))
-+ pfn + (address >> PAGE_SHIFT), flags)) {
-+ err = -ENOMEM;
- break;
-- error = 0;
-+ }
-+
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
-+
- spin_unlock(&init_mm.page_table_lock);
-- flush_tlb_all();
-- return error;
-+ flush_cache_vmap(start, end);
-+ return err;
- }
-
- /*
-@@ -146,11 +282,11 @@
- /*
- * Ok, go for it..
- */
-- area = get_vm_area(size, VM_IOREMAP);
-+ area = get_io_vm_area(size, align, VM_IOREMAP);
- if (!area)
- return NULL;
- addr = area->addr;
-- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
-+ if (remap_area_pages((unsigned long) addr, phys_addr >> PAGE_SHIFT, size, flags)) {
- vfree(addr);
- return NULL;
- }
-@@ -159,5 +295,26 @@
-
- void __iounmap(void *addr)
- {
-- vfree((void *) (PAGE_MASK & (unsigned long) addr));
-+ struct vm_struct **p, *tmp;
-+
-+ if (!addr)
-+ return;
-+
-+ if ((PAGE_SIZE - 1) & (unsigned long)addr) {
-+ printk(KERN_ERR "Trying to iounmap() bad address (%p)\n", addr);
-+ return;
-+ }
-+
-+ write_lock(&vmlist_lock);
-+ for (p = &vmlist; (tmp = *p); p = &tmp->next) {
-+ if (tmp->addr == addr) {
-+ *p = tmp->next;
-+ unmap_area_pages((unsigned long) tmp->addr, tmp->size);
-+ write_unlock(&vmlist_lock);
-+ kfree(tmp);
-+ return;
-+ }
-+ }
-+ write_unlock(&vmlist_lock);
-+ printk(KERN_ERR "Trying to iounmap nonexistent area (%p)\n", addr);
- }
---- linux-2.6.5/arch/arm/mm/proc-xscale.S~heh 2004-04-03 22:38:05.000000000 -0500
-+++ linux-2.6.5/arch/arm/mm/proc-xscale.S 2004-04-30 20:57:36.000000000 -0400
-@@ -563,11 +563,62 @@
- movne r2, #0 @ no -> fault
-
- str r2, [r0] @ hardware version
-+
-+ @ We try to map 64K page entries when possible.
-+ @ We do that for kernel space only since the usage pattern from
-+ @ the setting of VM area is quite simple. User space is not worth
-+ @ the implied complexity because of ever randomly changing PTEs
-+ @ (page aging, swapout, etc) requiring constant coherency checks.
-+ @ Since PTEs are usually set in increasing order, we test the
-+ @ possibility for a large page only when given the last PTE of a
-+ @ 64K boundary.
-+ tsteq r1, #L_PTE_USER
-+ andeq r1, r0, #(15 << 2)
-+ teqeq r1, #(15 << 2)
-+ beq 1f
-+
- mov ip, #0
- mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
- mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
- mov pc, lr
-
-+ @ See if we have 16 identical PTEs but with consecutive base addresses
-+1: bic r3, r2, #0x0000f000
-+ mov r1, #0x0000f000
-+2: eor r2, r2, r3
-+ teq r2, r1
-+ bne 4f
-+ subs r1, r1, #0x00001000
-+ ldr r2, [r0, #-4]!
-+ bne 2b
-+ eors r2, r2, r3
-+ bne 4f
-+
-+ @ Now create our LARGE PTE from the current EXT one.
-+ bic r3, r3, #PTE_TYPE_MASK
-+ orr r3, r3, #PTE_TYPE_LARGE
-+ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0
-+ orr r2, r2, r2, lsl #2 @ add LARGE_AP1
-+ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2
-+ and r1, r3, #0x3c0 @ EXT_TEX
-+ bic r3, r3, #0x3c0
-+ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX
-+ orr r2, r2, r3 @ add remaining bits
-+
-+ @ then put it in the pagetable
-+ mov r3, r2
-+3: strd r2, [r0], #8
-+ tst r0, #(15 << 2)
-+ bne 3b
-+
-+ @ Then sync the 2 corresponding cache lines
-+ sub r0, r0, #(16 << 2)
-+ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
-+4: orr r0, r0, #(15 << 2)
-+ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
-+ mov ip, #0
-+ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
-+ mov pc, lr
-
- .ltorg
-
---- linux-2.6.5/arch/arm/mach-sa1100/Makefile~heh 2004-04-03 22:38:26.000000000 -0500
-+++ linux-2.6.5/arch/arm/mach-sa1100/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -3,7 +3,7 @@
- #
-
- # Common support
--obj-y := generic.o irq.o dma.o
-+obj-y := generic.o irq.o dma.o nmi-oopser.o
- obj-m :=
- obj-n :=
- obj- :=
-@@ -88,7 +88,7 @@
- obj-$(CONFIG_LEDS) += $(led-y)
-
- # SA1110 USB client support
--#obj-$(CONFIG_SA1100_USB) += usb/
-+obj-$(CONFIG_SA1100_USB) += usb/
-
- # Miscelaneous functions
- obj-$(CONFIG_PM) += pm.o sleep.o
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/strings.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,43 @@
-+/*
-+ * usb/strings.h
-+ *
-+ * Copyright (C) 2002 Russell King.
-+ *
-+ * USB device string handling, built upon usb buffers.
-+ */
-+#ifndef USBDEV_STRINGS_H
-+#define USBDEV_STRINGS_H
-+
-+#include <linux/spinlock.h>
-+
-+struct usb_buf;
-+
-+#define NR_STRINGS 8
-+
-+struct usb_string_descriptor;
-+
-+struct usbc_strs {
-+ spinlock_t lock;
-+ struct usb_buf *buf[NR_STRINGS];
-+};
-+
-+#define usbc_string_desc(buf) ((struct usb_string_descriptor *)(buf)->data)
-+
-+void usbc_string_from_cstr(struct usb_buf *buf, const char *str);
-+struct usb_buf *usbc_string_alloc(int len);
-+void usbc_string_free(struct usb_buf *buf);
-+
-+int usbc_string_add(struct usbc_strs *table, struct usb_buf *buf);
-+void usbc_string_del(struct usbc_strs *table, int nr);
-+
-+/*
-+ * Note: usbc_string_find() increments the buffer use count.
-+ * You must call usbb_put() after use.
-+ */
-+struct usb_buf *
-+usbc_string_find(struct usbc_strs *table, unsigned int lang, unsigned int idx);
-+
-+void usbc_string_free_all(struct usbc_strs *table);
-+void usbc_string_init(struct usbc_strs *table);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_ctl.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,114 @@
-+/*
-+ * Copyright (C) Compaq Computer Corporation, 1998, 1999
-+ * Copyright (C) Extenex Corporation 2001
-+ *
-+ * usb_ctl.h
-+ *
-+ * PRIVATE interface used to share info among components of the SA-1100 USB
-+ * core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
-+ * should use sa1100_usb.h.
-+ *
-+ */
-+
-+#ifndef _USB_CTL_H
-+#define _USB_CTL_H
-+
-+#include <asm/dma.h> /* dmach_t */
-+
-+struct usb_client;
-+
-+struct usb_stats_t {
-+ unsigned long ep0_fifo_write_failures;
-+ unsigned long ep0_bytes_written;
-+ unsigned long ep0_fifo_read_failures;
-+ unsigned long ep0_bytes_read;
-+};
-+
-+struct usb_info_t
-+{
-+ struct usb_client *client;
-+ dma_regs_t *dmach_tx, *dmach_rx;
-+ int state;
-+ unsigned char address;
-+ struct usb_stats_t stats;
-+};
-+
-+/* in usb_ctl.c */
-+extern struct usb_info_t usbd_info;
-+
-+/*
-+ * Function Prototypes
-+ */
-+enum { kError=-1, kEvSuspend=0, kEvReset=1,
-+ kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 };
-+int usbctl_next_state_on_event( int event );
-+
-+/* endpoint zero */
-+void ep0_reset(void);
-+void ep0_int_hndlr(void);
-+
-+/* receiver */
-+int ep1_recv(void);
-+int ep1_init(dma_regs_t *dma);
-+void ep1_int_hndlr(int status);
-+void ep1_reset(void);
-+void ep1_stall(void);
-+
-+/* xmitter */
-+void ep2_reset(void);
-+int ep2_init(dma_regs_t *dma);
-+void ep2_int_hndlr(int status);
-+void ep2_stall(void);
-+
-+#define UDC_write(reg, val) { \
-+ int i = 10000; \
-+ do { \
-+ (reg) = (val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: write %#x to %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while((reg) != (val)); \
-+}
-+
-+#define UDC_set(reg, val) { \
-+ int i = 10000; \
-+ do { \
-+ (reg) |= (val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: set %#x of %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while(!((reg) & (val))); \
-+}
-+
-+#define UDC_clear(reg, val) { \
-+ int i = 10000; \
-+ do { \
-+ (reg) &= ~(val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while((reg) & (val)); \
-+}
-+
-+#define UDC_flip(reg, val) { \
-+ int i = 10000; \
-+ (reg) = (val); \
-+ do { \
-+ (reg) = (val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while(((reg) & (val))); \
-+}
-+
-+
-+#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}}
-+#endif /* _USB_CTL_H */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_send.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,302 @@
-+/*
-+ * Generic xmit layer for the SA1100 USB client function
-+ * Copyright (c) 2001 by Nicolas Pitre
-+ *
-+ * This code was loosely inspired by the original version which was
-+ * Copyright (c) Compaq Computer Corporation, 1998-1999
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This is still work in progress...
-+ *
-+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
-+ * 15/03/2001 - ep2_start now sets UDCAR to overcome something that is hardware
-+ * bug, I think. green@iXcelerator.com
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/errno.h>
-+#include <linux/delay.h> // for the massive_attack hack 28Feb01ww
-+#include <linux/usb_ch9.h>
-+
-+#include <asm/dma.h>
-+
-+#include "usbdev.h"
-+#include "sa1100_usb.h"
-+#include "sa1100usb.h"
-+
-+static unsigned int ep2_curdmalen;
-+static unsigned int ep2_remain;
-+
-+static struct sausb_dev *ep2_dev;
-+
-+static void udc_set_cs2(u32 val, u32 mask, u32 check)
-+{
-+ int i = 0;
-+
-+ do {
-+ Ser0UDCCS2 = val;
-+ udelay(1);
-+ if ((Ser0UDCCS2 & mask) == check)
-+ return;
-+ } while (i++ < 10000);
-+
-+ printk("UDC: UDCCS2 write timed out: val=0x%08x\n", val);
-+}
-+
-+/* set feature stall executing, async */
-+static void ep2_start(struct sausb_dev *usb)
-+{
-+ ep2_curdmalen = min(ep2_remain, usb->ep[1].maxpktsize);
-+ if (ep2_curdmalen == 0)
-+ return;
-+
-+ /*
-+ * must do this _before_ queue buffer..
-+ * stop NAKing IN tokens
-+ */
-+ udc_set_cs2(usb->ep[1].udccs | UDCCS2_TPC, UDCCS2_TPC, 0);
-+
-+ UDC_write(Ser0UDCIMP, ep2_curdmalen - 1);
-+
-+ /* Remove if never seen...8Mar01ww */
-+ {
-+ int massive_attack = 20;
-+ while (Ser0UDCIMP != ep2_curdmalen - 1 && massive_attack--) {
-+ printk("usbsnd: Oh no you don't! Let me spin...");
-+ udelay(500);
-+ printk("and try again...\n");
-+ UDC_write(Ser0UDCIMP, ep2_curdmalen - 1);
-+ }
-+ if (massive_attack != 20) {
-+ if (Ser0UDCIMP != ep2_curdmalen - 1)
-+ printk("usbsnd: Massive attack FAILED. %d\n",
-+ 20 - massive_attack);
-+ else
-+ printk("usbsnd: Massive attack WORKED. %d\n",
-+ 20 - massive_attack);
-+ }
-+ }
-+ /* End remove if never seen... 8Mar01ww */
-+
-+ /*
-+ * fight stupid silicon bug
-+ */
-+ Ser0UDCAR = usb->ctl->address;
-+
-+ sa1100_start_dma(usb->ep[1].dmach, usb->ep[1].pktdma, ep2_curdmalen);
-+}
-+
-+static void udc_ep2_done(struct sausb_dev *usb, int flag)
-+{
-+ int size = usb->ep[1].buflen - ep2_remain;
-+
-+ if (!usb->ep[1].buflen)
-+ return;
-+
-+ dma_unmap_single(usb->dev, usb->ep[1].bufdma, usb->ep[1].buflen,
-+ DMA_TO_DEVICE);
-+
-+ usb->ep[1].bufdma = 0;
-+ usb->ep[1].buflen = 0;
-+ usb->ep[1].pktdma = 0;
-+
-+ if (usb->ep[1].cb_func)
-+ usb->ep[1].cb_func(usb->ep[1].cb_data, flag, size);
-+}
-+
-+/*
-+ * Initialisation. Clear out the status.
-+ */
-+void udc_ep2_init(struct sausb_dev *usb)
-+{
-+ ep2_dev = usb;
-+
-+ usb->ep[1].udccs = UDCCS2_FST;
-+
-+ BUG_ON(usb->ep[1].buflen);
-+ BUG_ON(usb->ep[1].pktlen);
-+
-+ sa1100_reset_dma(usb->ep[1].dmach);
-+}
-+
-+/*
-+ * Note: rev A0-B2 chips don't like FST
-+ */
-+void udc_ep2_halt(struct sausb_dev *usb, int halt)
-+{
-+ usb->ep[1].host_halt = halt;
-+
-+ if (halt) {
-+ usb->ep[1].udccs |= UDCCS2_FST;
-+ udc_set_cs2(UDCCS2_FST, UDCCS2_FST, UDCCS2_FST);
-+ } else {
-+ sa1100_clear_dma(usb->ep[1].dmach);
-+
-+ udc_set_cs2(UDCCS2_FST, UDCCS2_FST, UDCCS2_FST);
-+ udc_set_cs2(0, UDCCS2_FST, 0);
-+ udc_set_cs2(UDCCS2_SST, UDCCS2_SST, 0);
-+
-+ usb->ep[1].udccs &= ~UDCCS2_FST;
-+
-+ udc_ep2_done(usb, -EINTR);
-+ }
-+}
-+
-+/*
-+ * This gets called when we receive a SET_CONFIGURATION packet to EP0.
-+ * We were configured. We can now send packets to the host.
-+ */
-+void udc_ep2_config(struct sausb_dev *usb, unsigned int maxpktsize)
-+{
-+ /*
-+ * We shouldn't be transmitting anything...
-+ */
-+ BUG_ON(usb->ep[1].buflen);
-+ BUG_ON(usb->ep[1].pktlen);
-+
-+ /*
-+ * Set our configuration.
-+ */
-+ usb->ep[1].maxpktsize = maxpktsize;
-+ usb->ep[1].configured = 1;
-+
-+ /*
-+ * Clear any pending TPC status.
-+ */
-+ udc_set_cs2(UDCCS2_TPC, UDCCS2_TPC, 0);
-+
-+ /*
-+ * Enable EP2 interrupts.
-+ */
-+ usb->udccr &= ~UDCCR_TIM;
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+
-+ usb->ep[1].udccs = 0;
-+}
-+
-+/*
-+ * We saw a reset from the attached hub, or were deconfigured.
-+ * This means we are no longer configured.
-+ */
-+void udc_ep2_reset(struct sausb_dev *usb)
-+{
-+ /*
-+ * Disable EP2 interrupts.
-+ */
-+ usb->udccr |= UDCCR_TIM;
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+
-+ usb->ep[1].configured = 0;
-+ usb->ep[1].maxpktsize = 0;
-+
-+ sa1100_reset_dma(usb->ep[1].dmach);
-+ udc_ep2_done(usb, -EINTR);
-+}
-+
-+void udc_ep2_int_hndlr(struct sausb_dev *usb)
-+{
-+ u32 status = Ser0UDCCS2;
-+
-+ // check for stupid silicon bug.
-+ if (Ser0UDCAR != usb->ctl->address)
-+ Ser0UDCAR = usb->ctl->address;
-+
-+ udc_set_cs2(usb->ep[1].udccs | UDCCS2_SST, UDCCS2_SST, 0);
-+
-+ if (!(status & UDCCS2_TPC)) {
-+ printk("usb_send: Not TPC: UDCCS2 = %x\n", status);
-+ return;
-+ }
-+
-+ sa1100_stop_dma(usb->ep[1].dmach);
-+
-+ if (status & (UDCCS2_TPE | UDCCS2_TUR)) {
-+ printk("usb_send: transmit error %x\n", status);
-+ usb->ep[1].fifo_errs ++;
-+ udc_ep2_done(usb, -EIO);
-+ } else {
-+ unsigned int imp;
-+#if 1 // 22Feb01ww/Oleg
-+ imp = ep2_curdmalen;
-+#else
-+ // this is workaround for case when setting
-+ // of Ser0UDCIMP was failed
-+ imp = Ser0UDCIMP + 1;
-+#endif
-+ usb->ep[1].pktdma += imp;
-+ ep2_remain -= imp;
-+
-+ usb->ep[1].bytes += imp;
-+ usb->ep[1].packets++;
-+
-+ sa1100_clear_dma(usb->ep[1].dmach);
-+
-+ if (ep2_remain != 0) {
-+ ep2_start(usb);
-+ } else {
-+ udc_ep2_done(usb, 0);
-+ }
-+ }
-+}
-+
-+int udc_ep2_send(struct sausb_dev *usb, char *buf, int len)
-+{
-+ unsigned long flags;
-+ dma_addr_t dma;
-+ int ret;
-+
-+ if (!buf || len == 0)
-+ return -EINVAL;
-+
-+ dma = dma_map_single(usb->dev, buf, len, DMA_TO_DEVICE);
-+
-+ spin_lock_irqsave(&usb->lock, flags);
-+ do {
-+ if (!usb->ep[1].configured) {
-+ ret = -ENODEV;
-+ break;
-+ }
-+
-+ if (usb->ep[1].buflen) {
-+ ret = -EBUSY;
-+ break;
-+ }
-+
-+ usb->ep[1].bufdma = dma;
-+ usb->ep[1].buflen = len;
-+ usb->ep[1].pktdma = dma;
-+ ep2_remain = len;
-+
-+ sa1100_clear_dma(usb->ep[1].dmach);
-+
-+ ep2_start(usb);
-+ ret = 0;
-+ } while (0);
-+ spin_unlock_irqrestore(&usb->lock, flags);
-+
-+ if (ret)
-+ dma_unmap_single(usb->dev, dma, len, DMA_TO_DEVICE);
-+
-+ return ret;
-+}
-+
-+void udc_ep2_send_reset(struct sausb_dev *usb)
-+{
-+ sa1100_reset_dma(usb->ep[1].dmach);
-+ udc_ep2_done(usb, -EINTR);
-+}
-+
-+int udc_ep2_idle(struct sausb_dev *usb)
-+{
-+ if (!usb->ep[1].configured)
-+ return -ENODEV;
-+
-+ if (usb->ep[1].buflen)
-+ return -EBUSY;
-+
-+ return 0;
-+}
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-char.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,709 @@
-+/*
-+ * (C) Copyright 2000-2001 Extenex Corporation
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * usb-char.c
-+ *
-+ * Miscellaneous character device interface for SA1100 USB function
-+ * driver.
-+ *
-+ * Background:
-+ * The SA1100 function driver ported from the Compaq Itsy project
-+ * has an interface, usb-eth.c, to feed network packets over the
-+ * usb wire and into the Linux TCP/IP stack.
-+ *
-+ * This file replaces that one with a simple character device
-+ * interface that allows unstructured "byte pipe" style reads and
-+ * writes over the USB bulk endpoints by userspace programs.
-+ *
-+ * A new define, CONFIG_SA1100_USB_NETLINK, has been created that,
-+ * when set, (the default) causes the ethernet interface to be used.
-+ * When not set, this more pedestrian character interface is linked
-+ * in instead.
-+ *
-+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
-+ *
-+ * ward.willats@extenex.com
-+ *
-+ * To do:
-+ * - Can't dma into ring buffer directly with dma_map/unmap usb_recv
-+ * uses and get bytes out at the same time DMA is going on. Investigate:
-+ * a) changing usb_recv to use alloc_consistent() at client request; or
-+ * b) non-ring-buffer based data structures. In the meantime, I am using
-+ * a bounce buffer. Simple, but wasteful.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/config.h>
-+#include <linux/miscdevice.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/cache.h>
-+#include <linux/poll.h>
-+#include <linux/circ_buf.h>
-+#include <linux/timer.h>
-+#include <linux/usb_ch9.h>
-+
-+#include <asm/io.h>
-+#include <asm/semaphore.h>
-+#include <asm/page.h>
-+#include <asm/mach-types.h>
-+
-+#include "usb-char.h"
-+#include "client.h"
-+
-+
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Driver Options
-+//////////////////////////////////////////////////////////////////////////////
-+
-+#define VERSION "0.4"
-+
-+
-+#define VERBOSITY 1
-+
-+#if VERBOSITY
-+# define PRINTK(x, a...) printk (x, ## a)
-+#else
-+# define PRINTK(x, a...) /**/
-+#endif
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Globals - Macros - Enums - Structures
-+//////////////////////////////////////////////////////////////////////////////
-+#ifndef MIN
-+#define MIN( a, b ) ((a)<(b)?(a):(b))
-+#endif
-+
-+typedef int bool; enum { false = 0, true = 1 };
-+
-+static const char pszMe[] = "usbchr: ";
-+
-+static wait_queue_head_t wq_read;
-+static wait_queue_head_t wq_write;
-+static wait_queue_head_t wq_poll;
-+
-+/* Serialze multiple writers onto the transmit hardware
-+.. since we sleep the writer during transmit to stay in
-+.. sync. (Multiple writers don't make much sense, but..) */
-+static DECLARE_MUTEX( xmit_sem );
-+
-+// size of usb DATA0/1 packets. 64 is standard maximum
-+// for bulk transport, though most hosts seem to be able
-+// to handle larger.
-+#define TX_PACKET_SIZE 64
-+#define RX_PACKET_SIZE 64
-+#define RBUF_SIZE (4*PAGE_SIZE)
-+
-+static struct wcirc_buf {
-+ char *buf;
-+ int in;
-+ int out;
-+} rx_ring = { NULL, 0, 0 };
-+
-+static struct {
-+ unsigned long cnt_rx_complete;
-+ unsigned long cnt_rx_errors;
-+ unsigned long bytes_rx;
-+ unsigned long cnt_tx_timeouts;
-+ unsigned long cnt_tx_errors;
-+ unsigned long bytes_tx;
-+} charstats;
-+
-+
-+static char * tx_buf = NULL;
-+static char * packet_buffer = NULL;
-+static int sending = 0;
-+static int usb_ref_count = 0;
-+static int last_tx_result = 0;
-+static int last_rx_result = 0;
-+static int last_tx_size = 0;
-+static struct timer_list tx_timer;
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Prototypes
-+//////////////////////////////////////////////////////////////////////////////
-+static char * what_the_f( int e );
-+static void free_txrx_buffers( void );
-+static void twiddle_descriptors(struct usb_client *client);
-+static int usbc_open( struct inode *pInode, struct file *pFile );
-+static void rx_done_callback_packet_buffer(void *data, int flag, int size );
-+
-+static void tx_timeout( unsigned long );
-+static void tx_done_callback(void *data, int flag, int size );
-+
-+static ssize_t usbc_read( struct file *, char *, size_t, loff_t * );
-+static ssize_t usbc_write( struct file *, const char *, size_t, loff_t * );
-+static unsigned int usbc_poll( struct file *pFile, poll_table * pWait );
-+static int usbc_ioctl( struct inode *pInode, struct file *pFile,
-+ unsigned int nCmd, unsigned long argument );
-+static int usbc_close( struct inode *pInode, struct file *pFile );
-+
-+#ifdef CONFIG_SA1100_EXTENEX1
-+static void extenex_configured_notify_proc( void );
-+#endif
-+//////////////////////////////////////////////////////////////////////////////
-+// Private Helpers
-+//////////////////////////////////////////////////////////////////////////////
-+
-+static char * what_the_f( int e )
-+{
-+ char * p;
-+ switch( e ) {
-+ case 0:
-+ p = "noErr";
-+ break;
-+ case -ENODEV:
-+ p = "ENODEV - usb not in config state";
-+ break;
-+ case -EBUSY:
-+ p = "EBUSY - another request on the hardware";
-+ break;
-+ case -EAGAIN:
-+ p = "EAGAIN";
-+ break;
-+ case -EINTR:
-+ p = "EINTR - interrupted\n";
-+ break;
-+ case -EPIPE:
-+ p = "EPIPE - zero length xfer\n";
-+ break;
-+ default:
-+ p = "????";
-+ break;
-+ }
-+ return p;
-+}
-+
-+static void free_txrx_buffers( void )
-+{
-+ if ( rx_ring.buf != NULL ) {
-+ kfree( rx_ring.buf );
-+ rx_ring.buf = NULL;
-+ }
-+ if ( packet_buffer != NULL ) {
-+ kfree( packet_buffer );
-+ packet_buffer = NULL;
-+ }
-+ if ( tx_buf != NULL ) {
-+ kfree( tx_buf );
-+ tx_buf = NULL;
-+ }
-+}
-+
-+/* twiddle_descriptors()
-+ * It is between open() and start(). Setup descriptors.
-+ */
-+static void twiddle_descriptors(struct usb_client *client)
-+{
-+ struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
-+
-+ cdb->ep1.wMaxPacketSize = cpu_to_le16(RX_PACKET_SIZE);
-+ cdb->ep2.wMaxPacketSize = cpu_to_le16(TX_PACKET_SIZE);
-+
-+#ifdef CONFIG_SA1100_EXTENEX1
-+ if (machine_is_extenex1()) {
-+ int nr;
-+
-+ cdb->cfg.bmAttributes = USB_CONFIG_SELFPOWERED;
-+ cdb->cfg.MaxPower = 0;
-+
-+ nr = sa1100_usb_add_string(client->ctl, "HHT Bulk Transfer");
-+
-+ if (nr > 0)
-+ cdb->intf.iInterface = nr;
-+ }
-+#endif
-+}
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// ASYNCHRONOUS
-+//////////////////////////////////////////////////////////////////////////////
-+static void kick_start_rx( void )
-+{
-+ if ( usb_ref_count ) {
-+ int total_space = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE );
-+ if ( total_space >= RX_PACKET_SIZE ) {
-+ sa1100_usb_recv_set_callback(rx_done_callback_packet_buffer, NULL);
-+ sa1100_usb_recv( packet_buffer, RX_PACKET_SIZE);
-+ }
-+ }
-+}
-+/*
-+ * rx_done_callback_packet_buffer()
-+ * We have completed a DMA xfer into the temp packet buffer.
-+ * Move to ring.
-+ *
-+ * flag values:
-+ * on init, -EAGAIN
-+ * on reset, -EINTR
-+ * on RPE, -EIO
-+ * on short packet -EPIPE
-+ */
-+static void
-+rx_done_callback_packet_buffer(void *data, int flag, int size )
-+{
-+ charstats.cnt_rx_complete++;
-+
-+ if ( flag == 0 || flag == -EPIPE ) {
-+ size_t n;
-+
-+ charstats.bytes_rx += size;
-+
-+ n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
-+ n = MIN( n, size );
-+ size -= n;
-+
-+ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n );
-+ rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1);
-+ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size );
-+ rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1);
-+
-+ wake_up_interruptible( &wq_read );
-+ wake_up_interruptible( &wq_poll );
-+
-+ last_rx_result = 0;
-+
-+ kick_start_rx();
-+
-+ } else if ( flag != -EAGAIN ) {
-+ charstats.cnt_rx_errors++;
-+ last_rx_result = flag;
-+ wake_up_interruptible( &wq_read );
-+ wake_up_interruptible( &wq_poll );
-+ }
-+ else /* init, start a read */
-+ kick_start_rx();
-+}
-+
-+
-+static void tx_timeout( unsigned long unused )
-+{
-+ printk( "%stx timeout\n", pszMe );
-+ sa1100_usb_send_reset();
-+ charstats.cnt_tx_timeouts++;
-+}
-+
-+
-+// on init, -EAGAIN
-+// on reset, -EINTR
-+// on TPE, -EIO
-+static void tx_done_callback(void *data, int flags, int size )
-+{
-+ if ( flags == 0 )
-+ charstats.bytes_tx += size;
-+ else
-+ charstats.cnt_tx_errors++;
-+ last_tx_size = size;
-+ last_tx_result = flags;
-+ sending = 0;
-+ wake_up_interruptible( &wq_write );
-+ wake_up_interruptible( &wq_poll );
-+}
-+
-+
-+static struct usb_client usbc_client = {
-+ .name = "usb-char",
-+
-+ /*
-+ * USB client identification for host use in CPU endian.
-+ */
-+ .vendor = 0,
-+ .product = 0,
-+ .version = 0,
-+ .class = 0xff,
-+ .subclass = 0,
-+ .protocol = 0,
-+};
-+
-+#ifdef CONFIG_SA1100_EXTENEX1
-+#include "../../../drivers/char/ex_gpio.h"
-+static void extenex_state_change(void *data, int state, int oldstate)
-+{
-+ if (exgpio_play_string( "440,1:698,1") == -EAGAIN)
-+ printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe );
-+}
-+#endif
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Workers
-+//////////////////////////////////////////////////////////////////////////////
-+
-+static int usbc_open(struct inode *pInode, struct file *pFile)
-+{
-+ int retval = 0;
-+
-+ PRINTK( KERN_DEBUG "%sopen()\n", pszMe );
-+
-+#ifdef CONFIG_SA1100_EXTENEX1
-+ if (machine_is_extenex1()) {
-+ usbc_client.vendor = 0x0c9f;
-+ usbc_client.product = 0x0100;
-+ usbc_client.version = 0x0001;
-+ usbc_client.manufacturer_str = "Extenex";
-+ usbc_client.product_str = "Handheld Theater";
-+ usbc_client.serial_str = "00000000";
-+ usbc_client.state_change = extenex_state_change;
-+ }
-+#endif
-+
-+ /* start usb core */
-+ retval = usbctl_open(&usbc_client);
-+ if (retval)
-+ return retval;
-+
-+ /* allocate memory */
-+ if ( usb_ref_count == 0 ) {
-+ tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
-+ if ( tx_buf == NULL ) {
-+ printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe );
-+ goto malloc_fail;
-+ }
-+ rx_ring.buf =
-+ (char*) kmalloc( RBUF_SIZE, GFP_KERNEL );
-+
-+ if ( rx_ring.buf == NULL ) {
-+ printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe );
-+ goto malloc_fail;
-+ }
-+
-+ packet_buffer =
-+ (char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
-+
-+ if ( packet_buffer == NULL ) {
-+ printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe );
-+ goto malloc_fail;
-+ }
-+ rx_ring.in = rx_ring.out = 0;
-+ memset( &charstats, 0, sizeof( charstats ) );
-+ sending = 0;
-+ last_tx_result = 0;
-+ last_tx_size = 0;
-+ }
-+
-+ /* modify default descriptors */
-+ twiddle_descriptors(&usbc_client);
-+
-+ retval = usbctl_start(&usbc_client);
-+ if ( retval ) {
-+ printk( "%sAGHH! Could not USB core\n", pszMe );
-+ free_txrx_buffers();
-+ return retval;
-+ }
-+ usb_ref_count++; /* must do _before_ kick_start() */
-+ MOD_INC_USE_COUNT;
-+ kick_start_rx();
-+ return 0;
-+
-+ malloc_fail:
-+ free_txrx_buffers();
-+ return -ENOMEM;
-+}
-+
-+/*
-+ * Read endpoint. Note that you can issue a read to an
-+ * unconfigured endpoint. Eventually, the host may come along
-+ * and configure underneath this module and data will appear.
-+ */
-+static ssize_t usbc_read( struct file *pFile, char *pUserBuffer,
-+ size_t stCount, loff_t *pPos )
-+{
-+ ssize_t retval;
-+ unsigned long flags;
-+ DECLARE_WAITQUEUE( wait, current );
-+
-+ PRINTK( KERN_DEBUG "%sread()\n", pszMe );
-+
-+ local_irq_save(flags);
-+ if ( last_rx_result == 0 ) {
-+ local_irq_restore( flags );
-+ } else { /* an error happended and receiver is paused */
-+ local_irq_restore( flags );
-+ last_rx_result = 0;
-+ kick_start_rx();
-+ }
-+
-+ add_wait_queue( &wq_read, &wait );
-+ while( 1 ) {
-+ ssize_t bytes_avail;
-+ ssize_t bytes_to_end;
-+
-+ set_current_state( TASK_INTERRUPTIBLE );
-+
-+ /* snap ring buf state */
-+ local_irq_save( flags );
-+ bytes_avail = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE );
-+ bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
-+ local_irq_restore( flags );
-+
-+ if ( bytes_avail != 0 ) {
-+ ssize_t bytes_to_move = MIN( stCount, bytes_avail );
-+ retval = 0; // will be bytes transfered
-+ if ( bytes_to_move != 0 ) {
-+ size_t n = MIN( bytes_to_end, bytes_to_move );
-+ if ( copy_to_user( pUserBuffer,
-+ &rx_ring.buf[ rx_ring.out ],
-+ n ) ) {
-+ retval = -EFAULT;
-+ break;
-+ }
-+ bytes_to_move -= n;
-+ retval += n;
-+ // might go 1 char off end, so wrap
-+ rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1);
-+ if ( copy_to_user( pUserBuffer + n,
-+ &rx_ring.buf[ rx_ring.out ],
-+ bytes_to_move )
-+ ) {
-+ retval = -EFAULT;
-+ break;
-+ }
-+ rx_ring.out += bytes_to_move; // cannot wrap
-+ retval += bytes_to_move;
-+ kick_start_rx();
-+ }
-+ break;
-+ }
-+ else if ( last_rx_result ) {
-+ retval = last_rx_result;
-+ break;
-+ }
-+ else if ( pFile->f_flags & O_NONBLOCK ) { // no data, can't sleep
-+ retval = -EAGAIN;
-+ break;
-+ }
-+ else if ( signal_pending( current ) ) { // no data, can sleep, but signal
-+ retval = -ERESTARTSYS;
-+ break;
-+ }
-+ schedule(); // no data, can sleep
-+ }
-+ set_current_state( TASK_RUNNING );
-+ remove_wait_queue( &wq_read, &wait );
-+
-+ if ( retval < 0 )
-+ printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) );
-+ return retval;
-+}
-+
-+/*
-+ * Write endpoint. This routine attempts to break the passed in buffer
-+ * into usb DATA0/1 packet size chunks and send them to the host.
-+ * (The lower-level driver tries to do this too, but easier for us
-+ * to manage things here.)
-+ *
-+ * We are at the mercy of the host here, in that it must send an IN
-+ * token to us to pull this data back, so hopefully some higher level
-+ * protocol is expecting traffic to flow in that direction so the host
-+ * is actually polling us. To guard against hangs, a 5 second timeout
-+ * is used.
-+ *
-+ * This routine takes some care to only report bytes sent that have
-+ * actually made it across the wire. Thus we try to stay in lockstep
-+ * with the completion routine and only have one packet on the xmit
-+ * hardware at a time. Multiple simultaneous writers will get
-+ * "undefined" results.
-+ *
-+ */
-+static ssize_t usbc_write( struct file *pFile, const char * pUserBuffer,
-+ size_t stCount, loff_t *pPos )
-+{
-+ ssize_t retval = 0;
-+ ssize_t stSent = 0;
-+
-+ DECLARE_WAITQUEUE( wait, current );
-+
-+ PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount );
-+
-+ down( &xmit_sem ); // only one thread onto the hardware at a time
-+
-+ while( stCount != 0 && retval == 0 ) {
-+ int nThisTime = MIN( TX_PACKET_SIZE, stCount );
-+ copy_from_user( tx_buf, pUserBuffer, nThisTime );
-+ sending = nThisTime;
-+ sa1100_usb_send_set_callback(tx_done_callback, NULL);
-+ retval = sa1100_usb_send( tx_buf, nThisTime);
-+ if ( retval < 0 ) {
-+ char * p = what_the_f( retval );
-+ printk( "%sCould not queue xmission. rc=%d - %s\n",
-+ pszMe, retval, p );
-+ sending = 0;
-+ break;
-+ }
-+ /* now have something on the diving board */
-+ add_wait_queue( &wq_write, &wait );
-+ tx_timer.expires = jiffies + ( HZ * 5 );
-+ add_timer( &tx_timer );
-+ while( 1 ) {
-+ set_current_state( TASK_INTERRUPTIBLE );
-+ if ( sending == 0 ) { /* it jumped into the pool */
-+ del_timer( &tx_timer );
-+ retval = last_tx_result;
-+ if ( retval == 0 ) {
-+ stSent += last_tx_size;
-+ pUserBuffer += last_tx_size;
-+ stCount -= last_tx_size;
-+ }
-+ else
-+ printk( "%sxmission error rc=%d - %s\n",
-+ pszMe, retval, what_the_f(retval) );
-+ break;
-+ }
-+ else if ( signal_pending( current ) ) {
-+ del_timer( &tx_timer );
-+ printk( "%ssignal\n", pszMe );
-+ retval = -ERESTARTSYS;
-+ break;
-+ }
-+ schedule();
-+ }
-+ set_current_state( TASK_RUNNING );
-+ remove_wait_queue( &wq_write, &wait );
-+ }
-+
-+ up( &xmit_sem );
-+
-+ if ( 0 == retval )
-+ retval = stSent;
-+ return retval;
-+}
-+
-+static unsigned int usbc_poll( struct file *pFile, poll_table * pWait )
-+{
-+ unsigned int retval = 0;
-+
-+ PRINTK( KERN_DEBUG "%poll()\n", pszMe );
-+
-+ poll_wait( pFile, &wq_poll, pWait );
-+
-+ if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) )
-+ retval |= POLLIN | POLLRDNORM;
-+ if ( sa1100_usb_xmitter_avail() )
-+ retval |= POLLOUT | POLLWRNORM;
-+ return retval;
-+}
-+
-+static int usbc_ioctl( struct inode *pInode, struct file *pFile,
-+ unsigned int nCmd, unsigned long argument )
-+{
-+ int retval = 0;
-+
-+ switch( nCmd ) {
-+
-+ case USBC_IOC_FLUSH_RECEIVER:
-+ sa1100_usb_recv_reset();
-+ rx_ring.in = rx_ring.out = 0;
-+ break;
-+
-+ case USBC_IOC_FLUSH_TRANSMITTER:
-+ sa1100_usb_send_reset();
-+ break;
-+
-+ case USBC_IOC_FLUSH_ALL:
-+ sa1100_usb_recv_reset();
-+ rx_ring.in = rx_ring.out = 0;
-+ sa1100_usb_send_reset();
-+ break;
-+
-+ default:
-+ retval = -ENOIOCTLCMD;
-+ break;
-+
-+ }
-+ return retval;
-+}
-+
-+
-+static int usbc_close( struct inode *pInode, struct file * pFile )
-+{
-+ PRINTK( KERN_DEBUG "%sclose()\n", pszMe );
-+ if ( --usb_ref_count == 0 ) {
-+ down( &xmit_sem );
-+ usbctl_stop(&usbc_client);
-+ free_txrx_buffers();
-+ del_timer( &tx_timer );
-+ usbctl_close(&usbc_client);
-+ up(&xmit_sem);
-+ }
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Initialization
-+//////////////////////////////////////////////////////////////////////////////
-+
-+static struct file_operations usbc_fops = {
-+ owner: THIS_MODULE,
-+ open: usbc_open,
-+ read: usbc_read,
-+ write: usbc_write,
-+ poll: usbc_poll,
-+ ioctl: usbc_ioctl,
-+ release: usbc_close,
-+};
-+
-+static struct miscdevice usbc_misc_device = {
-+ USBC_MINOR,
-+ "usb_char",
-+ &usbc_fops
-+};
-+
-+/*
-+ * usbc_init()
-+ */
-+
-+static int __init usbc_init( void )
-+{
-+ int rc;
-+
-+#if !defined( CONFIG_ARCH_SA1100 )
-+ return -ENODEV;
-+#endif
-+
-+ if ( (rc = misc_register( &usbc_misc_device )) != 0 ) {
-+ printk( KERN_WARNING "%sCould not register device 10, "
-+ "%d. (%d)\n", pszMe, USBC_MINOR, rc );
-+ return -EBUSY;
-+ }
-+
-+ // initialize wait queues
-+ init_waitqueue_head( &wq_read );
-+ init_waitqueue_head( &wq_write );
-+ init_waitqueue_head( &wq_poll );
-+
-+ // initialize tx timeout timer
-+ init_timer( &tx_timer );
-+ tx_timer.function = tx_timeout;
-+
-+ printk( KERN_INFO "USB Function Character Driver Interface"
-+ " - %s, (C) 2001, Extenex Corp.\n", VERSION
-+ );
-+
-+ return rc;
-+}
-+
-+static void __exit usbc_exit( void )
-+{
-+}
-+
-+module_init(usbc_init);
-+module_exit(usbc_exit);
-+
-+// end: usb-char.c
-+
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-eth.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,535 @@
-+/*
-+ * Network driver for the SA1100 USB client function
-+ * Copyright (c) 2001 by Nicolas Pitre
-+ *
-+ * This code was loosely inspired by the original initial ethernet test driver
-+ * Copyright (c) Compaq Computer Corporation, 1999
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * Issues:
-+ * - DMA needs 8 byte aligned buffer, but causes inefficiencies
-+ * in the IP code.
-+ * - stall endpoint operations appeared to be very unstable.
-+ */
-+
-+/*
-+ * Define RX_NO_COPY if you want data to arrive directly into the
-+ * receive network buffers, instead of arriving into bounce buffer
-+ * and then get copied to network buffer.
-+ *
-+ * Since the SA1100 DMA engine is unable to cope with unaligned
-+ * buffer addresses, we need to use bounce buffers or suffer the
-+ * alignment trap performance hit.
-+ */
-+#undef RX_NO_COPY
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/random.h>
-+#include <linux/usb_ch9.h>
-+
-+#include "client.h"
-+
-+
-+#define ETHERNET_VENDOR_ID 0x049f
-+#define ETHERNET_PRODUCT_ID 0x505A
-+#define MAX_PACKET 32768
-+
-+/*
-+ * This is our usb "packet size", and must match the host "packet size".
-+ */
-+static int usb_rsize = 64;
-+static int usb_wsize = 64;
-+
-+struct usbe_info {
-+ struct net_device dev;
-+ struct usb_client client;
-+ struct sk_buff *cur_tx_skb;
-+ struct sk_buff *next_tx_skb;
-+ struct sk_buff *cur_rx_skb;
-+ struct sk_buff *next_rx_skb;
-+#ifndef RX_NO_COPY
-+ char *dmabuf; // dma expects it's buffers to be aligned on 8 bytes boundary
-+#endif
-+ struct net_device_stats stats;
-+};
-+
-+
-+static int usbeth_change_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if (new_mtu <= sizeof(struct ethhdr) || new_mtu > MAX_PACKET)
-+ return -EINVAL;
-+
-+ // no second zero-length packet read wanted after mtu-sized packets
-+ if (((new_mtu + sizeof(struct ethhdr)) % usb_rsize) == 0)
-+ return -EDOM;
-+
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+
-+static struct sk_buff *usb_new_recv_skb(struct usbe_info *usbe)
-+{
-+ struct sk_buff *skb;
-+
-+ skb = alloc_skb(2 + sizeof(struct ethhdr) + usbe->dev.mtu,
-+ GFP_ATOMIC);
-+
-+ if (skb)
-+ skb_reserve(skb, 2);
-+
-+ return skb;
-+}
-+
-+static void usbeth_recv_callback(void *data, int flag, int len)
-+{
-+ struct usbe_info *usbe = data;
-+ struct sk_buff *skb;
-+ unsigned int size;
-+ char *buf;
-+
-+ skb = usbe->cur_rx_skb;
-+
-+ /* flag validation */
-+ if (flag != 0)
-+ goto error;
-+
-+ /*
-+ * Make sure we have enough room left in the buffer.
-+ */
-+ if (len > skb_tailroom(skb)) {
-+ usbe->stats.rx_over_errors++;
-+ usbe->stats.rx_errors++;
-+ goto oversize;
-+ }
-+
-+ /*
-+ * If the packet is smaller than usb_rsize bytes, the packet
-+ * is complete, and we need to use the next receive buffer.
-+ */
-+ if (len != usb_rsize)
-+ usbe->cur_rx_skb = usbe->next_rx_skb;
-+
-+ /*
-+ * Put the data onto the socket buffer and resume USB receive.
-+ */
-+#ifndef RX_NO_COPY
-+ memcpy(skb_put(skb, len), usbe->dmabuf, len);
-+ buf = usbe->dmabuf;
-+ size = usb_rsize;
-+#else
-+ skb_put(skb, len);
-+ buf = usbe->cur_rx_skb->tail;
-+ size = skb_tailroom(usbe->cur_rx_skb);
-+#endif
-+ usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size);
-+
-+ if (len == usb_rsize)
-+ return;
-+
-+ /*
-+ * A frame must contain at least an ethernet header.
-+ */
-+ if (skb->len < sizeof(struct ethhdr)) {
-+ usbe->stats.rx_length_errors++;
-+ usbe->stats.rx_errors++;
-+ goto recycle;
-+ }
-+
-+ /*
-+ * MAC must match our address or the broadcast address.
-+ * Really, we should let any packet through, otherwise
-+ * things that rely on multicast won't work.
-+ */
-+ if (memcmp(skb->data, usbe->dev.dev_addr, ETH_ALEN) &&
-+ memcmp(skb->data, usbe->dev.broadcast, ETH_ALEN)) {
-+ usbe->stats.rx_frame_errors++;
-+ usbe->stats.rx_errors++;
-+ goto recycle;
-+ }
-+
-+ /*
-+ * We're going to consume this SKB. Get a new skb to
-+ * replace it with. IF this fails, we'd better recycle
-+ * the one we have.
-+ */
-+ usbe->next_rx_skb = usb_new_recv_skb(usbe);
-+ if (!usbe->next_rx_skb) {
-+ if (net_ratelimit())
-+ printk(KERN_ERR "%s: can't allocate new rx skb\n",
-+ usbe->dev.name);
-+ usbe->stats.rx_dropped++;
-+ goto recycle;
-+ }
-+
-+// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
-+
-+ usbe->stats.rx_packets++;
-+ usbe->stats.rx_bytes += skb->len;
-+ usbe->dev.last_rx = jiffies;
-+
-+ skb->dev = &usbe->dev;
-+ skb->protocol = eth_type_trans(skb, &usbe->dev);
-+ skb->ip_summed = CHECKSUM_NONE;
-+
-+ if (netif_rx(skb) == NET_RX_DROP)
-+ usbe->stats.rx_dropped++;
-+ return;
-+
-+ error:
-+ /*
-+ * Oops, IO error, or stalled.
-+ */
-+ switch (flag) {
-+ case -EIO: /* aborted transfer */
-+ usbe->stats.rx_errors++;
-+ break;
-+
-+ case -EPIPE: /* fifo screwed/no data */
-+ usbe->stats.rx_fifo_errors++;
-+ usbe->stats.rx_errors++;
-+ break;
-+
-+ case -EINTR: /* reset */
-+ break;
-+
-+ case -EAGAIN: /* initialisation */
-+ break;
-+ }
-+
-+ oversize:
-+ skb_trim(skb, 0);
-+
-+#ifndef RX_NO_COPY
-+ buf = usbe->dmabuf;
-+ size = usb_rsize;
-+#else
-+ buf = skb->tail;
-+ size = skb_tailroom(skb);
-+#endif
-+ usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size);
-+ return;
-+
-+ recycle:
-+ skb_trim(skb, 0);
-+ usbe->next_rx_skb = skb;
-+ return;
-+}
-+
-+/*
-+ * Send a skb.
-+ *
-+ * Note that the receiver expects the last packet to be a non-multiple
-+ * of its rsize. If the packet length is a muliple of wsize (and
-+ * therefore the remote rsize) tweak the length.
-+ */
-+static void usbeth_send(struct sk_buff *skb, struct usbe_info *usbe)
-+{
-+ unsigned int len = skb->len;
-+ int ret;
-+
-+ if ((len % usb_wsize) == 0)
-+ len++;
-+
-+ ret = usbctl_ep_queue_buffer(usbe->client.ctl, 2, skb->data, len);
-+ if (ret) {
-+ printk(KERN_ERR "%s: tx dropping packet: %d\n",
-+ usbe->dev.name, ret);
-+
-+ /*
-+ * If the USB core can't accept the packet, we drop it.
-+ */
-+ dev_kfree_skb_irq(skb);
-+
-+ usbe->cur_tx_skb = NULL;
-+ usbe->stats.tx_carrier_errors++;
-+ } else {
-+ usbe->dev.trans_start = jiffies;
-+ }
-+}
-+
-+static void usbeth_send_callback(void *data, int flag, int size)
-+{
-+ struct usbe_info *usbe = data;
-+ struct sk_buff *skb = usbe->cur_tx_skb;
-+
-+ switch (flag) {
-+ case 0:
-+ usbe->stats.tx_packets++;
-+ usbe->stats.tx_bytes += skb->len;
-+ break;
-+ case -EIO:
-+ usbe->stats.tx_errors++;
-+ break;
-+ default:
-+ usbe->stats.tx_dropped++;
-+ break;
-+ }
-+
-+ dev_kfree_skb_irq(skb);
-+
-+ skb = usbe->cur_tx_skb = usbe->next_tx_skb;
-+ usbe->next_tx_skb = NULL;
-+
-+ if (skb)
-+ usbeth_send(skb, usbe);
-+
-+ netif_wake_queue(&usbe->dev);
-+}
-+
-+static int usbeth_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct usbe_info *usbe = dev->priv;
-+ unsigned long flags;
-+
-+ if (usbe->next_tx_skb) {
-+ printk(KERN_ERR "%s: called with next_tx_skb != NULL\n",
-+ usbe->dev.name);
-+ return 1;
-+ }
-+
-+ local_irq_save(flags);
-+ if (usbe->cur_tx_skb) {
-+ usbe->next_tx_skb = skb;
-+ netif_stop_queue(dev);
-+ } else {
-+ usbe->cur_tx_skb = skb;
-+
-+ usbeth_send(skb, usbe);
-+ }
-+ local_irq_restore(flags);
-+ return 0;
-+}
-+
-+/*
-+ * Transmit timed out. Reset the endpoint, and re-queue the pending
-+ * packet. If we have a free transmit slot, wake the transmit queue.
-+ */
-+static void usbeth_xmit_timeout(struct net_device *dev)
-+{
-+ struct usbe_info *usbe = dev->priv;
-+ unsigned long flags;
-+
-+ usbctl_ep_reset(usbe->client.ctl, 2);
-+
-+ local_irq_save(flags);
-+ if (usbe->cur_tx_skb)
-+ usbeth_send(usbe->cur_tx_skb, usbe);
-+
-+ if (usbe->next_tx_skb == NULL)
-+ netif_wake_queue(dev);
-+
-+ usbe->stats.tx_errors++;
-+ local_irq_restore(flags);
-+}
-+
-+static int usbeth_open(struct net_device *dev)
-+{
-+ struct usbe_info *usbe = dev->priv;
-+ unsigned char *buf;
-+ unsigned int size;
-+
-+ usbctl_ep_set_callback(usbe->client.ctl, 2, usbeth_send_callback, usbe);
-+ usbctl_ep_set_callback(usbe->client.ctl, 1, usbeth_recv_callback, usbe);
-+
-+ usbe->cur_tx_skb = usbe->next_tx_skb = NULL;
-+ usbe->cur_rx_skb = usb_new_recv_skb(usbe);
-+ usbe->next_rx_skb = usb_new_recv_skb(usbe);
-+ if (!usbe->cur_rx_skb || !usbe->next_rx_skb) {
-+ printk(KERN_ERR "%s: can't allocate new skb\n",
-+ usbe->dev.name);
-+ if (usbe->cur_rx_skb)
-+ kfree_skb(usbe->cur_rx_skb);
-+ if (usbe->next_rx_skb)
-+ kfree_skb(usbe->next_rx_skb);
-+ return -ENOMEM;;
-+ }
-+#ifndef RX_NO_COPY
-+ buf = usbe->dmabuf;
-+ size = usb_rsize;
-+#else
-+ buf = usbe->cur_rx_skb->tail;
-+ size = skb_tailroom(usbe->cur_rx_skb);
-+#endif
-+ usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size);
-+
-+ if (netif_carrier_ok(dev))
-+ netif_start_queue(dev);
-+
-+ return 0;
-+}
-+
-+static int usbeth_close(struct net_device *dev)
-+{
-+ struct usbe_info *usbe = dev->priv;
-+
-+ netif_stop_queue(dev);
-+
-+ usbctl_ep_set_callback(usbe->client.ctl, 2, NULL, NULL);
-+ usbctl_ep_set_callback(usbe->client.ctl, 1, NULL, NULL);
-+ usbctl_ep_reset(usbe->client.ctl, 2);
-+ usbctl_ep_reset(usbe->client.ctl, 1);
-+
-+ if (usbe->cur_tx_skb)
-+ kfree_skb(usbe->cur_tx_skb);
-+ if (usbe->next_tx_skb)
-+ kfree_skb(usbe->next_tx_skb);
-+ if (usbe->cur_rx_skb)
-+ kfree_skb(usbe->cur_rx_skb);
-+ if (usbe->next_rx_skb)
-+ kfree_skb(usbe->next_rx_skb);
-+
-+ return 0;
-+}
-+
-+static struct net_device_stats *usbeth_stats(struct net_device *dev)
-+{
-+ struct usbe_info *usbe = dev->priv;
-+
-+ return &usbe->stats;
-+}
-+
-+static int __init usbeth_probe(struct net_device *dev)
-+{
-+ u8 node_id[ETH_ALEN];
-+
-+ SET_MODULE_OWNER(dev);
-+
-+ /*
-+ * Assign the hardware address of the board:
-+ * generate it randomly, as there can be many such
-+ * devices on the bus.
-+ */
-+ get_random_bytes(node_id, sizeof node_id);
-+ node_id[0] &= 0xfe; // clear multicast bit
-+ memcpy(dev->dev_addr, node_id, sizeof node_id);
-+
-+ ether_setup(dev);
-+ dev->flags &= ~IFF_MULTICAST;
-+ dev->flags &= ~IFF_BROADCAST;
-+ //dev->flags |= IFF_NOARP;
-+
-+ return 0;
-+}
-+
-+/*
-+ * This is called when something in the upper usb client layers
-+ * changes that affects the endpoint connectivity state (eg,
-+ * connection or disconnection from the host.) We probably want
-+ * to do some more handling here, like kicking off a pending
-+ * transmission if we're running?
-+ */
-+static void usbeth_state_change(void *data, int state, int oldstate)
-+{
-+ struct usbe_info *usbe = data;
-+
-+ if (state == USB_STATE_CONFIGURED) {
-+ netif_carrier_on(&usbe->dev);
-+ if (netif_running(&usbe->dev))
-+ netif_wake_queue(&usbe->dev);
-+ } else {
-+ if (netif_running(&usbe->dev))
-+ netif_stop_queue(&usbe->dev);
-+ netif_carrier_off(&usbe->dev);
-+ }
-+}
-+
-+static struct usbe_info usbe_info = {
-+ .dev = {
-+ .name = "usbf",
-+ .init = usbeth_probe,
-+ .get_stats = usbeth_stats,
-+ .watchdog_timeo = 1 * HZ,
-+ .open = usbeth_open,
-+ .stop = usbeth_close,
-+ .hard_start_xmit = usbeth_xmit,
-+ .change_mtu = usbeth_change_mtu,
-+ .tx_timeout = usbeth_xmit_timeout,
-+ .priv = &usbe_info,
-+ },
-+ .client = {
-+ .name = "usbeth",
-+ .priv = &usbe_info,
-+ .state_change = usbeth_state_change,
-+
-+ /*
-+ * USB client identification for host use in CPU endian.
-+ */
-+ .vendor = ETHERNET_VENDOR_ID,
-+ .product = ETHERNET_PRODUCT_ID,
-+ .version = 0,
-+ .class = 0xff, /* vendor specific */
-+ .subclass = 0,
-+ .protocol = 0,
-+
-+ .product_str = "SA1100 USB NIC",
-+ },
-+};
-+
-+static int __init usbeth_init(void)
-+{
-+ int rc;
-+
-+#ifndef RX_NO_COPY
-+ usbe_info.dmabuf = kmalloc(usb_rsize, GFP_KERNEL | GFP_DMA);
-+ if (!usbe_info.dmabuf)
-+ return -ENOMEM;
-+#endif
-+
-+ if (register_netdev(&usbe_info.dev) != 0) {
-+#ifndef RX_NO_COPY
-+ kfree(usbe_info.dmabuf);
-+#endif
-+ return -EIO;
-+ }
-+
-+ rc = usbctl_open(&usbe_info.client);
-+ if (rc == 0) {
-+ struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
-+
-+ cdb->ep1.wMaxPacketSize = cpu_to_le16(usb_rsize);
-+ cdb->ep2.wMaxPacketSize = cpu_to_le16(usb_wsize);
-+
-+ rc = usbctl_start(&usbe_info.client);
-+ if (rc)
-+ usbctl_close(&usbe_info.client);
-+ }
-+
-+ if (rc) {
-+ unregister_netdev(&usbe_info.dev);
-+#ifndef RX_NO_COPY
-+ kfree(usbe_info.dmabuf);
-+#endif
-+ }
-+
-+ return rc;
-+}
-+
-+static void __exit usbeth_cleanup(void)
-+{
-+ usbctl_stop(&usbe_info.client);
-+ usbctl_close(&usbe_info.client);
-+
-+ unregister_netdev(&usbe_info.dev);
-+#ifndef RX_NO_COPY
-+ kfree(usbe_info.dmabuf);
-+#endif
-+}
-+
-+module_init(usbeth_init);
-+module_exit(usbeth_cleanup);
-+
-+MODULE_DESCRIPTION("USB client ethernet driver");
-+MODULE_PARM(usb_rsize, "1i");
-+MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to sa11x0");
-+MODULE_PARM(usb_wsize, "1i");
-+MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from sa11x0 to host");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_recv.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,318 @@
-+/*
-+ * Generic receive layer for the SA1100 USB client function
-+ * Copyright (c) 2001 by Nicolas Pitre
-+ *
-+ * This code was loosely inspired by the original version which was
-+ * Copyright (c) Compaq Computer Corporation, 1998-1999
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This is still work in progress...
-+ *
-+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/errno.h>
-+#include <linux/usb_ch9.h>
-+
-+#include <asm/byteorder.h>
-+#include <asm/dma.h>
-+
-+#include "sa1100_usb.h"
-+#include "sa1100usb.h"
-+
-+static int naking;
-+
-+#if 1
-+static void dump_buf(struct sausb_dev *usb, const char *prefix)
-+{
-+ printk("%s: buf [dma=%08x len=%3d] pkt [cpu=%08x dma=%08x len=%3d rem=%3d]\n",
-+ prefix,
-+ usb->ep[0].bufdma,
-+ usb->ep[0].buflen,
-+ (unsigned int)usb->ep[0].pktcpu,
-+ usb->ep[0].pktdma,
-+ usb->ep[0].pktlen,
-+ usb->ep[0].pktrem);
-+}
-+#endif
-+
-+static void udc_ep1_done(struct sausb_dev *usb, int flag, int size)
-+{
-+// printk("UDC: rxd: %3d %3d\n", flag, size);
-+ dump_buf(usb, "UDC: rxd");
-+
-+ if (!usb->ep[0].buflen)
-+ return;
-+
-+ dma_unmap_single(usb->dev, usb->ep[0].bufdma, usb->ep[0].buflen,
-+ DMA_FROM_DEVICE);
-+
-+ usb->ep[0].bufdma = 0;
-+ usb->ep[0].buflen = 0;
-+ usb->ep[0].pktcpu = NULL;
-+ usb->ep[0].pktdma = 0;
-+ usb->ep[0].pktlen = 0;
-+ usb->ep[0].pktrem = 0;
-+
-+ if (usb->ep[0].cb_func)
-+ usb->ep[0].cb_func(usb->ep[0].cb_data, flag, size);
-+}
-+
-+/*
-+ * Initialisation. Clear out the status, and set FST.
-+ */
-+void udc_ep1_init(struct sausb_dev *usb)
-+{
-+ sa1100_reset_dma(usb->ep[0].dmach);
-+
-+ UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC);
-+
-+ BUG_ON(usb->ep[0].buflen);
-+ BUG_ON(usb->ep[0].pktlen);
-+}
-+
-+void udc_ep1_halt(struct sausb_dev *usb, int halt)
-+{
-+ if (halt) {
-+ /* force stall at UDC */
-+ UDC_set(Ser0UDCCS1, UDCCS1_FST);
-+ } else {
-+ sa1100_reset_dma(usb->ep[0].dmach);
-+
-+ UDC_clear(Ser0UDCCS1, UDCCS1_FST);
-+
-+ udc_ep1_done(usb, -EINTR, 0);
-+ }
-+}
-+
-+/*
-+ * This gets called when we receive a SET_CONFIGURATION packet to EP0.
-+ * We were configured. We can now accept packets from the host.
-+ */
-+void udc_ep1_config(struct sausb_dev *usb, unsigned int maxpktsize)
-+{
-+ usb->ep[0].maxpktsize = maxpktsize;
-+ usb->ep[0].configured = 1;
-+
-+ Ser0UDCOMP = maxpktsize - 1;
-+
-+ sa1100_reset_dma(usb->ep[0].dmach);
-+ udc_ep1_done(usb, -EINTR, 0);
-+
-+ /*
-+ * Enable EP1 interrupts.
-+ */
-+ usb->udccr &= ~UDCCR_RIM;
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+}
-+
-+/*
-+ * We saw a reset from the attached hub. This means we are no
-+ * longer configured, and as far as the rest of the world is
-+ * concerned, we don't exist.
-+ */
-+void udc_ep1_reset(struct sausb_dev *usb)
-+{
-+ /*
-+ * Disable EP1 interrupts.
-+ */
-+ usb->udccr |= UDCCR_RIM;
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+
-+ usb->ep[0].configured = 0;
-+ usb->ep[0].maxpktsize = 0;
-+
-+ sa1100_reset_dma(usb->ep[0].dmach);
-+ udc_ep1_done(usb, -EINTR, 0);
-+}
-+
-+void udc_ep1_int_hndlr(struct sausb_dev *usb)
-+{
-+ dma_addr_t dma_addr;
-+ unsigned int len;
-+ u32 status = Ser0UDCCS1;
-+
-+ dump_buf(usb, "UDC: int");
-+
-+ if (naking) {
-+ printk("UDC: usbrx: in ISR but naking [0x%02x]\n", status);
-+ return;
-+ }
-+
-+ if (!(status & UDCCS1_RPC))
-+ /* you can get here if we are holding NAK */
-+ return;
-+
-+ if (!usb->ep[0].buflen) {
-+ printk("UDC: usb_recv: RPC for non-existent buffer [0x%02x]\n", status);
-+ naking = 1;
-+ return;
-+ }
-+
-+ sa1100_stop_dma(usb->ep[0].dmach);
-+
-+ dma_addr = sa1100_get_dma_pos(usb->ep[0].dmach);
-+
-+ /*
-+ * We've finished with the DMA for this packet.
-+ */
-+ sa1100_clear_dma(usb->ep[0].dmach);
-+
-+ if (status & UDCCS1_SST) {
-+ printk("UDC: usb_recv: stall sent\n");
-+ UDC_flip(Ser0UDCCS1, UDCCS1_SST);
-+
-+ /*
-+ * UDC aborted current transfer, so we do.
-+ *
-+ * It would be better to re-queue this buffer IMHO. It
-+ * hasn't gone anywhere yet. --rmk
-+ */
-+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
-+ udc_ep1_done(usb, -EIO, 0);
-+ return;
-+ }
-+
-+ if (status & UDCCS1_RPE) {
-+ printk("UDC: usb_recv: RPError %x\n", status);
-+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
-+ udc_ep1_done(usb, -EIO, 0);
-+ return;
-+ }
-+
-+ len = dma_addr - usb->ep[0].pktdma;
-+ if (len < 0) {
-+ printk("UDC: usb_recv: dma_addr (%x) < pktdma (%x)\n",
-+ dma_addr, usb->ep[0].pktdma);
-+ len = 0;
-+ }
-+
-+ if (len > usb->ep[0].pktlen)
-+ len = usb->ep[0].pktlen;
-+
-+ /*
-+ * If our transfer was smaller, and we have bytes left in
-+ * the FIFO, we need to read them out manually.
-+ */
-+ if (len < usb->ep[0].pktlen && (Ser0UDCCS1 & UDCCS1_RNE)) {
-+ char *buf;
-+
-+ dma_sync_single(usb->dev, usb->ep[0].pktdma + len,
-+ usb->ep[0].pktlen - len, DMA_FROM_DEVICE);
-+
-+ buf = (char *)usb->ep[0].pktcpu + len;
-+
-+ do {
-+ *buf++ = Ser0UDCDR;
-+ len++;
-+ } while (len < usb->ep[0].pktlen && (Ser0UDCCS1 & UDCCS1_RNE));
-+
-+ /*
-+ * Note: knowing the internals of this macro is BAD, but we
-+ * need this to cause the data to be written back to memory.
-+ */
-+ dma_sync_single(usb->dev, usb->ep[0].pktdma + len,
-+ usb->ep[0].pktlen - len, DMA_TO_DEVICE);
-+ }
-+
-+ /*
-+ * If the FIFO still contains data, something's definitely wrong.
-+ */
-+ if (Ser0UDCCS1 & UDCCS1_RNE) {
-+ printk("UDC: usb_recv: fifo screwed, shouldn't contain data\n");
-+ usb->ep[0].fifo_errs++;
-+ naking = 1;
-+ udc_ep1_done(usb, -EPIPE, 0);
-+ return;
-+ }
-+
-+ /*
-+ * Do statistics.
-+ */
-+ if (len) {
-+ usb->ep[0].bytes += len;
-+ usb->ep[0].packets ++;
-+ }
-+
-+ /*
-+ * Update remaining byte count for this buffer.
-+ */
-+ usb->ep[0].pktrem -= len;
-+
-+ /*
-+ * If we received a full-sized packet, and there's more
-+ * data remaining, th, queue up another receive.
-+ */
-+ if (len == usb->ep[0].pktlen && usb->ep[0].pktrem != 0) {
-+ usb->ep[0].pktcpu += len;
-+ usb->ep[0].pktdma += len;
-+ usb->ep[0].pktlen = min(usb->ep[0].pktrem, usb->ep[0].maxpktsize);
-+ sa1100_start_dma(usb->ep[0].dmach, usb->ep[0].pktdma, usb->ep[0].pktlen);
-+ /*
-+ * Clear RPC to receive next packet.
-+ */
-+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
-+ dump_buf(usb, "UDC: req");
-+ return;
-+ }
-+
-+ naking = 1;
-+ udc_ep1_done(usb, 0, usb->ep[0].buflen - usb->ep[0].pktrem);
-+}
-+
-+int udc_ep1_queue_buffer(struct sausb_dev *usb, char *buf, unsigned int len)
-+{
-+ unsigned long flags;
-+ dma_addr_t dma;
-+ int ret;
-+
-+ if (!buf || len == 0)
-+ return -EINVAL;
-+
-+ dma = dma_map_single(usb->dev, buf, len, DMA_FROM_DEVICE);
-+
-+ spin_lock_irqsave(&usb->lock, flags);
-+ do {
-+ if (usb->ep[0].buflen) {
-+ ret = -EBUSY;
-+ break;
-+ }
-+
-+ sa1100_clear_dma(usb->ep[0].dmach);
-+
-+ usb->ep[0].bufdma = dma;
-+ usb->ep[0].buflen = len;
-+ usb->ep[0].pktcpu = buf;
-+ usb->ep[0].pktdma = dma;
-+ usb->ep[0].pktlen = min(len, usb->ep[0].maxpktsize);
-+ usb->ep[0].pktrem = len;
-+
-+ sa1100_start_dma(usb->ep[0].dmach, usb->ep[0].bufdma, usb->ep[0].buflen);
-+ dump_buf(usb, "UDC: que");
-+
-+ if (naking) {
-+ /* turn off NAK of OUT packets, if set */
-+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
-+ naking = 0;
-+ }
-+
-+ ret = 0;
-+ } while (0);
-+ spin_unlock_irqrestore(&usb->lock, flags);
-+
-+ if (ret)
-+ dma_unmap_single(usb->dev, dma, len, DMA_FROM_DEVICE);
-+
-+ return 0;
-+}
-+
-+void udc_ep1_recv_reset(struct sausb_dev *usb)
-+{
-+ sa1100_reset_dma(usb->ep[0].dmach);
-+ udc_ep1_done(usb, -EINTR, 0);
-+}
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/buffer.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,63 @@
-+/*
-+ * usb/buffer.c
-+ *
-+ * Copyright (C) 2002 Russell King.
-+ */
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+
-+#include "buffer.h"
-+
-+static LIST_HEAD(buffers);
-+
-+struct usb_buf *usbb_alloc(int size, int gfp)
-+{
-+ unsigned long flags;
-+ struct usb_buf *buf;
-+
-+ buf = kmalloc(sizeof(struct usb_buf) + size, gfp);
-+ if (buf) {
-+ atomic_set(&buf->users, 1);
-+ local_irq_save(flags);
-+ list_add(&buf->list, &buffers);
-+ local_irq_restore(flags);
-+ buf->len = 0;
-+ buf->data = (unsigned char *) (buf + 1);
-+ buf->head = (unsigned char *) (buf + 1);
-+ }
-+
-+ return buf;
-+}
-+
-+void __usbb_free(struct usb_buf *buf)
-+{
-+ unsigned long flags;
-+ local_irq_save(flags);
-+ list_del(&buf->list);
-+ local_irq_restore(flags);
-+ kfree(buf);
-+}
-+
-+EXPORT_SYMBOL(usbb_alloc);
-+EXPORT_SYMBOL(__usbb_free);
-+
-+static void __exit usbb_exit(void)
-+{
-+ if (!list_empty(&buffers)) {
-+ struct list_head *l, *n;
-+ printk("usbb: buffers not freed:\n");
-+
-+ list_for_each_safe(l, n, &buffers) {
-+ struct usb_buf *b = list_entry(l, struct usb_buf, list);
-+
-+ printk(" %p: alloced from %p count %d\n",
-+ b, b->alloced_by, atomic_read(&b->users));
-+
-+ __usbb_free(b);
-+ }
-+ }
-+}
-+
-+module_exit(usbb_exit);
-+
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-char.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,34 @@
-+/*
-+ * Copyright (C) 2001 Extenex Corporation
-+ *
-+ * usb-char.h
-+ *
-+ * Character device emulation client for SA-1100 client usb core.
-+ *
-+ *
-+ *
-+ */
-+#ifndef _USB_CHAR_H
-+#define _USB_CHAR_H
-+
-+#define USBC_MAJOR 10 /* miscellaneous character device */
-+#define USBC_MINOR 240 /* in the "reserved for local use" range */
-+
-+#define USBC_MAGIC 0x8E
-+
-+/* zap everything in receive ring buffer */
-+#define USBC_IOC_FLUSH_RECEIVER _IO( USBC_MAGIC, 0x01 )
-+
-+/* reset transmitter */
-+#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 )
-+
-+/* do both of above */
-+#define USBC_IOC_FLUSH_ALL _IO( USBC_MAGIC, 0x03 )
-+
-+
-+
-+
-+
-+
-+#endif /* _USB_CHAR_H */
-+
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/buffer.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,45 @@
-+/*
-+ * usb/buffer.h: USB client buffers
-+ *
-+ * Copyright (C) 2002 Russell King.
-+ *
-+ * Loosely based on linux/skbuff.h
-+ */
-+#ifndef USBDEV_BUFFER_H
-+#define USBDEV_BUFFER_H
-+
-+#include <linux/list.h>
-+
-+struct usb_buf {
-+ atomic_t users;
-+ struct list_head list;
-+ void *alloced_by;
-+ unsigned char *data;
-+ unsigned char *head;
-+ unsigned int len;
-+};
-+
-+extern struct usb_buf *usbb_alloc(int size, int gfp);
-+extern void __usbb_free(struct usb_buf *);
-+
-+static inline struct usb_buf *usbb_get(struct usb_buf *buf)
-+{
-+ atomic_inc(&buf->users);
-+ return buf;
-+}
-+
-+static inline void usbb_put(struct usb_buf *buf)
-+{
-+ if (atomic_dec_and_test(&buf->users))
-+ __usbb_free(buf);
-+}
-+
-+static inline void *usbb_push(struct usb_buf *buf, int len)
-+{
-+ unsigned char *b = buf->head;
-+ buf->head += len;
-+ buf->len += len;
-+ return b;
-+}
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100usb.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,1160 @@
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/usb_ch9.h>
-+#include <linux/init.h>
-+#include <linux/proc_fs.h>
-+#include <linux/spinlock.h>
-+#include <linux/device.h>
-+
-+#include <asm/mach-types.h>
-+#include <asm/io.h>
-+#include <asm/dma.h>
-+#include <asm/irq.h>
-+
-+#include "buffer.h"
-+#include "usbdev.h"
-+#include "sa1100_usb.h"
-+#include "sa1100usb.h"
-+
-+#ifdef DEBUG
-+#define DPRINTK(fmt, args...) printk( fmt , ## args)
-+#else
-+#define DPRINTK(fmt, args...)
-+#endif
-+
-+static inline void pcs(const char *prefix)
-+{
-+#ifdef DEBUG
-+ __u32 foo = Ser0UDCCS0;
-+
-+ DPRINTK("%s UDCAR: %d\n", prefix, Ser0UDCAR);
-+
-+ printk("UDC: %s: %08x [ %s%s%s%s%s%s]\n", prefix,
-+ foo,
-+ foo & UDCCS0_SE ? "SE " : "",
-+ foo & UDCCS0_DE ? "DE " : "",
-+ foo & UDCCS0_FST ? "FST " : "",
-+ foo & UDCCS0_SST ? "SST " : "",
-+ foo & UDCCS0_IPR ? "IPR " : "",
-+ foo & UDCCS0_OPR ? "OPR " : "");
-+#endif
-+}
-+
-+/*
-+ * soft_connect_hook()
-+ *
-+ * Some devices have platform-specific circuitry to make USB
-+ * not seem to be plugged in, even when it is. This allows
-+ * software to control when a device 'appears' on the USB bus
-+ * (after Linux has booted and this driver has loaded, for
-+ * example). If you have such a circuit, control it here.
-+ */
-+static inline void soft_connect_hook(int enable)
-+{
-+#ifdef CONFIG_SA1100_EXTENEX1
-+ if (machine_is_extenex1()) {
-+ if (enable) {
-+ PPDR |= PPC_USB_SOFT_CON;
-+ PPSR |= PPC_USB_SOFT_CON;
-+ } else {
-+ PPSR &= ~PPC_USB_SOFT_CON;
-+ PPDR &= ~PPC_USB_SOFT_CON;
-+ }
-+ }
-+#endif
-+}
-+
-+/*
-+ * disable the UDC at the source
-+ */
-+static inline void udc_disable(struct sausb_dev *usb)
-+{
-+ soft_connect_hook(0);
-+
-+ usb->udccr = UDCCR_UDD | UDCCR_SUSIM;
-+
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+}
-+
-+/*
-+ * Clear any pending write from the EP0 write buffer.
-+ */
-+static void ep0_clear_write(struct sausb_dev *usb)
-+{
-+ struct usb_buf *buf;
-+
-+ buf = usb->wrbuf;
-+ usb->wrint = NULL;
-+ usb->wrbuf = NULL;
-+ usb->wrptr = NULL;
-+ usb->wrlen = 0;
-+
-+ if (buf)
-+ usbb_put(buf);
-+}
-+
-+static int udc_start(void *priv)
-+{
-+ struct sausb_dev *usb = priv;
-+
-+ usb->ep[0].maxpktsize = 0;
-+ usb->ep[1].maxpktsize = 0;
-+
-+ /*
-+ * start UDC internal machinery running, but mask interrupts.
-+ */
-+ usb->udccr = UDCCR_SUSIM | UDCCR_TIM | UDCCR_RIM | UDCCR_EIM |
-+ UDCCR_RESIM;
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+
-+ udelay(100);
-+
-+ /*
-+ * clear all interrupt sources
-+ */
-+ Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR |
-+ UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR;
-+
-+ /*
-+ * flush DMA and fire through some -EAGAINs
-+ */
-+ udc_ep1_init(usb);
-+ udc_ep2_init(usb);
-+
-+ /*
-+ * enable any platform specific hardware
-+ */
-+ soft_connect_hook(1);
-+
-+ /*
-+ * Enable resume, suspend and endpoint 0 interrupts. Leave
-+ * endpoint 1 and 2 interrupts masked.
-+ *
-+ * If you are unplugged you will immediately get a suspend
-+ * interrupt. If you are plugged and have a soft connect-circuit,
-+ * you will get a reset. If you are plugged without a soft-connect,
-+ * I think you also get suspend.
-+ */
-+ usb->udccr &= ~(UDCCR_SUSIM | UDCCR_EIM | UDCCR_RESIM);
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+
-+ return 0;
-+}
-+
-+static int udc_stop(void *priv)
-+{
-+ struct sausb_dev *usb = priv;
-+
-+ ep0_clear_write(usb);
-+
-+ /* mask everything */
-+ Ser0UDCCR = 0xFC;
-+
-+ udc_ep1_reset(usb);
-+ udc_ep2_reset(usb);
-+
-+ udc_disable(usb);
-+
-+ return 0;
-+}
-+
-+
-+
-+
-+
-+/*
-+ * some voodo I am adding, since the vanilla macros just aren't doing it
-+ * 1Mar01ww
-+ */
-+
-+#define ABORT_BITS (UDCCS0_SST | UDCCS0_SE)
-+#define OK_TO_WRITE (!(Ser0UDCCS0 & ABORT_BITS))
-+#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE)
-+
-+static void set_de(void)
-+{
-+ int i = 1;
-+
-+ while (1) {
-+ if (OK_TO_WRITE) {
-+ Ser0UDCCS0 |= UDCCS0_DE;
-+ } else {
-+ DPRINTK("UDC: quitting set DE because SST or SE set\n");
-+ break;
-+ }
-+ if (Ser0UDCCS0 & UDCCS0_DE)
-+ break;
-+ udelay(i);
-+ if (++i == 50) {
-+ printk("UDC: Dangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8X)\n",
-+ UDCCS0_DE, Ser0UDCCS0);
-+ break;
-+ }
-+ }
-+}
-+
-+static void set_ipr(void)
-+{
-+ int i = 1;
-+
-+ while (1) {
-+ if (OK_TO_WRITE) {
-+ Ser0UDCCS0 |= UDCCS0_IPR;
-+ } else {
-+ DPRINTK("UDC: Quitting set IPR because SST or SE set\n");
-+ break;
-+ }
-+ if (Ser0UDCCS0 & UDCCS0_IPR)
-+ break;
-+ udelay(i);
-+ if (++i == 50) {
-+ printk("UDC: Dangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8X)\n",
-+ UDCCS0_IPR, Ser0UDCCS0);
-+ break;
-+ }
-+ }
-+}
-+
-+static void set_ipr_and_de(void)
-+{
-+ int i = 1;
-+
-+ while (1) {
-+ if (OK_TO_WRITE) {
-+ Ser0UDCCS0 |= BOTH_BITS;
-+ } else {
-+ DPRINTK("UDC: Quitting set IPR/DE because SST or SE set\n");
-+ break;
-+ }
-+ if ((Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS)
-+ break;
-+ udelay(i);
-+ if (++i == 50) {
-+ printk("UDC: Dangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8X)\n",
-+ UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0);
-+ break;
-+ }
-+ }
-+}
-+
-+static inline void set_cs_bits(__u32 bits)
-+{
-+ if (bits & (UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST))
-+ Ser0UDCCS0 = bits;
-+ else if ((bits & BOTH_BITS) == BOTH_BITS)
-+ set_ipr_and_de();
-+ else if (bits & UDCCS0_IPR)
-+ set_ipr();
-+ else if (bits & UDCCS0_DE)
-+ set_de();
-+}
-+
-+/*
-+ * udc_ep0_write_fifo()
-+ *
-+ * Stick bytes in the 8 bytes endpoint zero FIFO. This version uses a
-+ * variety of tricks to make sure the bytes are written correctly:
-+ * 1. The count register is checked to see if the byte went in,
-+ * and the write is attempted again if not.
-+ * 2. An overall counter is used to break out so we don't hang in
-+ * those (rare) cases where the UDC reverses direction of the
-+ * FIFO underneath us without notification (in response to host
-+ * aborting a setup transaction early).
-+ */
-+static void udc_ep0_write_fifo(struct sausb_dev *usb)
-+{
-+ unsigned int bytes_this_time = min(usb->wrlen, 8U);
-+ int bytes_written = 0;
-+
-+ DPRINTK("WF=%d: ", bytes_this_time);
-+
-+ while (bytes_this_time--) {
-+ unsigned int cwc;
-+ int i;
-+
-+ DPRINTK("%2.2X ", *usb->wrptr);
-+
-+ cwc = Ser0UDCWC & 15;
-+
-+ i = 10;
-+ do {
-+ Ser0UDCD0 = *usb->wrptr;
-+ udelay(20); /* voodo 28Feb01ww */
-+ } while ((Ser0UDCWC & 15) == cwc && --i);
-+
-+ if (i == 0) {
-+ printk("UDC: udc_ep0_write_fifo: write failure\n");
-+ usb->ep0_wr_fifo_errs++;
-+ }
-+
-+ usb->wrptr++;
-+ bytes_written++;
-+ }
-+ usb->wrlen -= bytes_written;
-+
-+ /* following propagation voodo so maybe caller writing IPR in
-+ ..a moment might actually get it to stick 28Feb01ww */
-+ udelay(300);
-+
-+ usb->ep0_wr_bytes += bytes_written;
-+ DPRINTK("L=%d WCR=%8.8X\n", usb->wrlen, Ser0UDCWC);
-+}
-+
-+/*
-+ * read_fifo()
-+ *
-+ * Read 1-8 bytes out of FIFO and put in request. Called to do the
-+ * initial read of setup requests from the host. Return number of
-+ * bytes read.
-+ *
-+ * Like write fifo above, this driver uses multiple reads checked
-+ * against the count register with an overall timeout.
-+ */
-+static int
-+udc_ep0_read_fifo(struct sausb_dev *usb, struct usb_ctrlrequest *request, int sz)
-+{
-+ unsigned char *pOut = (unsigned char *) request;
-+ unsigned int fifo_count, bytes_read = 0;
-+
-+ fifo_count = Ser0UDCWC & 15;
-+
-+ DPRINTK("RF=%d ", fifo_count);
-+ BUG_ON(fifo_count > sz);
-+
-+ while (fifo_count--) {
-+ unsigned int cwc;
-+ int i;
-+
-+ cwc = Ser0UDCWC & 15;
-+
-+ i = 10;
-+ do {
-+ *pOut = (unsigned char) Ser0UDCD0;
-+ udelay(20);
-+ } while ((Ser0UDCWC & 15) == cwc && --i);
-+
-+ if (i == 0) {
-+ printk(KERN_ERR "UDC: udc_ep0_read_fifo: read failure\n");
-+ usb->ep0_rd_fifo_errs++;
-+ break;
-+ }
-+ pOut++;
-+ bytes_read++;
-+ }
-+
-+ DPRINTK("fc=%d\n", bytes_read);
-+ usb->ep0_rd_bytes += bytes_read;
-+ usb->ep0_rd_packets ++;
-+ return bytes_read;
-+}
-+
-+static void ep0_sh_write_data(struct sausb_dev *usb)
-+{
-+ /*
-+ * If bytes left is zero, we are coming in on the
-+ * interrupt after the last packet went out. And
-+ * we know we don't have to empty packet this
-+ * transfer so just set DE and we are done
-+ */
-+ set_cs_bits(UDCCS0_DE);
-+}
-+
-+static void ep0_sh_write_with_empty_packet(struct sausb_dev *usb)
-+{
-+ /*
-+ * If bytes left is zero, we are coming in on the
-+ * interrupt after the last packet went out.
-+ * We must do short packet suff, so set DE and IPR
-+ */
-+ set_cs_bits(UDCCS0_IPR | UDCCS0_DE);
-+ DPRINTK("UDC: sh_write_empty: Sent empty packet\n");
-+}
-+
-+static int udc_clear_opr(void)
-+{
-+ int i = 10000;
-+ int is_clear;
-+
-+ /*FIXME*/
-+ do {
-+ Ser0UDCCS0 = UDCCS0_SO;
-+ is_clear = !(Ser0UDCCS0 & UDCCS0_OPR);
-+ if (i-- <= 0)
-+ break;
-+ } while (!is_clear);
-+
-+ return is_clear;
-+}
-+
-+static int udc_ep0_queue(void *priv, struct usb_buf *buf,
-+ unsigned int req_len)
-+{
-+ struct sausb_dev *usb = priv;
-+ __u32 cs_reg_bits = UDCCS0_IPR;
-+
-+ DPRINTK("a=%d r=%d\n", buf->len, req_len);
-+
-+ /*
-+ * thou shalt not enter data phase until
-+ * Out Packet Ready is clear
-+ */
-+ if (!udc_clear_opr()) {
-+ printk("UDC: SO did not clear OPR\n");
-+ set_cs_bits(UDCCS0_DE | UDCCS0_SO);
-+ usbb_put(buf);
-+ return 1;
-+ }
-+
-+ usb->ep0_wr_packets++;
-+
-+ usb->wrbuf = buf;
-+ usb->wrptr = buf->data;
-+ usb->wrlen = min(buf->len, req_len);
-+
-+ udc_ep0_write_fifo(usb);
-+
-+ if (usb->wrlen == 0) {
-+ /*
-+ * out in one, so data end
-+ */
-+ cs_reg_bits |= UDCCS0_DE;
-+ ep0_clear_write(usb);
-+ } else if (buf->len < req_len) {
-+ /*
-+ * we are going to short-change host
-+ * so need nul to not stall
-+ */
-+ usb->wrint = ep0_sh_write_with_empty_packet;
-+ } else {
-+ /*
-+ * we have as much or more than requested
-+ */
-+ usb->wrint = ep0_sh_write_data;
-+ }
-+
-+ /*
-+ * note: IPR was set uncondtionally at start of routine
-+ */
-+ set_cs_bits(cs_reg_bits);
-+ return 0;
-+}
-+
-+/*
-+ * When SO and DE sent, UDC will enter status phase and ack, propagating
-+ * new address to udc core. Next control transfer will be on the new
-+ * address.
-+ *
-+ * You can't see the change in a read back of CAR until then (about 250us
-+ * later, on my box). The original Intel driver sets S0 and DE and code
-+ * to check that address has propagated here. I tried this, but it would
-+ * only sometimes work! The rest of the time it would never propagate and
-+ * we'd spin forever. So now I just set it and pray...
-+ */
-+static void udc_set_address(void *priv, unsigned int addr)
-+{
-+ Ser0UDCAR = addr;
-+}
-+
-+static void udc_set_config(void *priv, struct cdb *cdb)
-+{
-+ struct sausb_dev *usb = priv;
-+
-+ if (cdb) {
-+ udc_ep1_config(usb, le16_to_cpu(cdb->ep1.wMaxPacketSize));
-+ udc_ep2_config(usb, le16_to_cpu(cdb->ep2.wMaxPacketSize));
-+ } else {
-+ udc_ep1_reset(usb);
-+ udc_ep2_reset(usb);
-+ }
-+}
-+
-+static unsigned int udc_ep_get_status(void *priv, unsigned int ep)
-+{
-+ unsigned int status;
-+
-+ switch (ep) {
-+ case 0:
-+ status = (Ser0UDCCS0 & UDCCS0_FST) ? 1 : 0;
-+ break;
-+
-+ case 1:
-+ status = (Ser0UDCCS1 & UDCCS1_FST) ? 1 : 0;
-+ break;
-+
-+ case 2:
-+ status = (Ser0UDCCS2 & UDCCS2_FST) ? 1 : 0;
-+ break;
-+
-+ default:
-+ printk(KERN_ERR "UDC: get_status: bad end point %d\n", ep);
-+ status = 0;
-+ break;
-+ }
-+
-+ return status;
-+}
-+
-+static void udc_ep_halt(void *priv, unsigned int ep, int halt)
-+{
-+ struct sausb_dev *usb = priv;
-+
-+ printk("UDC: ep%d %s halt\n", ep, halt ? "set" : "clear");
-+
-+ switch (ep) {
-+ case 1:
-+ udc_ep1_halt(usb, halt);
-+ break;
-+
-+ case 2:
-+ udc_ep2_halt(usb, halt);
-+ break;
-+ }
-+}
-+
-+static int udc_ep_queue(void *priv, unsigned int ep, char *buf, unsigned int len)
-+{
-+ struct sausb_dev *usb = priv;
-+ int ret = -EINVAL;
-+
-+ switch (ep) {
-+ case 1:
-+ ret = udc_ep1_queue_buffer(usb, buf, len);
-+ break;
-+ case 2:
-+ ret = udc_ep2_send(usb, buf, len);
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static void udc_ep_reset(void *priv, unsigned int ep)
-+{
-+ struct sausb_dev *usb = priv;
-+
-+ switch (ep) {
-+ case 1:
-+ udc_ep1_recv_reset(usb);
-+ break;
-+ case 2:
-+ udc_ep2_send_reset(usb);
-+ break;
-+ }
-+}
-+
-+static void udc_ep_callback(void *priv, unsigned int ep, usb_callback_t cb, void *data)
-+{
-+ struct sausb_dev *usb = priv;
-+ unsigned long flags;
-+
-+ if (ep == 1 || ep == 2) {
-+ ep -= 1;
-+
-+ spin_lock_irqsave(&usb->lock, flags);
-+ usb->ep[ep].cb_func = cb;
-+ usb->ep[ep].cb_data = data;
-+ spin_unlock_irqrestore(&usb->lock, flags);
-+ }
-+}
-+
-+static int udc_ep_idle(void *priv, unsigned int ep)
-+{
-+ struct sausb_dev *usb = priv;
-+ int ret = -EINVAL;
-+
-+ switch (ep) {
-+ case 1:
-+ break;
-+ case 2:
-+ ret = udc_ep2_idle(usb);
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static struct usbc_driver usb_sa1100_drv = {
-+ .owner = THIS_MODULE,
-+ .name = "SA1100",
-+ .start = udc_start,
-+ .stop = udc_stop,
-+ .ep0_queue = udc_ep0_queue,
-+ .set_address = udc_set_address,
-+ .set_config = udc_set_config,
-+ .ep_get_status = udc_ep_get_status,
-+ .ep_halt = udc_ep_halt,
-+ .ep_queue = udc_ep_queue,
-+ .ep_reset = udc_ep_reset,
-+ .ep_callback = udc_ep_callback,
-+ .ep_idle = udc_ep_idle,
-+};
-+
-+
-+/*
-+ * udc_ep0_read_packet()
-+ *
-+ * This setup handler is the "idle" state of endpoint zero. It looks for
-+ * OPR (OUT packet ready) to see if a setup request has been been received
-+ * from the host. Requests without a return data phase are immediately
-+ * handled. Otherwise, the handler may be set to one of the sh_write_xxxx
-+ * data pumpers if more than 8 bytes need to get back to the host.
-+ */
-+static void udc_ep0_read_packet(struct sausb_dev *usb, u32 cs_reg_in)
-+{
-+ struct usb_ctrlrequest req;
-+ int n, ret = RET_NOACTION;
-+
-+ /*
-+ * A control request has been received by EP0.
-+ * Read the request.
-+ */
-+ n = udc_ep0_read_fifo(usb, &req, sizeof(req));
-+
-+ if (n == sizeof(req)) {
-+ ret = usbctl_parse_request(usb->ctl, &req);
-+ } else {
-+ /*
-+ * The request wasn't fully received. Force a
-+ * stall.
-+ */
-+ set_cs_bits(UDCCS0_FST | UDCCS0_SO);
-+ printk("UDC: fifo read error: wanted %d bytes got %d\n",
-+ sizeof(req), n);
-+ }
-+
-+ switch (ret) {
-+ case RET_ERROR:
-+ case RET_NOACTION:
-+ break;
-+
-+ case RET_ACK:
-+ set_cs_bits(UDCCS0_DE | UDCCS0_SO);
-+ break;
-+
-+ case RET_REQERROR:
-+ /*
-+ * Send stall PID to host.
-+ */
-+ set_cs_bits(UDCCS0_DE | UDCCS0_SO | UDCCS0_FST);
-+ break;
-+ }
-+}
-+
-+/*
-+ * HACK DEBUG 3Mar01ww
-+ * Well, maybe not, it really seems to help! 08Mar01ww
-+ */
-+static void core_kicker(struct sausb_dev *usb)
-+{
-+ __u32 car = Ser0UDCAR;
-+ __u32 imp = Ser0UDCIMP;
-+ __u32 omp = Ser0UDCOMP;
-+
-+ UDC_set(Ser0UDCCR, UDCCR_UDD);
-+ udelay(300);
-+ UDC_clear(Ser0UDCCR, UDCCR_UDD);
-+
-+ Ser0UDCAR = car;
-+ Ser0UDCIMP = imp;
-+ Ser0UDCOMP = omp;
-+}
-+
-+static void enable_resume_mask_suspend(struct sausb_dev *usb)
-+{
-+ int i;
-+
-+ usb->udccr |= UDCCR_SUSIM;
-+
-+ i = 1;
-+ do {
-+ Ser0UDCCR = usb->udccr;
-+ udelay(i);
-+ if (Ser0UDCCR == usb->udccr)
-+ break;
-+ if (Ser0UDCSR & UDCSR_RSTIR)
-+ break;
-+ } while (i++ < 50);
-+
-+ if (i == 50)
-+ printk("UDC: enable_resume: could not set SUSIM 0x%08x\n",
-+ Ser0UDCCR);
-+
-+ usb->udccr &= ~UDCCR_RESIM;
-+
-+ i = 1;
-+ do {
-+ Ser0UDCCR = usb->udccr;
-+ udelay(i);
-+ if (Ser0UDCCR == usb->udccr)
-+ break;
-+ if (Ser0UDCSR & UDCSR_RSTIR)
-+ break;
-+ } while (i++ < 50);
-+
-+ if (i == 50)
-+ printk("UDC: enable_resume: could not clear RESIM 0x%08x\n",
-+ Ser0UDCCR);
-+}
-+
-+static void enable_suspend_mask_resume(struct sausb_dev *usb)
-+{
-+ int i;
-+
-+ usb->udccr |= UDCCR_RESIM;
-+
-+ i = 1;
-+ do {
-+ Ser0UDCCR = usb->udccr;
-+ udelay(i);
-+ if (Ser0UDCCR == usb->udccr)
-+ break;
-+ if (Ser0UDCSR & UDCSR_RSTIR)
-+ break;
-+ } while (i++ < 50);
-+
-+ if (i == 50)
-+ printk("UDC: enable_resume: could not set RESIM 0x%08x\n",
-+ Ser0UDCCR);
-+
-+ usb->udccr &= ~UDCCR_SUSIM;
-+
-+ i = 1;
-+ do {
-+ Ser0UDCCR = usb->udccr;
-+ udelay(i);
-+ if (Ser0UDCCR == usb->udccr)
-+ break;
-+ if (Ser0UDCSR & UDCSR_RSTIR)
-+ break;
-+ } while (i++ < 50);
-+
-+ if (i == 50)
-+ printk("UDC: enable_resume: could not clear SUSIM 0x%08x\n",
-+ Ser0UDCCR);
-+}
-+
-+/*
-+ * Reset received from HUB (or controller just went nuts and reset by
-+ * itself!) so UDC core has been reset, track this state here
-+ */
-+static void udc_reset(struct sausb_dev *usb)
-+{
-+ if (usbctl_reset(usb->ctl)) {
-+ ep0_clear_write(usb);
-+
-+ /*
-+ * Clean up endpoints.
-+ */
-+ udc_ep1_reset(usb);
-+ udc_ep2_reset(usb);
-+ }
-+
-+ /*
-+ * mask reset ints, they flood during sequence, enable
-+ * suspend and resume
-+ */
-+ usb->udccr = (usb->udccr & ~(UDCCR_SUSIM | UDCCR_RESIM)) | UDCCR_REM;
-+ Ser0UDCCR = usb->udccr;
-+}
-+
-+/*
-+ * handle interrupt for endpoint zero
-+ */
-+static void udc_ep0_int_hndlr(struct sausb_dev *usb)
-+{
-+ u32 cs_reg_in;
-+
-+ pcs("-->");
-+
-+ cs_reg_in = Ser0UDCCS0;
-+
-+ /*
-+ * If "setup end" has been set, the usb controller has terminated
-+ * a setup transaction before we set DE. This happens during
-+ * enumeration with some hosts. For example, the host will ask for
-+ * our device descriptor and specify a return of 64 bytes. When we
-+ * hand back the first 8, the host will know our max packet size
-+ * and turn around and issue a new setup immediately. This causes
-+ * the UDC to auto-ack the new setup and set SE. We must then
-+ * "unload" (process) the new setup, which is what will happen
-+ * after this preamble is finished executing.
-+ */
-+ if (cs_reg_in & UDCCS0_SE) {
-+ DPRINTK("UDC: early termination of setup\n");
-+
-+ /*
-+ * Clear setup end
-+ */
-+ set_cs_bits(UDCCS0_SSE);
-+
-+ /*
-+ * Clear any pending write.
-+ */
-+ ep0_clear_write(usb);
-+ }
-+
-+ /*
-+ * UDC sent a stall due to a protocol violation.
-+ */
-+ if (cs_reg_in & UDCCS0_SST) {
-+ usb->ep0_stall_sent++;
-+
-+ DPRINTK("UDC: write_preamble: UDC sent stall\n");
-+
-+ /*
-+ * Clear sent stall
-+ */
-+ set_cs_bits(UDCCS0_SST);
-+
-+ /*
-+ * Clear any pending write.
-+ */
-+ ep0_clear_write(usb);
-+ }
-+
-+ switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) {
-+ case UDCCS0_OPR | UDCCS0_IPR:
-+ DPRINTK("UDC: write_preamble: see OPR. Stopping write to "
-+ "handle new SETUP\n");
-+
-+ /*
-+ * very rarely, you can get OPR and
-+ * leftover IPR. Try to clear
-+ */
-+ UDC_clear(Ser0UDCCS0, UDCCS0_IPR);
-+
-+ /*
-+ * Clear any pending write.
-+ */
-+ ep0_clear_write(usb);
-+
-+ /*FALLTHROUGH*/
-+ case UDCCS0_OPR:
-+ /*
-+ * A new setup request is pending. Handle
-+ * it. Note that we don't try to read a
-+ * packet if SE was set and OPR is clear.
-+ */
-+ udc_ep0_read_packet(usb, cs_reg_in);
-+ break;
-+
-+ case 0:
-+ if (usb->wrint) {
-+ if (usb->wrlen != 0) {
-+ /*
-+ * More data to go
-+ */
-+ udc_ep0_write_fifo(usb);
-+ set_ipr();
-+ }
-+
-+ if (usb->wrlen == 0) {
-+ /*
-+ * All data sent.
-+ */
-+ usb->wrint(usb);
-+
-+ ep0_clear_write(usb);
-+ }
-+ }
-+ break;
-+
-+ case UDCCS0_IPR:
-+ DPRINTK("UDC: IPR set, not writing\n");
-+ usb->ep0_early_irqs++;
-+ break;
-+ }
-+
-+ pcs("<--");
-+}
-+
-+static irqreturn_t udc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ struct sausb_dev *usb = dev_id;
-+ u32 status = Ser0UDCSR;
-+
-+ /*
-+ * ReSeT Interrupt Request - UDC has been reset
-+ */
-+ if (status & UDCSR_RSTIR) {
-+ udc_reset(usb);
-+
-+ /*
-+ * clear all pending sources
-+ */
-+ UDC_flip(Ser0UDCSR, status);
-+ return IRQ_HANDLED;
-+ }
-+
-+ /*
-+ * else we have done something other than reset,
-+ * so be sure reset enabled
-+ */
-+ usb->udccr &= ~UDCCR_REM;
-+ UDC_write(Ser0UDCCR, usb->udccr);
-+
-+ /*
-+ * RESume Interrupt Request
-+ */
-+ if (status & UDCSR_RESIR) {
-+ usbctl_resume(usb->ctl);
-+ core_kicker(usb);
-+ enable_suspend_mask_resume(usb);
-+ }
-+
-+ /*
-+ * SUSpend Interrupt Request
-+ */
-+ if (status & UDCSR_SUSIR) {
-+ usbctl_suspend(usb->ctl);
-+ enable_resume_mask_suspend(usb);
-+ }
-+
-+ /*
-+ * clear all pending sources
-+ */
-+ UDC_flip(Ser0UDCSR, status);
-+
-+ if (status & UDCSR_EIR)
-+ udc_ep0_int_hndlr(usb);
-+
-+ if (status & UDCSR_RIR)
-+ udc_ep1_int_hndlr(usb);
-+
-+ if (status & UDCSR_TIR)
-+ udc_ep2_int_hndlr(usb);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+#ifdef CONFIG_PROC_FS
-+
-+#define SAY( fmt, args... ) p += sprintf(p, fmt, ## args )
-+#define SAYV( num ) p += sprintf(p, num_fmt, "Value", num )
-+#define SAYC( label, yn ) p += sprintf(p, yn_fmt, label, yn )
-+#define SAYS( label, v ) p += sprintf(p, cnt_fmt, label, v )
-+
-+static int
-+udc_read_proc(char *page, char **start, off_t off, int cnt, int *eof,
-+ void *data)
-+{
-+ struct sausb_dev *usb = data;
-+ char *p = page;
-+ u32 v;
-+ int len, i;
-+
-+ p += usbctl_proc_info(usb->ctl, p);
-+ p += sprintf(p, "\nUDC:\n");
-+ v = Ser0UDCAR;
-+ p += sprintf(p, "Address\t: %d (0x%02x)\n", v, v);
-+ v = Ser0UDCIMP;
-+ p += sprintf(p, "IN max\t: %d (0x%02x)\n", v + 1, v);
-+ v = Ser0UDCOMP;
-+ p += sprintf(p, "OUT max\t: %d (0x%02x)\n", v + 1, v);
-+ v = Ser0UDCCR;
-+ p += sprintf(p, "UDCCR\t: 0x%02x "
-+ "[ %cSUSIM %cTIM %cRIM %cEIM %cRESIM %cUDA %cUDD ] "
-+ "(0x%02x)\n",
-+ v,
-+ v & UDCCR_SUSIM ? '+' : '-', v & UDCCR_TIM ? '+' : '-',
-+ v & UDCCR_RIM ? '+' : '-', v & UDCCR_EIM ? '+' : '-',
-+ v & UDCCR_RESIM ? '+' : '-', v & UDCCR_UDA ? '+' : '-',
-+ v & UDCCR_UDD ? '+' : '-', usb->udccr);
-+ v = Ser0UDCCS0;
-+ p += sprintf(p, "UDCCS0\t: 0x%02x "
-+ "[ %cSO %cSE %cDE %cFST %cSST %cIPR %cOPR ]\n",
-+ v,
-+ v & UDCCS0_SO ? '+' : '-', v & UDCCS0_SE ? '+' : '-',
-+ v & UDCCS0_DE ? '+' : '-', v & UDCCS0_FST ? '+' : '-',
-+ v & UDCCS0_SST ? '+' : '-', v & UDCCS0_IPR ? '+' : '-',
-+ v & UDCCS0_OPR ? '+' : '-');
-+ v = Ser0UDCCS1;
-+ p += sprintf(p, "UDCCS1\t: 0x%02x "
-+ "[ %cRNE %cFST %cSST %cRPE %cRPC %cRFS ]\n",
-+ v,
-+ v & UDCCS1_RNE ? '+' : '-', v & UDCCS1_FST ? '+' : '-',
-+ v & UDCCS1_SST ? '+' : '-', v & UDCCS1_RPE ? '+' : '-',
-+ v & UDCCS1_RPC ? '+' : '-', v & UDCCS1_RFS ? '+' : '-');
-+ v = Ser0UDCCS2;
-+ p += sprintf(p, "UDCCS2\t: 0x%02x "
-+ "[ %cFST %cSST %cTUR %cTPE %cTPC %cTFS ]\n",
-+ v,
-+ v & UDCCS2_FST ? '+' : '-', v & UDCCS2_SST ? '+' : '-',
-+ v & UDCCS2_TUR ? '+' : '-', v & UDCCS2_TPE ? '+' : '-',
-+ v & UDCCS2_TPC ? '+' : '-', v & UDCCS2_TFS ? '+' : '-');
-+
-+ p += sprintf(p, "\n");
-+ p += sprintf(p, " Bytes Packets FIFO errs Max Sz\n");
-+ p += sprintf(p, "EP0 Rd: %10ld %10ld %10ld -\n",
-+ usb->ep0_rd_bytes,
-+ usb->ep0_rd_packets,
-+ usb->ep0_rd_fifo_errs);
-+ p += sprintf(p, "EP0 Wr: %10ld %10ld %10ld -\n",
-+ usb->ep0_wr_bytes,
-+ usb->ep0_wr_packets,
-+ usb->ep0_wr_fifo_errs);
-+
-+ for (i = 0; i < 2; i++)
-+ p += sprintf(p, "EP%d : %10ld %10ld %10ld %6d\n",
-+ i + 1,
-+ usb->ep[i].bytes,
-+ usb->ep[i].packets,
-+ usb->ep[i].fifo_errs,
-+ usb->ep[i].maxpktsize);
-+
-+ p += sprintf(p, "Stalls sent\t: %ld\n", usb->ep0_stall_sent);
-+ p += sprintf(p, "Early ints\t: %ld\n", usb->ep0_early_irqs);
-+
-+#if 0
-+ v = Ser0UDCSR;
-+ SAY("\nUDC Interrupt Request Register\n");
-+ SAYV(v);
-+ SAYC("Reset pending", (v & UDCSR_RSTIR) ? yes : no);
-+ SAYC("Suspend pending", (v & UDCSR_SUSIR) ? yes : no);
-+ SAYC("Resume pending", (v & UDCSR_RESIR) ? yes : no);
-+ SAYC("ep0 pending", (v & UDCSR_EIR) ? yes : no);
-+ SAYC("receiver pending", (v & UDCSR_RIR) ? yes : no);
-+ SAYC("tramsitter pending", (v & UDCSR_TIR) ? yes : no);
-+
-+#ifdef CONFIG_SA1100_EXTENEX1
-+ SAYC("\nSoft connect",
-+ (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden");
-+#endif
-+#endif
-+
-+ len = (p - page) - off;
-+ if (len < 0)
-+ len = 0;
-+ *eof = (len <= cnt) ? 1 : 0;
-+ *start = page + off;
-+
-+ return len;
-+}
-+
-+#endif
-+
-+extern struct usbctl usbctl;
-+
-+static int __devinit udc_probe(struct device *dev)
-+{
-+ struct sausb_dev *usb;
-+ int retval;
-+
-+ if (!request_mem_region(0x80000000, 0x10000, "sa11x0-udc"))
-+ return -EBUSY;
-+
-+ usb = kmalloc(sizeof(struct sausb_dev), GFP_KERNEL);
-+ if (!usb)
-+ return -ENOMEM;
-+
-+ memset(usb, 0, sizeof(struct sausb_dev));
-+ dev_set_drvdata(dev, usb);
-+
-+ usb_sa1100_drv.priv = usb;
-+
-+ usb->dev = dev;
-+ usb->ctl = &usbctl;
-+
-+ spin_lock_init(&usb->lock);
-+
-+ udc_disable(usb);
-+
-+ usbctl_init(usb->ctl, &usb_sa1100_drv);
-+
-+#ifdef CONFIG_PROC_FS
-+ create_proc_read_entry("sausb", 0, NULL, udc_read_proc, usb);
-+#endif
-+
-+ /* setup rx dma */
-+ retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive",
-+ NULL, NULL, &usb->ep[0].dmach);
-+ if (retval) {
-+ printk("UDC: unable to register for rx dma rc=%d\n",
-+ retval);
-+ goto err;
-+ }
-+
-+ /* setup tx dma */
-+ retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit",
-+ NULL, NULL, &usb->ep[1].dmach);
-+ if (retval) {
-+ printk("UDC: unable to register for tx dma rc=%d\n",
-+ retval);
-+ goto err;
-+ }
-+
-+ /* now allocate the IRQ. */
-+ retval = request_irq(IRQ_Ser0UDC, udc_interrupt, SA_INTERRUPT,
-+ "SA USB core", usb);
-+ if (retval) {
-+ printk("UDC: couldn't request USB irq rc=%d\n", retval);
-+ goto err;
-+ }
-+
-+ return retval;
-+
-+ err:
-+ if (usb->ep[2].dmach) {
-+ sa1100_free_dma(usb->ep[2].dmach);
-+ usb->ep[2].dmach = NULL;
-+ }
-+ if (usb->ep[1].dmach) {
-+ sa1100_free_dma(usb->ep[1].dmach);
-+ usb->ep[1].dmach = NULL;
-+ }
-+#ifdef CONFIG_PROC_FS
-+ remove_proc_entry("sausb", NULL);
-+#endif
-+ release_mem_region(0x80000000, 0x10000);
-+ return retval;
-+}
-+
-+/*
-+ * Release DMA and interrupt resources
-+ */
-+static int __devexit udc_remove(struct device *dev)
-+{
-+ struct sausb_dev *usb = dev_get_drvdata(dev);
-+
-+ dev_set_drvdata(dev, NULL);
-+
-+#ifdef CONFIG_PROC_FS
-+ remove_proc_entry("sausb", NULL);
-+#endif
-+
-+ udc_disable(usb);
-+
-+ free_irq(IRQ_Ser0UDC, usb);
-+ sa1100_free_dma(usb->ep[1].dmach);
-+ sa1100_free_dma(usb->ep[0].dmach);
-+
-+ usbctl_exit(usb->ctl);
-+
-+ release_mem_region(0x80000000, 0x10000);
-+
-+ return 0;
-+}
-+
-+static struct device_driver sa11x0usb_driver = {
-+ .name = "sa11x0-udc",
-+ .bus = &platform_bus_type,
-+ .probe = udc_probe,
-+ .remove = __devexit_p(udc_remove),
-+};
-+
-+static int __init udc_init(void)
-+{
-+ return driver_register(&sa11x0usb_driver);
-+}
-+
-+static void __exit udc_exit(void)
-+{
-+ driver_unregister(&sa11x0usb_driver);
-+}
-+
-+module_init(udc_init);
-+module_exit(udc_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("SA1100 USB Gadget driver");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/control.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,933 @@
-+/*
-+ * usb/control.c
-+ *
-+ * This parses and handles all the control messages to/from endpoint 0.
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/usb_ch9.h>
-+#include <linux/gfp.h>
-+#include <linux/init.h>
-+
-+#include "buffer.h"
-+#include "client.h"
-+#include "usbdev.h"
-+
-+#include "sa1100_usb.h"
-+
-+#define USB_ENDPOINT_HALT 0
-+#define USB_DEVICE_REMOTE_WAKEUP 1
-+
-+#undef DEBUG
-+
-+#ifdef DEBUG
-+#define DPRINTK(fmt, args...) printk(KERN_DEBUG fmt , ## args)
-+#else
-+#define DPRINTK(fmt, args...)
-+#endif
-+
-+/*
-+ * print string descriptor
-+ */
-+static char * __attribute__((unused))
-+psdesc(char *str, int len, struct usb_string_descriptor *desc)
-+{
-+ char *start = str;
-+ int nchars = (desc->bLength - 2) / sizeof(__u16) + 2;
-+ int i;
-+
-+ if (nchars >= len)
-+ nchars = len - 1;
-+
-+ nchars -= 2;
-+
-+ *str++ = '"';
-+ for(i = 0; i < nchars; i++)
-+ *str++ = le16_to_cpu(desc->wData[i]);
-+ *str++ = '"';
-+ *str = '\0';
-+
-+ return start;
-+}
-+
-+enum {
-+ kError = -1,
-+ kEvSuspend = 0,
-+ kEvReset = 1,
-+ kEvResume = 2,
-+ kEvAddress = 3,
-+ kEvConfig = 4,
-+ kEvDeConfig = 5
-+};
-+
-+enum {
-+ kStateZombie = 0,
-+ kStateZombieSuspend = 1,
-+ kStateDefault = 2,
-+ kStateDefaultSuspend = 3,
-+ kStateAddr = 4,
-+ kStateAddrSuspend = 5,
-+ kStateConfig = 6,
-+ kStateConfigSuspend = 7
-+};
-+
-+#define kE kError
-+#define kSZ kStateZombie
-+#define kSZS kStateZombieSuspend
-+#define kSD kStateDefault
-+#define kSDS kStateDefaultSuspend
-+#define kSA kStateAddr
-+#define kSAS kStateAddrSuspend
-+#define kSC kStateConfig
-+#define kSCS kStateConfigSuspend
-+
-+/*
-+ * Fig 9-1 P192
-+ * Zombie == Attached | Powered
-+ */
-+static int device_state_machine[8][6] = {
-+// suspend reset resume addr config deconfig
-+{ kSZS, kSD, kE, kE, kE, kE }, /* zombie */
-+{ kE, kSD, kSZ, kE, kE, kE }, /* zom sus */
-+{ kSDS, kError, kSD, kSA, kE, kE }, /* default */
-+{ kE, kSD, kSD, kE, kE, kE }, /* def sus */
-+{ kSAS, kSD, kE, kE, kSC, kE }, /* addr */
-+{ kE, kSD, kSA, kE, kE, kE }, /* addr sus */
-+{ kSCS, kSD, kE, kE, kE, kSA }, /* config */
-+{ kE, kSD, kSC, kE, kE, kE } /* cfg sus */
-+};
-+
-+/*
-+ * "device state" is the usb device framework state, as opposed to the
-+ * "state machine state" which is whatever the driver needs and is much
-+ * more fine grained
-+ */
-+static int sm_state_to_device_state[8] = {
-+ USB_STATE_POWERED, /* zombie */
-+ USB_STATE_SUSPENDED, /* zombie suspended */
-+ USB_STATE_DEFAULT, /* default */
-+ USB_STATE_SUSPENDED, /* default suspended */
-+ USB_STATE_ADDRESS, /* address */
-+ USB_STATE_SUSPENDED, /* address suspended */
-+ USB_STATE_CONFIGURED, /* config */
-+ USB_STATE_SUSPENDED /* config suspended */
-+};
-+
-+static char * state_names[8] = {
-+ "zombie",
-+ "zombie suspended",
-+ "default",
-+ "default suspended",
-+ "address",
-+ "address suspended",
-+ "configured",
-+ "config suspended"
-+};
-+
-+static char * event_names[6] = {
-+ "suspend",
-+ "reset",
-+ "resume",
-+ "address assigned",
-+ "configure",
-+ "de-configure"
-+};
-+
-+static char * device_state_names[] = {
-+ "not attached",
-+ "attached",
-+ "powered",
-+ "default",
-+ "address",
-+ "configured",
-+ "suspended"
-+};
-+
-+static void usbctl_callbacks(struct usbctl *ctl, int state, int oldstate)
-+{
-+ struct usb_client *clnt = ctl->clnt;
-+
-+ /*
-+ * Inform any clients currently attached
-+ * that the connectivity state changed.
-+ */
-+ if (clnt && clnt->state_change)
-+ clnt->state_change(clnt->priv, state, oldstate);
-+}
-+
-+/*
-+ * called by the interrupt handler here and the two endpoint
-+ * files when interesting .."events" happen
-+ */
-+static int usbctl_next_state_on_event(struct usbctl *ctl, int event)
-+{
-+ int next_state, next_dev_state, old_dev_state;
-+
-+ printk(KERN_DEBUG "usbctl: %s --[%s]--> ", state_names[ctl->sm_state],
-+ event_names[event]);
-+
-+ next_state = device_state_machine[ctl->sm_state][event];
-+ if (next_state != kError) {
-+ next_dev_state = sm_state_to_device_state[next_state];
-+
-+ printk("%s. Device in %s state.\n",
-+ state_names[next_state],
-+ device_state_names[next_dev_state]);
-+
-+ old_dev_state = ctl->state;
-+ ctl->sm_state = next_state;
-+ ctl->state = next_dev_state;
-+
-+ if (old_dev_state != next_dev_state)
-+ usbctl_callbacks(ctl, next_dev_state, old_dev_state);
-+ } else
-+ printk("(error)\n");
-+
-+ return next_state;
-+}
-+
-+/*
-+ * Driver detected USB HUB reset.
-+ */
-+int usbctl_reset(struct usbctl *ctl)
-+{
-+ int ret;
-+
-+ ret = usbctl_next_state_on_event(ctl, kEvReset) == kError;
-+
-+ if (!ret) {
-+ ctl->address = 0;
-+ }
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(usbctl_reset);
-+
-+void usbctl_suspend(struct usbctl *ctl)
-+{
-+ usbctl_next_state_on_event(ctl, kEvSuspend);
-+}
-+
-+EXPORT_SYMBOL(usbctl_suspend);
-+
-+void usbctl_resume(struct usbctl *ctl)
-+{
-+ usbctl_next_state_on_event(ctl, kEvResume);
-+}
-+
-+EXPORT_SYMBOL(usbctl_resume);
-+
-+static struct usb_interface_descriptor *
-+usbctl_get_interface_descriptor(struct usbctl *ctl, unsigned int interface)
-+{
-+ /*FIXME*/
-+ struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
-+
-+ return (struct usb_interface_descriptor *)&cdb->intf;
-+}
-+
-+static inline int
-+__usbctl_queue(struct usbctl *ctl, struct usb_ctrlrequest *req,
-+ struct usb_buf *buf)
-+{
-+ unsigned int reqlen = le16_to_cpu(req->wLength);
-+
-+ return ctl->driver->ep0_queue(ctl->driver->priv, buf, reqlen) ?
-+ RET_ERROR : RET_QUEUED;
-+}
-+
-+static int
-+usbctl_queue(struct usbctl *ctl, struct usb_ctrlrequest *req,
-+ void *data, unsigned int len)
-+{
-+ struct usb_buf *buf;
-+
-+ buf = usbb_alloc(len, GFP_ATOMIC);
-+ if (!buf) {
-+ printk(KERN_ERR "usb: out of memory\n");
-+ return RET_ERROR;
-+ }
-+
-+ if (data)
-+ memcpy(usbb_push(buf, len), data, len);
-+
-+ return __usbctl_queue(ctl, req, buf);
-+}
-+
-+/*
-+ * 9.4.5: Get Status (device)
-+ */
-+static int
-+usbctl_parse_dev_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ u16 status;
-+
-+ status = /* self_powered_hook() ? 1 : 0 */1;
-+
-+ status = cpu_to_le16(status);
-+
-+ return usbctl_queue(ctl, req, &status, 2);
-+}
-+
-+/*
-+ * Send USB device description to the host.
-+ */
-+static int
-+usbctl_desc_device(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ return __usbctl_queue(ctl, req, usbb_get(ctl->dev_desc_buf));
-+}
-+
-+/*
-+ * Send USB configuration information to the host.
-+ */
-+static int
-+usbctl_desc_config(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ /*FIXME*/
-+ struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
-+
-+ return usbctl_queue(ctl, req, cdb, sizeof(struct cdb));
-+}
-+
-+/*
-+ * Send a string to the host from the string table.
-+ */
-+static int
-+usbctl_desc_string(struct usbctl *ctl, struct usb_ctrlrequest *req,
-+ unsigned int idx)
-+{
-+ struct usb_buf *buf;
-+ unsigned int lang = le16_to_cpu(req->wIndex);
-+ char string[32] __attribute__((unused));
-+ int ret;
-+
-+ DPRINTK("usbctl: desc_string (index %u, lang 0x%04x): ", idx, lang);
-+
-+ buf = usbc_string_find(&ctl->strings, lang, idx);
-+ if (buf) {
-+ DPRINTK("%s\n", idx == 0 ? "language" :
-+ psdesc(string, sizeof(string), usbc_string_desc(buf)));
-+
-+ ret = __usbctl_queue(ctl, req, buf);
-+ } else {
-+ DPRINTK("not found -> stall\n");
-+ ret = RET_REQERROR;
-+ }
-+ return ret;
-+}
-+
-+/*
-+ * Send an interface description (and endpoints) to the host.
-+ */
-+static int
-+usbctl_desc_interface(struct usbctl *ctl, struct usb_ctrlrequest *req,
-+ unsigned int idx)
-+{
-+ struct usb_interface_descriptor *desc;
-+ int ret;
-+
-+ DPRINTK("usbctl: desc_interface (index %d)\n", idx);
-+
-+ desc = usbctl_get_interface_descriptor(ctl, idx);
-+
-+ if (desc) {
-+ ret = usbctl_queue(ctl, req, desc, desc->bLength);
-+ } else {
-+ printk("usbctl: unknown interface %d\n", idx);
-+ ret = RET_REQERROR;
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * Send an endpoint (1 .. n) to the host.
-+ */
-+static int
-+usbctl_desc_endpoint(struct usbctl *ctl, struct usb_ctrlrequest *req,
-+ unsigned int idx)
-+{
-+ int ret;
-+
-+ DPRINTK("usbctl: desc_endpoint (index %d)\n", idx);
-+
-+ if (idx >= 1 && idx <= ctl->nr_ep) {
-+ struct usb_endpoint_descriptor *ep = ctl->ep_desc[idx - 1];
-+
-+ ret = usbctl_queue(ctl, req, ep, ep->bLength);
-+ } else {
-+ printk("usbctl: unknown endpoint %d\n", idx);
-+ ret = RET_REQERROR;
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * 9.4.3: Parse a request for a descriptor.
-+ * Unspecified conditions:
-+ * None
-+ * Valid states: default, address, configured.
-+ */
-+static int
-+usbctl_parse_dev_descriptor(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int idx = le16_to_cpu(req->wValue) & 255;
-+ unsigned int type = le16_to_cpu(req->wValue) >> 8;
-+ int ret;
-+
-+ switch (type) {
-+ case USB_DT_DEVICE: /* check if idx matters */
-+ ret = usbctl_desc_device(ctl, req);
-+ break;
-+
-+ case USB_DT_CONFIG: /* check if idx matters */
-+ ret = usbctl_desc_config(ctl, req);
-+ break;
-+
-+ case USB_DT_STRING:
-+ ret = usbctl_desc_string(ctl, req, idx);
-+ break;
-+
-+ case USB_DT_INTERFACE:
-+ ret = usbctl_desc_interface(ctl, req, idx);
-+ break;
-+
-+ case USB_DT_ENDPOINT:
-+ ret = usbctl_desc_endpoint(ctl, req, idx);
-+ break;
-+
-+ case USB_DT_DEVICE_QUALIFIER:
-+ case USB_DT_OTHER_SPEED_CONFIG:
-+ case USB_DT_INTERFACE_POWER:
-+ default:
-+ printk(KERN_ERR "usbctl: unknown descriptor: "
-+ "wValue = 0x%04x wIndex = 0x%04x\n",
-+ le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex));
-+ ret = RET_REQERROR;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * 9.4.6: Set Address
-+ * The USB1.1 spec says the response to SetAddress() with value 0
-+ * is undefined. It then goes on to define the response. We
-+ * acknowledge addresses of zero, but take no further action.
-+ */
-+static int
-+usbctl_parse_dev_set_address(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int address = le16_to_cpu(req->wValue) & 0x7f;
-+
-+ if (ctl->state == USB_STATE_CONFIGURED)
-+ return RET_REQERROR;
-+
-+ if (address != 0) {
-+ ctl->address = address;
-+
-+ usbctl_next_state_on_event(ctl, kEvAddress);
-+
-+ ctl->driver->set_address(ctl->driver->priv, address);
-+ }
-+
-+ return RET_ACK;
-+}
-+
-+/*
-+ * 9.4.2: Get Configuration.
-+ * Unspecified conditions:
-+ * - non-zero wIndex, wValue or wLength (ignored)
-+ * - default state (request error)
-+ * Valid states: address, configured.
-+ */
-+static int
-+usbctl_parse_dev_get_config(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ u8 status = 0;
-+
-+ if (ctl->state == USB_STATE_CONFIGURED)
-+ status = 1;
-+
-+ return usbctl_queue(ctl, req, &status, 1);
-+}
-+
-+/*
-+ * 9.4.7: Set Configuration.
-+ * Unspecified conditions:
-+ * - default state (request error)
-+ */
-+static int
-+usbctl_parse_dev_set_config(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int cfg = le16_to_cpu(req->wValue);
-+ int ret = RET_REQERROR;
-+
-+ if (ctl->state == USB_STATE_DEFAULT)
-+ return ret;
-+
-+ if (cfg == 0) {
-+ /* enter address state, or remain in address state */
-+ usbctl_next_state_on_event(ctl, kEvDeConfig);
-+
-+ ctl->driver->set_config(ctl->driver->priv, NULL);
-+
-+ ret = RET_ACK;
-+ } else if (cfg == 1) {
-+ /* enter configured state, and set configuration */
-+ /*FIXME*/
-+ struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
-+
-+ usbctl_next_state_on_event(ctl, kEvConfig);
-+
-+ ctl->driver->set_config(ctl->driver->priv, cdb);
-+ ret = RET_ACK;
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * Interface handling
-+ */
-+
-+/*
-+ * 9.4.5: Get Status (interface)
-+ */
-+static int
-+usbctl_parse_int_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int interface = le16_to_cpu(req->wIndex) & 255;
-+ u16 status;
-+
-+ switch (ctl->state) {
-+ case USB_STATE_DEFAULT:
-+ return RET_REQERROR;
-+
-+ case USB_STATE_ADDRESS:
-+ if (interface != 0)
-+ return RET_REQERROR;
-+ break;
-+
-+ case USB_STATE_CONFIGURED:
-+ if (interface != 1)
-+ return RET_REQERROR;
-+ break;
-+ }
-+
-+ status = cpu_to_le16(0);
-+
-+ return usbctl_queue(ctl, req, &status, 2);
-+}
-+
-+/*
-+ * 9.4.4: Get Interface
-+ * Unspecified conditions:
-+ * -
-+ * States: Default (unspecified), Address (Request Error), Configured (ok)
-+ */
-+static int
-+usbctl_parse_int_get_interface(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int interface = le16_to_cpu(req->wIndex) & 255;
-+ u8 null = 0;
-+
-+ if (ctl->state != USB_STATE_CONFIGURED)
-+ return RET_REQERROR;
-+
-+ /*
-+ * If the interface doesn't exist, respond with request error
-+ */
-+ if (interface != 1)
-+ return RET_REQERROR;
-+
-+ printk("usbctl: get interface %d not supported\n", interface);
-+
-+ return usbctl_queue(ctl, req, &null, 1);
-+}
-+
-+static int
-+usbctl_parse_int_set_interface(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int interface = le16_to_cpu(req->wIndex) & 255;
-+
-+ if (interface != 0)
-+ printk("usbctl: set interface %d not supported (ignored)\n",
-+ interface);
-+
-+ return RET_ACK;
-+}
-+
-+/*
-+ * Endpoint handling
-+ */
-+
-+/*
-+ * 9.4.5: Get Status (endpoint)
-+ */
-+static int
-+usbctl_parse_ep_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int ep = le16_to_cpu(req->wIndex) & 15;
-+ u16 status;
-+
-+ if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) ||
-+ ep <= ctl->nr_ep)
-+ return RET_REQERROR;
-+
-+ status = ctl->driver->ep_get_status(ctl->driver->priv, ep);
-+ status = cpu_to_le16(status);
-+
-+ return usbctl_queue(ctl, req, &status, 2);
-+}
-+
-+/*
-+ * 9.4.1: Clear an endpoint feature. We only support ENDPOINT_HALT.
-+ * Unspecified conditions:
-+ * - non-zero wLength is not specified (ignored)
-+ * Valid states: Address, Configured.
-+ */
-+static int
-+usbctl_parse_ep_clear_feature(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int feature = le16_to_cpu(req->wValue);
-+ unsigned int ep = le16_to_cpu(req->wIndex) & 15;
-+ int ret;
-+
-+ if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) ||
-+ ep <= ctl->nr_ep)
-+ return RET_REQERROR;
-+
-+ if (feature == USB_ENDPOINT_HALT) {
-+ ctl->driver->ep_halt(ctl->driver->priv, ep, 0);
-+ ret = RET_ACK;
-+ } else {
-+ printk(KERN_ERR "usbctl: unsupported clear feature: "
-+ "wValue = 0x%04x wIndex = 0x%04x\n",
-+ feature, ep);
-+
-+ ret = RET_REQERROR;
-+ }
-+ return ret;
-+}
-+
-+/*
-+ * 9.4.9: Set Feature (endpoint)
-+ */
-+static int
-+usbctl_parse_ep_set_feature(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int feature = le16_to_cpu(req->wValue);
-+ unsigned int ep = le16_to_cpu(req->wIndex) & 15;
-+ int ret;
-+
-+ if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) ||
-+ ep <= ctl->nr_ep)
-+ return RET_REQERROR;
-+
-+ if (feature == USB_ENDPOINT_HALT) {
-+ ctl->driver->ep_halt(ctl->driver->priv, ep, 1);
-+ ret = RET_ACK;
-+ } else {
-+ printk(KERN_ERR "usbctl: unsupported set feature "
-+ "wValue = 0x%04x wIndex = 0x%04x\n",
-+ feature, ep);
-+
-+ ret = RET_REQERROR;
-+ }
-+ return ret;
-+}
-+
-+/*
-+ * This reflects Table 9.3 (p186) in the USB1.1 spec.
-+ *
-+ * Some notes:
-+ * - USB1.1 specifies remote wakeup feature, so we don't implement
-+ * USB_RECIP_DEVICE USB_REQ_{SET,CLEAR}_FEATURE
-+ * - USB1.1 doesn't actually specify any interface features, so we
-+ * don't implement USB_RECIP_INTERFACE USB_REQ_{SET,CLEAR}_FEATURE
-+ */
-+static int (*request_fns[4][16])(struct usbctl *, struct usb_ctrlrequest *) = {
-+ [USB_RECIP_DEVICE] = {
-+ [USB_REQ_GET_STATUS] = usbctl_parse_dev_get_status,
-+ [USB_REQ_CLEAR_FEATURE] = NULL,
-+ [USB_REQ_SET_FEATURE] = NULL,
-+ [USB_REQ_SET_ADDRESS] = usbctl_parse_dev_set_address,
-+ [USB_REQ_GET_DESCRIPTOR] = usbctl_parse_dev_descriptor,
-+ [USB_REQ_SET_DESCRIPTOR] = NULL,
-+ [USB_REQ_GET_CONFIGURATION] = usbctl_parse_dev_get_config,
-+ [USB_REQ_SET_CONFIGURATION] = usbctl_parse_dev_set_config,
-+ },
-+
-+ [USB_RECIP_INTERFACE] = {
-+ [USB_REQ_GET_STATUS] = usbctl_parse_int_get_status,
-+ [USB_REQ_CLEAR_FEATURE] = NULL,
-+ [USB_REQ_SET_FEATURE] = NULL,
-+ [USB_REQ_GET_INTERFACE] = usbctl_parse_int_get_interface,
-+ [USB_REQ_SET_INTERFACE] = usbctl_parse_int_set_interface,
-+ },
-+
-+ [USB_RECIP_ENDPOINT] = {
-+ [USB_REQ_GET_STATUS] = usbctl_parse_ep_get_status,
-+ [USB_REQ_CLEAR_FEATURE] = usbctl_parse_ep_clear_feature,
-+ [USB_REQ_SET_FEATURE] = usbctl_parse_ep_set_feature,
-+ },
-+};
-+
-+static void __attribute__((unused))
-+usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req)
-+{
-+ printk("%sbRequestType=0x%02x bRequest=0x%02x "
-+ "wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n",
-+ prefix, req->bRequestType, req->bRequest,
-+ le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex),
-+ le16_to_cpu(req->wLength));
-+}
-+
-+int usbctl_parse_request(struct usbctl *ctl, struct usb_ctrlrequest *req)
-+{
-+ unsigned int type;
-+ int (*fn)(struct usbctl *, struct usb_ctrlrequest *) = NULL;
-+ int ret = RET_REQERROR;
-+
-+ //usbctl_dump_request("usbctl: ", req);
-+
-+ type = req->bRequestType & USB_TYPE_MASK;
-+ if (type == USB_TYPE_STANDARD) {
-+ unsigned int recip;
-+
-+ recip = req->bRequestType & USB_RECIP_MASK;
-+ if (recip < ARRAY_SIZE(request_fns) &&
-+ req->bRequest < ARRAY_SIZE(request_fns[0]))
-+ fn = request_fns[recip][req->bRequest];
-+ }
-+
-+ if (fn)
-+ ret = fn(ctl, req);
-+ else
-+ usbctl_dump_request(KERN_ERR "usbctl: unknown request: ",
-+ req);
-+
-+ /*
-+ * Make sure we're doing the right thing.
-+ */
-+ if (req->bRequestType & USB_DIR_IN) {
-+ if (ret != RET_QUEUED && ret != RET_REQERROR)
-+ printk("Error: device to host transfer expected\n");
-+ } else {
-+ if (ret == RET_QUEUED)
-+ printk("Error: no device to host transfer expected\n");
-+ }
-+
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(usbctl_parse_request);
-+
-+/* Start running. Must have called usb_open (above) first */
-+int usbctl_start(struct usb_client *client)
-+{
-+ struct usbctl *ctl = client->ctl;
-+
-+ if (ctl == NULL || ctl->clnt != client) {
-+ printk("usbctl: start: no client registered\n");
-+ return -EPERM;
-+ }
-+
-+ ctl->sm_state = kStateZombie;
-+ ctl->state = USB_STATE_POWERED;
-+
-+ /*
-+ * Notify the client as to our state.
-+ */
-+ usbctl_callbacks(ctl, USB_STATE_POWERED, USB_STATE_SUSPENDED);
-+
-+ return ctl->driver->start(ctl->driver->priv);
-+}
-+
-+EXPORT_SYMBOL(usbctl_start);
-+
-+/*
-+ * Stop USB core from running
-+ */
-+void usbctl_stop(struct usb_client *client)
-+{
-+ struct usbctl *ctl = client->ctl;
-+
-+ if (ctl == NULL || ctl->clnt != client) {
-+ printk("USBDEV: stop: no client/driver registered\n");
-+ return;
-+ }
-+
-+ ctl->driver->stop(ctl->driver->priv);
-+}
-+
-+EXPORT_SYMBOL(usbctl_stop);
-+
-+struct usbctl usbctl;
-+
-+EXPORT_SYMBOL(usbctl);
-+
-+/* Open SA usb core on behalf of a client, but don't start running */
-+
-+int usbctl_open(struct usb_client *client)
-+{
-+ struct usbctl *ctl = &usbctl;
-+ int ret;
-+printk("usbctl_open: ctl %p driver %p\n", ctl, ctl->driver);
-+ if (!ctl->driver || !try_module_get(ctl->driver->owner))
-+ return -ENODEV;
-+
-+ if (ctl->clnt != NULL) {
-+ ret = -EBUSY;
-+ goto err;
-+ }
-+
-+ ctl->clnt = client;
-+ ctl->state = USB_STATE_SUSPENDED;
-+ ctl->nr_ep = 2;
-+ /* start in zombie suspended state */
-+ ctl->sm_state = kStateZombieSuspend;
-+ ctl->state = USB_STATE_SUSPENDED;
-+ client->ctl = ctl;
-+
-+ ctl->dev_desc_buf = usbb_alloc(sizeof(struct usb_device_descriptor),
-+ GFP_KERNEL);
-+ if (!ctl->dev_desc_buf) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ ctl->dev_desc = usbb_push(ctl->dev_desc_buf,
-+ sizeof(struct usb_device_descriptor));
-+
-+ /* create descriptors for enumeration */
-+ initialize_descriptors(ctl);
-+
-+ return 0;
-+
-+ err:
-+ module_put(ctl->driver->owner);
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(usbctl_open);
-+
-+/* Tell SA core client is through using it */
-+void usbctl_close(struct usb_client *client)
-+{
-+ struct usbctl *ctl = client->ctl;
-+
-+ if (ctl == NULL || ctl->clnt != client) {
-+ printk("usbctl: close: no client registered\n");
-+ return;
-+ }
-+
-+ usbb_put(ctl->dev_desc_buf);
-+
-+ client->ctl = NULL;
-+ ctl->clnt = NULL;
-+ ctl->dev_desc = NULL;
-+ ctl->dev_desc_buf = NULL;
-+ /* reset to zombie suspended state */
-+ ctl->sm_state = kStateZombieSuspend;
-+ ctl->state = USB_STATE_SUSPENDED;
-+
-+ usbc_string_free_all(&ctl->strings);
-+
-+ if (ctl->driver->owner)
-+ module_put(ctl->driver->owner);
-+}
-+
-+EXPORT_SYMBOL(usbctl_close);
-+
-+int usbctl_proc_info(struct usbctl *ctl, char *buf)
-+{
-+ char *p = buf;
-+
-+ p += sprintf(p, "USB Gadget Core:\n");
-+ p += sprintf(p, "Driver\t: %s\n",
-+ ctl->driver ? ctl->driver->name : "none");
-+ p += sprintf(p, "Client\t: %s\n",
-+ ctl->clnt ? ctl->clnt->name : "none");
-+ p += sprintf(p, "State\t: %s (%s) %d\n",
-+ device_state_names[sm_state_to_device_state[ctl->sm_state]],
-+ state_names[ctl->sm_state],
-+ ctl->sm_state);
-+ p += sprintf(p, "Address\t: %d\n", ctl->address);
-+
-+ return p - buf;
-+}
-+
-+EXPORT_SYMBOL(usbctl_proc_info);
-+
-+int
-+usbctl_ep_queue_buffer(struct usbctl *ctl, unsigned int ep,
-+ char *buf, unsigned int len)
-+{
-+ return ctl->driver->ep_queue(ctl->driver->priv, ep, buf, len);
-+}
-+
-+EXPORT_SYMBOL(usbctl_ep_queue_buffer);
-+
-+void usbctl_ep_reset(struct usbctl *ctl, unsigned int ep)
-+{
-+ return ctl->driver->ep_reset(ctl->driver->priv, ep);
-+}
-+
-+EXPORT_SYMBOL(usbctl_ep_reset);
-+
-+void
-+usbctl_ep_set_callback(struct usbctl *ctl, unsigned int ep,
-+ usb_callback_t callback, void *data)
-+{
-+ ctl->driver->ep_callback(ctl->driver->priv, ep, callback, data);
-+}
-+
-+EXPORT_SYMBOL(usbctl_ep_set_callback);
-+
-+int usbctl_ep_idle(struct usbctl *ctl, unsigned int ep)
-+{
-+ return ctl->driver->ep_idle(ctl->driver->priv, ep);
-+}
-+
-+EXPORT_SYMBOL(usbctl_ep_idle);
-+
-+/*
-+ * usbctl_init()
-+ * Module load time. Allocate dma and interrupt resources. Setup /proc fs
-+ * entry. Leave UDC disabled.
-+ */
-+int usbctl_init(struct usbctl *ctl, struct usbc_driver *drv)
-+{
-+ usbc_string_init(&ctl->strings);
-+printk("usbctl_init: %p %p\n", ctl, drv);
-+ /*
-+ * start in zombie suspended state
-+ */
-+ ctl->sm_state = kStateZombieSuspend;
-+ ctl->state = USB_STATE_SUSPENDED;
-+ ctl->driver = drv;
-+
-+ return 0;
-+}
-+
-+/*
-+ * usbctl_exit()
-+ */
-+void usbctl_exit(struct usbctl *ctl)
-+{
-+ usbc_string_free_all(&ctl->strings);
-+
-+ ctl->driver = NULL;
-+}
-+
-+EXPORT_SYMBOL(usbctl_init);
-+EXPORT_SYMBOL(usbctl_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("USB gadget core");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/client.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,40 @@
-+#ifndef USBDEV_CLIENT_H
-+#define USBDEV_CLIENT_H
-+
-+#include "sa1100_usb.h" /* grr */
-+
-+struct usbctl;
-+
-+struct usb_client {
-+ struct usbctl *ctl;
-+ const char *name; /* Client name */
-+ void *priv; /* Client-private data */
-+ void (*state_change)(void *priv, int state, int oldstate);
-+ __u16 vendor; /* USB vendor ID */
-+ __u16 product; /* USB product ID */
-+ __u16 version; /* USB version ID */
-+ __u8 class; /* USB class */
-+ __u8 subclass; /* USB subclass */
-+ __u8 protocol; /* USB protocol */
-+ __u8 unused1;
-+ __u16 unused2;
-+ const char *manufacturer_str;
-+ const char *product_str;
-+ const char *serial_str;
-+};
-+
-+int usbctl_start(struct usb_client *client);
-+void usbctl_stop(struct usb_client *client);
-+int usbctl_open(struct usb_client *client);
-+void usbctl_close(struct usb_client *client);
-+
-+int
-+usbctl_ep_queue_buffer(struct usbctl *ctl, unsigned int ep,
-+ char *buf, unsigned int len);
-+void usbctl_ep_reset(struct usbctl *ctl, unsigned int ep);
-+void
-+usbctl_ep_set_callback(struct usbctl *ctl, unsigned int ep,
-+ usb_callback_t callback, void *data);
-+int usbctl_ep_idle(struct usbctl *ctl, unsigned int ep);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100_usb.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,50 @@
-+/*
-+ * sa1100_usb.h
-+ *
-+ * Public interface to the sa1100 USB core. For use by client modules
-+ * like usb-eth and usb-char.
-+ *
-+ */
-+#ifndef _SA1100_USB_H
-+#define _SA1100_USB_H
-+
-+typedef void (*usb_callback_t)(void *data, int flag, int size);
-+
-+/* in usb_send.c */
-+int sa1100_usb_xmitter_avail( void );
-+int sa1100_usb_send(char *buf, int len);
-+void sa1100_usb_send_set_callback(usb_callback_t callback, void *data);
-+void sa1100_usb_send_reset(void);
-+
-+/* in usb_recev.c */
-+int sa1100_usb_recv(char *buf, int len);
-+void sa1100_usb_recv_set_callback(usb_callback_t callback, void *data);
-+void sa1100_usb_recv_reset(void);
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Descriptor Management
-+//////////////////////////////////////////////////////////////////////////////
-+
-+// MaxPower:
-+#define USB_POWER(x) ((x)>>1) /* convert mA to descriptor units of A for MaxPower */
-+
-+/* "config descriptor buffer" - that is, one config,
-+ ..one interface and 2 endpoints */
-+struct cdb {
-+ struct usb_config_descriptor cfg;
-+ struct usb_interface_descriptor intf;
-+ struct usb_endpoint_descriptor ep1, ep2;
-+} __attribute__ ((packed));
-+
-+
-+/*=======================================================
-+ * Descriptor API
-+ */
-+
-+/* Get the address of the statically allocated desc_t structure
-+ in the usb core driver. Clients can modify this between
-+ the time they call sa1100_usb_open() and sa1100_usb_start()
-+*/
-+struct cdb *sa1100_usb_get_descriptor_ptr(void);
-+
-+#endif /* _SA1100_USB_H */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100usb.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,136 @@
-+/*
-+ * Copyright (C) Compaq Computer Corporation, 1998, 1999
-+ * Copyright (C) Extenex Corporation 2001
-+ *
-+ * usb_ctl.h
-+ *
-+ * PRIVATE interface used to share info among components of the SA-1100 USB
-+ * core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
-+ * should use sa1100_usb.h.
-+ *
-+ */
-+#ifndef SA1100USB_H
-+#define SA1100USB_H
-+
-+struct usbctl;
-+
-+struct sausb_dev {
-+ struct device *dev;
-+ struct usbctl *ctl;
-+ spinlock_t lock;
-+
-+ u32 udccr;
-+
-+ /*
-+ * EP0 write thread.
-+ */
-+ void (*wrint)(struct sausb_dev *);
-+ struct usb_buf *wrbuf;
-+ unsigned char *wrptr;
-+ unsigned int wrlen;
-+
-+ /*
-+ * EP0 statistics.
-+ */
-+ unsigned long ep0_wr_fifo_errs;
-+ unsigned long ep0_wr_bytes;
-+ unsigned long ep0_wr_packets;
-+ unsigned long ep0_rd_fifo_errs;
-+ unsigned long ep0_rd_bytes;
-+ unsigned long ep0_rd_packets;
-+ unsigned long ep0_stall_sent;
-+ unsigned long ep0_early_irqs;
-+
-+ /*
-+ * EP1 .. n
-+ */
-+ struct {
-+ dma_regs_t *dmach;
-+
-+ dma_addr_t bufdma;
-+ unsigned int buflen;
-+ void *pktcpu;
-+ dma_addr_t pktdma;
-+ unsigned int pktlen;
-+ unsigned int pktrem;
-+
-+ void *cb_data;
-+ void (*cb_func)(void *data, int flag, int size);
-+
-+ u32 udccs;
-+ unsigned int maxpktsize;
-+ unsigned int configured;
-+ unsigned int host_halt;
-+ unsigned long fifo_errs;
-+ unsigned long bytes;
-+ unsigned long packets;
-+ } ep[2];
-+};
-+
-+/* receiver */
-+int ep1_recv(void);
-+void udc_ep1_init(struct sausb_dev *);
-+void udc_ep1_halt(struct sausb_dev *, int);
-+void udc_ep1_reset(struct sausb_dev *);
-+void udc_ep1_config(struct sausb_dev *, unsigned int);
-+void udc_ep1_int_hndlr(struct sausb_dev *);
-+
-+/* xmitter */
-+void udc_ep2_init(struct sausb_dev *);
-+void udc_ep2_halt(struct sausb_dev *, int);
-+void udc_ep2_reset(struct sausb_dev *);
-+void udc_ep2_config(struct sausb_dev *, unsigned int);
-+void udc_ep2_int_hndlr(struct sausb_dev *);
-+
-+#define UDC_write(reg, val) do { \
-+ int i = 10000; \
-+ do { \
-+ (reg) = (val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: write %#x to %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while((reg) != (val)); \
-+} while (0)
-+
-+#define UDC_set(reg, val) do { \
-+ int i = 10000; \
-+ do { \
-+ (reg) |= (val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: set %#x of %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while(!((reg) & (val))); \
-+} while (0)
-+
-+#define UDC_clear(reg, val) do { \
-+ int i = 10000; \
-+ do { \
-+ (reg) &= ~(val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while((reg) & (val)); \
-+} while (0)
-+
-+#define UDC_flip(reg, val) do { \
-+ int i = 10000; \
-+ (reg) = (val); \
-+ do { \
-+ (reg) = (val); \
-+ if (i-- <= 0) { \
-+ printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \
-+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
-+ break; \
-+ } \
-+ } while(((reg) & (val))); \
-+} while (0)
-+
-+#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}}
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/strings.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,117 @@
-+/*
-+ * usb/strings.c
-+ *
-+ * Copyright (C) 2002 Russell King.
-+ */
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/errno.h>
-+#include <linux/spinlock.h>
-+#include <linux/string.h>
-+#include <linux/usb_ch9.h>
-+
-+#include "buffer.h"
-+#include "strings.h"
-+
-+struct usb_buf *usbc_string_alloc(int len)
-+{
-+ struct usb_buf *buf;
-+ int tot_len;
-+
-+ tot_len = sizeof(struct usb_descriptor_header) + sizeof(u16) * len;
-+
-+ buf = usbb_alloc(tot_len, GFP_KERNEL);
-+
-+ if (buf) {
-+ struct usb_string_descriptor *desc = usbb_push(buf, tot_len);
-+
-+ desc->bLength = tot_len;
-+ desc->bDescriptorType = USB_DT_STRING;
-+ }
-+ return buf;
-+}
-+
-+void usbc_string_free(struct usb_buf *buf)
-+{
-+ if (buf)
-+ usbb_put(buf);
-+}
-+
-+void usbc_string_from_cstr(struct usb_buf *buf, const char *str)
-+{
-+ struct usb_string_descriptor *desc = usbc_string_desc(buf);
-+ int i, len;
-+
-+ len = strlen(str);
-+ BUG_ON((sizeof(__u16) * len) > desc->bLength - sizeof(struct usb_descriptor_header));
-+
-+ for (i = 0; i < len; i++)
-+ desc->wData[i] = cpu_to_le16(str[i]);
-+}
-+
-+int usbc_string_add(struct usbc_strs *table, struct usb_buf *buf)
-+{
-+ int nr, i;
-+
-+ nr = -ENOSPC;
-+ spin_lock_irq(&table->lock);
-+ for (i = 0; i < NR_STRINGS; i++)
-+ if (table->buf[i] == NULL) {
-+ table->buf[i] = buf;
-+ nr = i;
-+ break;
-+ }
-+ spin_unlock_irq(&table->lock);
-+
-+ return nr;
-+}
-+
-+void usbc_string_del(struct usbc_strs *table, int nr)
-+{
-+ if (nr < NR_STRINGS) {
-+ spin_lock_irq(&table->lock);
-+ table->buf[nr] = NULL;
-+ spin_unlock_irq(&table->lock);
-+ }
-+}
-+
-+struct usb_buf *
-+usbc_string_find(struct usbc_strs *table, unsigned int lang, unsigned int idx)
-+{
-+ struct usb_buf *buf = NULL;
-+
-+ if (idx < NR_STRINGS) {
-+ spin_lock_irq(&table->lock);
-+ buf = usbb_get(table->buf[idx]);
-+ spin_unlock_irq(&table->lock);
-+ }
-+
-+ return buf;
-+}
-+
-+void usbc_string_free_all(struct usbc_strs *table)
-+{
-+ int i;
-+
-+ spin_lock_irq(&table->lock);
-+ for (i = 0; i < NR_STRINGS; i++) {
-+ usbc_string_free(table->buf[i]);
-+ table->buf[i] = NULL;
-+ }
-+ spin_unlock_irq(&table->lock);
-+}
-+
-+void usbc_string_init(struct usbc_strs *table)
-+{
-+ memset(table, 0, sizeof(struct usbc_strs));
-+ spin_lock_init(&table->lock);
-+}
-+
-+EXPORT_SYMBOL(usbc_string_from_cstr);
-+EXPORT_SYMBOL(usbc_string_alloc);
-+EXPORT_SYMBOL(usbc_string_free);
-+EXPORT_SYMBOL(usbc_string_add);
-+EXPORT_SYMBOL(usbc_string_del);
-+EXPORT_SYMBOL(usbc_string_find);
-+EXPORT_SYMBOL(usbc_string_free_all);
-+EXPORT_SYMBOL(usbc_string_init);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_ctl.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,171 @@
-+ /*
-+ * Copyright (C) Compaq Computer Corporation, 1998, 1999
-+ * Copyright (C) Extenex Corporation, 2001
-+ *
-+ * usb_ctl.c
-+ *
-+ * SA1100 USB controller core driver.
-+ *
-+ * This file provides interrupt routing and overall coordination
-+ * of the three endpoints in usb_ep0, usb_receive (1), and usb_send (2).
-+ *
-+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
-+ *
-+ */
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/usb.h>
-+
-+#include "buffer.h"
-+#include "client.h"
-+#include "usbdev.h"
-+#include "sa1100_usb.h"
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Globals
-+//////////////////////////////////////////////////////////////////////////////
-+
-+/* device descriptors */
-+static struct cdb cdb;
-+
-+//////////////////////////////////////////////////////////////////////////////
-+// Private Helpers
-+//////////////////////////////////////////////////////////////////////////////
-+
-+int sa1100_usb_add_string(struct usbctl *ctl, const char *str)
-+{
-+ int nr = 0;
-+
-+ if (str) {
-+ struct usb_buf *buf;
-+ int len;
-+
-+ len = strlen(str);
-+
-+ nr = -ENOMEM;
-+ buf = usbc_string_alloc(len);
-+ if (buf) {
-+ usbc_string_from_cstr(buf, str);
-+ nr = usbc_string_add(&ctl->strings, buf);
-+
-+ if (nr < 0)
-+ usbc_string_free(buf);
-+ }
-+ }
-+
-+ return nr;
-+}
-+
-+EXPORT_SYMBOL(sa1100_usb_add_string);
-+
-+static int sa1100_usb_add_language(struct usbctl *ctl, unsigned int lang)
-+{
-+ struct usb_buf *buf;
-+ int nr = -ENOMEM;
-+
-+ buf = usbc_string_alloc(1);
-+ if (buf) {
-+ usbc_string_desc(buf)->wData[0] = cpu_to_le16(lang); /* American English */
-+ nr = usbc_string_add(&ctl->strings, buf);
-+
-+ if (nr < 0)
-+ usbc_string_free(buf);
-+ }
-+
-+ return nr;
-+}
-+
-+/* setup default descriptors */
-+
-+void initialize_descriptors(struct usbctl *ctl)
-+{
-+ struct usb_client *clnt = ctl->clnt;
-+ int r;
-+
-+ ctl->ep_desc[0] = (struct usb_endpoint_descriptor *)&cdb.ep1;
-+ ctl->ep_desc[1] = (struct usb_endpoint_descriptor *)&cdb.ep2;
-+
-+ cdb.cfg.bLength = USB_DT_CONFIG_SIZE;
-+ cdb.cfg.bDescriptorType = USB_DT_CONFIG;
-+ cdb.cfg.wTotalLength = cpu_to_le16(sizeof(struct cdb));
-+ cdb.cfg.bNumInterfaces = 1;
-+ cdb.cfg.bConfigurationValue = 1;
-+ cdb.cfg.iConfiguration = 0;
-+ cdb.cfg.bmAttributes = USB_CONFIG_ATT_ONE;
-+ cdb.cfg.bMaxPower = USB_POWER( 500 );
-+
-+ cdb.intf.bLength = USB_DT_INTERFACE_SIZE;
-+ cdb.intf.bDescriptorType = USB_DT_INTERFACE;
-+ cdb.intf.bInterfaceNumber = 0; /* unique intf index*/
-+ cdb.intf.bAlternateSetting = 0;
-+ cdb.intf.bNumEndpoints = 2;
-+ cdb.intf.bInterfaceClass = 0xff; /* vendor specific */
-+ cdb.intf.bInterfaceSubClass = 0;
-+ cdb.intf.bInterfaceProtocol = 0;
-+ cdb.intf.iInterface = 0;
-+
-+ cdb.ep1.bLength = USB_DT_INTERFACE_SIZE;
-+ cdb.ep1.bDescriptorType = USB_DT_ENDPOINT;
-+ cdb.ep1.bEndpointAddress = USB_DIR_OUT | 1;
-+ cdb.ep1.bmAttributes = USB_ENDPOINT_XFER_BULK;
-+ cdb.ep1.wMaxPacketSize = cpu_to_le16(64);
-+ cdb.ep1.bInterval = 0;
-+
-+ cdb.ep2.bLength = USB_DT_INTERFACE_SIZE;
-+ cdb.ep2.bDescriptorType = USB_DT_ENDPOINT;
-+ cdb.ep2.bEndpointAddress = USB_DIR_IN | 2;
-+ cdb.ep2.bmAttributes = USB_ENDPOINT_XFER_BULK;
-+ cdb.ep2.wMaxPacketSize = cpu_to_le16(64);
-+ cdb.ep2.bInterval = 0;
-+
-+ ctl->dev_desc->bLength = USB_DT_DEVICE_SIZE;
-+ ctl->dev_desc->bDescriptorType = USB_DT_DEVICE;
-+ ctl->dev_desc->bcdUSB = cpu_to_le16(0x100); /* 1.0 */
-+ ctl->dev_desc->bDeviceClass = clnt->class;
-+ ctl->dev_desc->bDeviceSubClass = clnt->subclass;
-+ ctl->dev_desc->bDeviceProtocol = clnt->protocol;
-+ ctl->dev_desc->bMaxPacketSize0 = 8; /* ep0 max fifo size */
-+ ctl->dev_desc->idVendor = cpu_to_le16(clnt->vendor);
-+ ctl->dev_desc->idProduct = cpu_to_le16(clnt->product);
-+ ctl->dev_desc->bcdDevice = cpu_to_le16(clnt->version);
-+ ctl->dev_desc->bNumConfigurations = 1;
-+
-+ /* set language */
-+ /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */
-+ r = sa1100_usb_add_language(ctl, 0x409);
-+ if (r < 0)
-+ printk(KERN_ERR "usbc: couldn't add language\n");
-+
-+ r = sa1100_usb_add_string(ctl, clnt->manufacturer_str);
-+ if (r < 0)
-+ printk(KERN_ERR "usbc: couldn't add manufacturer string\n");
-+
-+ ctl->dev_desc->iManufacturer = r > 0 ? r : 0;
-+
-+ r = sa1100_usb_add_string(ctl, clnt->product_str);
-+ if (r < 0)
-+ printk(KERN_ERR "usbc: couldn't add product string\n");
-+
-+ ctl->dev_desc->iProduct = r > 0 ? r : 0;
-+
-+ r = sa1100_usb_add_string(ctl, clnt->serial_str);
-+ if (r < 0)
-+ printk(KERN_ERR "usbc: couldn't add serial string\n");
-+
-+ ctl->dev_desc->iSerialNumber = r > 0 ? r : 0;
-+}
-+
-+
-+/*====================================================
-+ * Descriptor Manipulation.
-+ * Use these between open() and start() above to setup
-+ * the descriptors for your device.
-+ */
-+
-+/* get pointer to static default descriptor */
-+struct cdb *sa1100_usb_get_descriptor_ptr(void)
-+{
-+ return &cdb;
-+}
-+
-+EXPORT_SYMBOL(sa1100_usb_get_descriptor_ptr);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,12 @@
-+#
-+# Makefile for the USB client
-+#
-+
-+usbdevcore-objs := buffer.o control.o strings.o usb_ctl.o
-+
-+sa1100-objs := sa1100usb.o usb_recv.o usb_send.o
-+
-+obj-$(CONFIG_SA1100_USB) += usbdevcore.o sa1100.o
-+obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o
-+obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o
-+
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/usb/usbdev.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,91 @@
-+#ifndef USBDEV_H
-+#define USBDEV_H
-+
-+#include "strings.h"
-+
-+struct usb_buf;
-+struct module;
-+struct cdb;
-+struct usb_client;
-+
-+struct usbc_driver {
-+ struct module *owner;
-+ const char *name;
-+ void *priv;
-+ int (*start)(void *);
-+ int (*stop)(void *);
-+
-+ int (*ep0_queue)(void *, struct usb_buf *buf, unsigned int req_len);
-+ void (*set_address)(void *, unsigned int addr);
-+ void (*set_config)(void *, struct cdb *config);
-+
-+ /*
-+ * Get specified endpoint status, as defined in 9.4.5.
-+ */
-+ unsigned int (*ep_get_status)(void *, unsigned int ep);
-+ void (*ep_halt)(void *, unsigned int ep, int halt);
-+
-+ /*
-+ * Client
-+ */
-+ int (*ep_queue)(void *, unsigned int, char *, unsigned int);
-+ void (*ep_reset)(void *, unsigned int);
-+ void (*ep_callback)(void *, unsigned int, void (*)(void *, int, int), void *);
-+ int (*ep_idle)(void *, unsigned int);
-+};
-+
-+struct usbc_endpoint {
-+ struct usb_endpoint_descriptor *desc;
-+};
-+
-+struct usbc_interface {
-+ struct usb_interface_descriptor *desc;
-+ unsigned int nr_ep;
-+ struct usbc_endpoint *ep[0];
-+};
-+
-+struct usbc_config {
-+ struct usb_config_descriptor *desc;
-+ unsigned int nr_interface;
-+ struct usbc_interface *interface[0];
-+};
-+
-+struct usbctl {
-+ struct usb_client *clnt;
-+ const struct usbc_driver *driver;
-+
-+ /* Internal state */
-+ unsigned int address; /* host assigned address */
-+ unsigned int state; /* our device state */
-+ unsigned int sm_state; /* state machine state */
-+
-+ struct usbc_config *config; /* active configuration */
-+ struct usbc_strs strings;
-+
-+ /* Descriptors */
-+ struct usb_device_descriptor *dev_desc; /* device descriptor */
-+ struct usb_buf *dev_desc_buf; /* device descriptor buffer */
-+
-+
-+ int nr_ep;
-+ struct usb_endpoint_descriptor *ep_desc[2];
-+};
-+
-+/*
-+ * Function Prototypes
-+ */
-+
-+#define RET_ERROR (-1)
-+#define RET_NOACTION (0)
-+#define RET_QUEUED (1)
-+#define RET_ACK (2)
-+#define RET_REQERROR (3)
-+
-+int usbctl_parse_request(struct usbctl *ctl, struct usb_ctrlrequest *req);
-+
-+int usbctl_reset(struct usbctl *ctl);
-+void usbctl_suspend(struct usbctl *ctl);
-+void usbctl_resume(struct usbctl *ctl);
-+
-+#endif
-+
---- linux-2.6.5/arch/arm/mach-sa1100/pm.c~heh 2004-04-03 22:36:27.000000000 -0500
-+++ linux-2.6.5/arch/arm/mach-sa1100/pm.c 2004-04-30 20:57:36.000000000 -0400
-@@ -150,6 +150,7 @@
- */
- static int sa11x0_pm_prepare(u32 state)
- {
-+ nmi_watchdog_disable();
- return 0;
- }
-
-@@ -158,6 +159,7 @@
- */
- static int sa11x0_pm_finish(u32 state)
- {
-+ nmi_watchdog_enable();
- return 0;
- }
-
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/arch/arm/mach-sa1100/nmi-oopser.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,104 @@
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/gfp.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+
-+#include <asm/ptrace.h>
-+#include <asm/domain.h>
-+#include <asm/hardware.h>
-+
-+static void *nmi_stack;
-+
-+asm(" \n\
-+nmi_start: \n\
-+ mrs r8, spsr \n\
-+ ldr r9, .Lstack \n\
-+ ldr sp, [r9] \n\
-+ sub sp, sp, #18 * 4 \n\
-+ str r8, [sp, #16 * 4] \n\
-+ str lr, [sp, #15 * 4] \n\
-+ stmia sp, {r0 - r7} \n\
-+ add r0, sp, #8 * 4 \n\
-+ mrs r2, cpsr \n\
-+ bic r1, r2, #0x1f \n\
-+ orr r1, r1, #0x13 \n\
-+ msr cpsr_c, r1 \n\
-+ mov r0, r0 \n\
-+ stmia r0, {r8 - lr} \n\
-+ mov r0, r0 \n\
-+ msr cpsr_c, r2 \n\
-+ mov r0, r0 \n\
-+ mov r0, sp \n\
-+ mov lr, pc \n\
-+ ldr pc, .Lfn \n\
-+ ldmia sp, {r0 - r7} \n\
-+ ldr r8, [sp, #16 * 4] \n\
-+ ldr lr, [sp, #15 * 4] \n\
-+ add sp, sp, #18 * 4 \n\
-+ msr spsr, r8 \n\
-+ movs pc, lr \n\
-+ \n\
-+.Lstack: .long nmi_stack \n\
-+.Lfn: .long nmi_fn \n\
-+nmi_end:");
-+
-+extern unsigned char nmi_start, nmi_end;
-+
-+static void __attribute__((unused)) nmi_fn(struct pt_regs *regs)
-+{
-+ struct thread_info *thread;
-+ unsigned long osmr0, osmr1, oscr, ossr, icmr, icip;
-+
-+ oscr = OSCR;
-+ osmr0 = OSMR0;
-+ osmr1 = OSMR1;
-+ ossr = OSSR;
-+ icmr = ICMR;
-+ icip = ICIP;
-+
-+ OSSR = OSSR_M1;
-+ ICMR &= ~IC_OST1;
-+
-+ thread = (struct thread_info *)(regs->ARM_sp & ~8191);
-+
-+ bust_spinlocks(1);
-+ printk("OSMR0:%08lx OSMR1:%08lx OSCR:%08lx OSSR:%08lx ICMR:%08lx ICIP:%08lx\n",
-+ osmr0, osmr1, oscr, ossr, icmr, icip);
-+ nmi_watchdog(thread, regs);
-+ bust_spinlocks(0);
-+
-+ OSSR = OSSR_M1;
-+ OSMR1 = OSSR + 36864000;
-+ ICMR |= IC_OST1;
-+}
-+
-+static int nmi_init(void)
-+{
-+ unsigned char *vec_base = (unsigned char *)vectors_base();
-+return 0;
-+ nmi_stack = (void *)__get_free_page(GFP_KERNEL);
-+ if (!nmi_stack)
-+ return -ENOMEM;
-+
-+ nmi_stack += PAGE_SIZE;
-+
-+ modify_domain(DOMAIN_USER, DOMAIN_MANAGER);
-+ memcpy(vec_base + 0x1c, &nmi_start, &nmi_end - &nmi_start);
-+ modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
-+
-+ /*
-+ * Ensure timer 1 is set to FIQ, and enabled.
-+ */
-+ OSMR1 = OSCR - 1;
-+ OSSR = OSSR_M1;
-+ OIER |= OIER_E1;
-+ ICLR |= IC_OST1;
-+ ICMR |= IC_OST1;
-+
-+ return 0;
-+}
-+
-+__initcall(nmi_init);
---- linux-2.6.5/drivers/media/Kconfig~heh 2004-04-03 22:36:51.000000000 -0500
-+++ linux-2.6.5/drivers/media/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -32,6 +32,8 @@
-
- source "drivers/media/common/Kconfig"
-
-+source "drivers/media/mmc/Kconfig"
-+
- config VIDEO_TUNER
- tristate
- default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_MXB=y || VIDEO_CX88=y
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,52 @@
-+#
-+# MMC subsystem configuration
-+#
-+
-+menu "MMC/SD Card support"
-+
-+config MMC
-+ tristate "MMC support"
-+ help
-+ MMC is the "multi-media card" bus protocol.
-+
-+ If you want MMC support, you should say Y here and also
-+ to the specific driver for your MMC interface.
-+
-+config MMC_DEBUG
-+ bool "MMC debugging"
-+ depends on MMC != n
-+ help
-+ This is an option for use by developers; most people should
-+ say N here. This enables MMC core and driver debugging.
-+
-+config MMC_BLOCK
-+ tristate "MMC block device driver"
-+ depends on MMC
-+ default y
-+ help
-+ Say Y here to enable the MMC block device driver support.
-+ This provides a block device driver, which you can use to
-+ mount the filesystem. Almost everyone wishing MMC support
-+ should say Y or M here.
-+
-+config MMC_ARMMMCI
-+ tristate "ARM AMBA Multimedia Card Interface support"
-+ depends on ARM_AMBA && MMC
-+ help
-+ This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
-+ Interface (PL180 and PL181) support. If you have an ARM(R)
-+ platform with a Multimedia Card slot, say Y or M here.
-+
-+ If unsure, say N.
-+
-+config MMC_PXA
-+ tristate "Intel PXA255 Multimedia Card Interface support"
-+ depends on ARCH_PXA && MMC
-+ help
-+ This selects the Intel(R) PXA(R) Multimedia card Interface.
-+ If you have a PXA(R) platform with a Multimedia Card slot,
-+ say Y or M here.
-+
-+ If unsure, say N.
-+
-+endmenu
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmc_queue.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,171 @@
-+/*
-+ * linux/drivers/media/mmc/mmc_queue.c
-+ *
-+ * Copyright (C) 2003 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+#include <linux/module.h>
-+#include <linux/blkdev.h>
-+
-+#include <linux/mmc/card.h>
-+#include <linux/mmc/host.h>
-+#include "mmc_queue.h"
-+
-+/*
-+ * Prepare a MMC request. Essentially, this means passing the
-+ * preparation off to the media driver. The media driver will
-+ * create a mmc_io_request in req->special.
-+ */
-+static int mmc_prep_request(struct request_queue *q, struct request *req)
-+{
-+ struct mmc_queue *mq = q->queuedata;
-+ int ret = BLKPREP_KILL;
-+
-+ if (req->flags & REQ_SPECIAL) {
-+ /*
-+ * Special commands already have the command
-+ * blocks already setup in req->special.
-+ */
-+ BUG_ON(!req->special);
-+
-+ ret = BLKPREP_OK;
-+ } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-+ /*
-+ * Block I/O requests need translating according
-+ * to the protocol.
-+ */
-+ ret = mq->prep_fn(mq, req);
-+ } else {
-+ /*
-+ * Everything else is invalid.
-+ */
-+ blk_dump_rq_flags(req, "MMC bad request");
-+ }
-+
-+ if (ret == BLKPREP_OK)
-+ req->flags |= REQ_DONTPREP;
-+
-+ return ret;
-+}
-+
-+static int mmc_queue_thread(void *d)
-+{
-+ struct mmc_queue *mq = d;
-+ struct request_queue *q = mq->queue;
-+ DECLARE_WAITQUEUE(wait, current);
-+ int ret;
-+
-+ /*
-+ * Set iothread to ensure that we aren't put to sleep by
-+ * the process freezing. We handle suspension ourselves.
-+ */
-+ current->flags |= PF_MEMALLOC|PF_IOTHREAD;
-+
-+ daemonize("mmcqd");
-+
-+ spin_lock_irq(&current->sighand->siglock);
-+ sigfillset(&current->blocked);
-+ recalc_sigpending();
-+ spin_unlock_irq(&current->sighand->siglock);
-+
-+ mq->thread = current;
-+ complete(&mq->thread_complete);
-+
-+ add_wait_queue(&mq->thread_wq, &wait);
-+ spin_lock_irq(q->queue_lock);
-+ do {
-+ struct request *req = NULL;
-+
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (!blk_queue_plugged(q))
-+ mq->req = req = elv_next_request(q);
-+ spin_unlock(q->queue_lock);
-+
-+ if (!req) {
-+ if (!mq->thread)
-+ break;
-+ schedule();
-+ continue;
-+ }
-+ set_current_state(TASK_RUNNING);
-+
-+ ret = mq->issue_fn(mq, req);
-+
-+ spin_lock_irq(q->queue_lock);
-+ end_request(req, ret);
-+ } while (1);
-+ remove_wait_queue(&mq->thread_wq, &wait);
-+
-+ complete_and_exit(&mq->thread_complete, 0);
-+ return 0;
-+}
-+
-+/*
-+ * Generic MMC request handler. This is called for any queue on a
-+ * particular host. When the host is not busy, we look for a request
-+ * on any queue on this host, and attempt to issue it. This may
-+ * not be the queue we were asked to process.
-+ */
-+static void mmc_request(request_queue_t *q)
-+{
-+ struct mmc_queue *mq = q->queuedata;
-+
-+ if (!mq->req && !blk_queue_plugged(q))
-+ wake_up(&mq->thread_wq);
-+}
-+
-+/**
-+ * mmc_init_queue - initialise a queue structure.
-+ * @mq: mmc queue
-+ * @card: mmc card to attach this queue
-+ * @lock: queue lock
-+ *
-+ * Initialise a MMC card request queue.
-+ */
-+int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
-+{
-+ u64 limit = BLK_BOUNCE_HIGH;
-+ int ret;
-+
-+ if (card->host->dev->dma_mask)
-+ limit = *card->host->dev->dma_mask;
-+
-+ mq->card = card;
-+ mq->queue = blk_init_queue(mmc_request, lock);
-+ blk_queue_prep_rq(mq->queue, mmc_prep_request);
-+ blk_queue_bounce_limit(mq->queue, limit);
-+
-+ mq->queue->queuedata = mq;
-+ mq->req = NULL;
-+
-+ init_completion(&mq->thread_complete);
-+ init_waitqueue_head(&mq->thread_wq);
-+
-+ ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
-+ if (ret < 0) {
-+ blk_cleanup_queue(mq->queue);
-+ } else {
-+ wait_for_completion(&mq->thread_complete);
-+ init_completion(&mq->thread_complete);
-+ }
-+
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(mmc_init_queue);
-+
-+void mmc_cleanup_queue(struct mmc_queue *mq)
-+{
-+ mq->thread = NULL;
-+ wake_up(&mq->thread_wq);
-+ wait_for_completion(&mq->thread_complete);
-+ blk_cleanup_queue(mq->queue);
-+
-+ mq->card = NULL;
-+}
-+
-+EXPORT_SYMBOL(mmc_cleanup_queue);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/pxamci.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,587 @@
-+/*
-+ * linux/drivers/media/mmc/pxa.c - PXA MMCI driver
-+ *
-+ * Copyright (C) 2003 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This hardware is really sick. No way to clear interrupts. Have
-+ * to turn off the clock whenever we touch the device. Yuck!
-+ *
-+ * 1 and 3 byte data transfers not supported
-+ * max block length up to 1023
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+#include <linux/interrupt.h>
-+#include <linux/blkdev.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/protocol.h>
-+
-+#include <asm/dma.h>
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/sizes.h>
-+
-+#include "pxamci.h"
-+
-+#ifdef CONFIG_MMC_DEBUG
-+#define DBG(x...) printk(KERN_DEBUG x)
-+#else
-+#define DBG(x...) do { } while (0)
-+#endif
-+
-+struct pxamci_host {
-+ struct mmc_host mmc;
-+ spinlock_t lock;
-+ struct resource *res;
-+ void *base;
-+ int irq;
-+ int dma;
-+ unsigned int clkrt;
-+ unsigned int cmdat;
-+ unsigned int imask;
-+ unsigned int power_mode;
-+
-+ struct mmc_request *req;
-+ struct mmc_command *cmd;
-+ struct mmc_data *data;
-+
-+ dma_addr_t sg_dma;
-+ struct pxa_dma_desc *sg_cpu;
-+
-+ dma_addr_t dma_buf;
-+ unsigned int dma_size;
-+ unsigned int dma_dir;
-+};
-+
-+#define to_pxamci_host(x) container_of(x, struct pxamci_host, mmc)
-+
-+/*
-+ * The base MMC clock rate
-+ */
-+#define CLOCKRATE 20000000
-+
-+static inline unsigned int ns_to_clocks(unsigned int ns)
-+{
-+ return (ns * (CLOCKRATE / 1000000) + 999) / 1000;
-+}
-+
-+static void pxamci_stop_clock(struct pxamci_host *host)
-+{
-+ if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
-+ unsigned long flags;
-+ unsigned int v;
-+
-+ writel(STOP_CLOCK, host->base + MMC_STRPCL);
-+
-+ /*
-+ * Wait for the "clock has stopped" interrupt.
-+ * We need to unmask the interrupt to receive
-+ * the notification. Sigh.
-+ */
-+ spin_lock_irqsave(&host->lock, flags);
-+ writel(host->imask & ~CLK_IS_OFF, host->base + MMC_I_MASK);
-+ do {
-+ v = readl(host->base + MMC_I_REG);
-+ } while (!(v & CLK_IS_OFF));
-+ writel(host->imask, host->base + MMC_I_MASK);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ }
-+}
-+
-+static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ host->imask &= ~mask;
-+ writel(host->imask, host->base + MMC_I_MASK);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ host->imask |= mask;
-+ writel(host->imask, host->base + MMC_I_MASK);
-+ spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
-+{
-+ unsigned int nob = data->blocks;
-+ unsigned int timeout, size;
-+ dma_addr_t dma;
-+ u32 dcmd;
-+ int i;
-+
-+ host->data = data;
-+
-+ if (data->flags & MMC_DATA_STREAM)
-+ nob = 0xffff;
-+
-+ writel(nob, host->base + MMC_NOB);
-+ writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
-+
-+ timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks;
-+ writel((timeout + 255) / 256, host->base + MMC_RDTO);
-+
-+ if (data->flags & MMC_DATA_READ) {
-+ host->dma_dir = DMA_FROM_DEVICE;
-+ dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
-+ DRCMRTXMMC = 0;
-+ DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
-+ } else {
-+ host->dma_dir = DMA_TO_DEVICE;
-+ dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
-+ DRCMRRXMMC = 0;
-+ DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
-+ }
-+
-+ dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
-+
-+ host->dma_size = data->blocks << data->blksz_bits;
-+ host->dma_buf = dma_map_single(host->mmc.dev, data->rq->buffer,
-+ host->dma_size, host->dma_dir);
-+
-+ for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) {
-+ u32 len = size;
-+
-+ if (len > DCMD_LENGTH)
-+ len = 0x1000;
-+
-+ if (data->flags & MMC_DATA_READ) {
-+ host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
-+ host->sg_cpu[i].dtadr = dma;
-+ } else {
-+ host->sg_cpu[i].dsadr = dma;
-+ host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
-+ }
-+ host->sg_cpu[i].dcmd = dcmd | len;
-+
-+ dma += len;
-+ size -= len;
-+
-+ if (size) {
-+ host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
-+ sizeof(struct pxa_dma_desc);
-+ } else {
-+ host->sg_cpu[i].ddadr = DDADR_STOP;
-+ }
-+ }
-+ wmb();
-+
-+ DDADR(host->dma) = host->sg_dma;
-+ DCSR(host->dma) = DCSR_RUN;
-+}
-+
-+static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-+{
-+ WARN_ON(host->cmd != NULL);
-+ host->cmd = cmd;
-+
-+ if (cmd->flags & MMC_RSP_BUSY)
-+ cmdat |= CMDAT_BUSY;
-+
-+ switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) {
-+ case MMC_RSP_SHORT | MMC_RSP_CRC:
-+ cmdat |= CMDAT_RESP_SHORT;
-+ break;
-+ case MMC_RSP_SHORT:
-+ cmdat |= CMDAT_RESP_R3;
-+ break;
-+ case MMC_RSP_LONG | MMC_RSP_CRC:
-+ cmdat |= CMDAT_RESP_R2;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ writel(cmd->opcode, host->base + MMC_CMD);
-+ writel(cmd->arg >> 16, host->base + MMC_ARGH);
-+ writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
-+ writel(cmdat, host->base + MMC_CMDAT);
-+ writel(host->clkrt, host->base + MMC_CLKRT);
-+
-+ writel(START_CLOCK, host->base + MMC_STRPCL);
-+
-+ pxamci_enable_irq(host, END_CMD_RES);
-+}
-+
-+static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *req)
-+{
-+ DBG("PXAMCI: request done\n");
-+ host->req = NULL;
-+ host->cmd = NULL;
-+ host->data = NULL;
-+ mmc_request_done(&host->mmc, req);
-+}
-+
-+static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
-+{
-+ struct mmc_command *cmd = host->cmd;
-+ int i;
-+ u32 v;
-+
-+ if (!cmd)
-+ return 0;
-+
-+ host->cmd = NULL;
-+
-+ /*
-+ * Did I mention this is Sick. We always need to
-+ * discard the upper 8 bits of the first 16-bit word.
-+ */
-+ v = readl(host->base + MMC_RES) & 0xffff;
-+ for (i = 0; i < 4; i++) {
-+ u32 w1 = readl(host->base + MMC_RES) & 0xffff;
-+ u32 w2 = readl(host->base + MMC_RES) & 0xffff;
-+ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
-+ v = w2;
-+ }
-+
-+ if (stat & STAT_TIME_OUT_RESPONSE) {
-+ cmd->error = MMC_ERR_TIMEOUT;
-+ } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
-+ cmd->error = MMC_ERR_BADCRC;
-+ }
-+
-+ pxamci_disable_irq(host, END_CMD_RES);
-+ if (host->data && cmd->error == MMC_ERR_NONE) {
-+ pxamci_enable_irq(host, DATA_TRAN_DONE);
-+ } else {
-+ pxamci_finish_request(host, host->req);
-+ }
-+
-+ return 1;
-+}
-+
-+static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
-+{
-+ struct mmc_data *data = host->data;
-+
-+ if (!data)
-+ return 0;
-+
-+ DCSR(host->dma) = 0;
-+ dma_unmap_single(host->mmc.dev, host->dma_buf, host->dma_size,
-+ host->dma_dir);
-+
-+ if (stat & STAT_READ_TIME_OUT)
-+ data->error = MMC_ERR_TIMEOUT;
-+ else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
-+ data->error = MMC_ERR_BADCRC;
-+
-+ data->bytes_xfered = (data->blocks - readl(host->base + MMC_NOB))
-+ << data->blksz_bits;
-+
-+ pxamci_disable_irq(host, DATA_TRAN_DONE);
-+
-+ host->data = NULL;
-+ if (host->req->stop && data->error == MMC_ERR_NONE) {
-+ pxamci_stop_clock(host);
-+ pxamci_start_cmd(host, host->req->stop, 0);
-+ } else {
-+ pxamci_finish_request(host, host->req);
-+ }
-+
-+ return 1;
-+}
-+
-+static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
-+{
-+ struct pxamci_host *host = devid;
-+ unsigned int ireg;
-+ int handled = 0;
-+
-+ ireg = readl(host->base + MMC_I_REG);
-+
-+ DBG("PXAMCI: irq %08x\n", ireg);
-+
-+ if (ireg) {
-+ unsigned stat = readl(host->base + MMC_STAT);
-+
-+ DBG("PXAMCI: stat %08x\n", stat);
-+
-+ if (ireg & END_CMD_RES)
-+ handled |= pxamci_cmd_done(host, stat);
-+ if (ireg & DATA_TRAN_DONE)
-+ handled |= pxamci_data_done(host, stat);
-+ }
-+
-+ return IRQ_RETVAL(handled);
-+}
-+
-+static void pxamci_request(struct mmc_host *mmc, struct mmc_request *req)
-+{
-+ struct pxamci_host *host = to_pxamci_host(mmc);
-+ unsigned int cmdat;
-+
-+ WARN_ON(host->req != NULL);
-+
-+ host->req = req;
-+
-+ pxamci_stop_clock(host);
-+
-+ cmdat = host->cmdat;
-+ host->cmdat &= ~CMDAT_INIT;
-+
-+ if (req->data) {
-+ pxamci_setup_data(host, req->data);
-+
-+ cmdat &= ~CMDAT_BUSY;
-+ cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
-+ if (req->data->flags & MMC_DATA_WRITE)
-+ cmdat |= CMDAT_WRITE;
-+
-+ if (req->data->flags & MMC_DATA_STREAM)
-+ cmdat |= CMDAT_STREAM;
-+ }
-+
-+ pxamci_start_cmd(host, req->cmd, cmdat);
-+}
-+
-+static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-+{
-+ struct pxamci_host *host = to_pxamci_host(mmc);
-+
-+ DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n",
-+ ios->clock, ios->power_mode, ios->vdd / 100,
-+ ios->vdd % 100);
-+
-+ if (ios->clock) {
-+ unsigned int clk = CLOCKRATE / ios->clock;
-+ if (CLOCKRATE / clk > ios->clock)
-+ clk <<= 1;
-+ host->clkrt = fls(clk) - 1;
-+
-+ /*
-+ * we write clkrt on the next command
-+ */
-+ } else if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
-+ /*
-+ * Ensure that the clock is off.
-+ */
-+ writel(STOP_CLOCK, host->base + MMC_STRPCL);
-+ }
-+
-+ if (host->power_mode != ios->power_mode) {
-+ host->power_mode = ios->power_mode;
-+
-+ /*
-+ * power control? none on the lubbock.
-+ */
-+
-+ if (ios->power_mode == MMC_POWER_ON)
-+ host->cmdat |= CMDAT_INIT;
-+ }
-+
-+ DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n",
-+ host->clkrt, host->cmdat);
-+}
-+
-+static struct mmc_host_ops pxamci_ops = {
-+ .request = pxamci_request,
-+ .set_ios = pxamci_set_ios,
-+};
-+
-+static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
-+{
-+ int i;
-+
-+ for (i = 0; i < dev->num_resources; i++)
-+ if (dev->resource[i].flags == mask && nr-- == 0)
-+ return &dev->resource[i];
-+ return NULL;
-+}
-+
-+static int platform_device_irq(struct platform_device *dev, int nr)
-+{
-+ int i;
-+
-+ for (i = 0; i < dev->num_resources; i++)
-+ if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
-+ return dev->resource[i].start;
-+ return NO_IRQ;
-+}
-+
-+static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
-+{
-+ printk(KERN_ERR "DMA%d: IRQ???\n", dma);
-+ DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
-+}
-+
-+static int pxamci_probe(struct device *dev)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct pxamci_host *host;
-+ struct resource *r;
-+ int ret, irq;
-+
-+ r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
-+ irq = platform_device_irq(pdev, 0);
-+ if (!r || irq == NO_IRQ)
-+ return -ENXIO;
-+
-+ r = request_mem_region(r->start, SZ_4K, "PXAMCI");
-+ if (!r)
-+ return -EBUSY;
-+
-+ host = kmalloc(sizeof(struct pxamci_host), GFP_KERNEL);
-+ if (!host) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ memset(host, 0, sizeof(struct pxamci_host));
-+ host->dma = -1;
-+
-+ host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
-+ if (!host->sg_cpu) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ ret = mmc_init_host(&host->mmc);
-+ if (ret)
-+ goto out;
-+
-+ spin_lock_init(&host->lock);
-+ host->res = r;
-+ host->irq = irq;
-+ host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
-+ END_CMD_RES|PRG_DONE|DATA_TRAN_DONE;
-+ host->mmc.dev = dev;
-+ host->mmc.ops = &pxamci_ops;
-+ host->mmc.f_min = 312500;
-+ host->mmc.f_max = 20000000;
-+ host->mmc.ocr_avail = MMC_VDD_32_33;
-+
-+ host->base = ioremap(r->start, SZ_4K);
-+ if (!host->base) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ /*
-+ * Ensure that the host controller is shut down, and setup
-+ * with our defaults.
-+ */
-+ pxamci_stop_clock(host);
-+ writel(0, host->base + MMC_SPI);
-+ writel(64, host->base + MMC_RESTO);
-+
-+#ifdef CONFIG_PREEMPT
-+#error Not Preempt-safe
-+#endif
-+ pxa_gpio_mode(GPIO6_MMCCLK_MD);
-+ pxa_gpio_mode(GPIO8_MMCCS0_MD);
-+ CKEN |= CKEN12_MMC;
-+
-+ host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host);
-+ if (host->dma < 0)
-+ goto out;
-+
-+ ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host);
-+ if (ret)
-+ goto out;
-+
-+ dev_set_drvdata(dev, host);
-+
-+ mmc_add_host(&host->mmc);
-+
-+ return 0;
-+
-+ out:
-+ if (host) {
-+ if (host->dma >= 0)
-+ pxa_free_dma(host->dma);
-+ if (host->base)
-+ iounmap(host->base);
-+ if (host->sg_cpu)
-+ dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-+ kfree(host);
-+ }
-+ release_resource(r);
-+ return ret;
-+}
-+
-+static int pxamci_remove(struct device *dev)
-+{
-+ struct pxamci_host *host = dev_get_drvdata(dev);
-+
-+ dev_set_drvdata(dev, NULL);
-+
-+ if (host) {
-+ mmc_remove_host(&host->mmc);
-+
-+ pxamci_stop_clock(host);
-+ writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
-+ END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
-+ host->base + MMC_I_MASK);
-+
-+ free_irq(host->irq, host);
-+ pxa_free_dma(host->dma);
-+ iounmap(host->base);
-+ dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-+
-+ release_resource(host->res);
-+
-+ kfree(host);
-+ }
-+ return 0;
-+}
-+
-+static int pxamci_suspend(struct device *dev, u32 state, u32 level)
-+{
-+ struct pxamci_host *host = dev_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host && level == SUSPEND_DISABLE)
-+ ret = mmc_suspend_host(&host->mmc, state);
-+ return ret;
-+}
-+
-+static int pxamci_resume(struct device *dev, u32 level)
-+{
-+ struct pxamci_host *host = dev_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host && level == RESUME_ENABLE)
-+ ret = mmc_resume_host(&host->mmc);
-+ return ret;
-+}
-+
-+static struct device_driver pxamci_driver = {
-+ .name = "pxamci",
-+ .bus = &platform_bus_type,
-+ .probe = pxamci_probe,
-+ .remove = pxamci_remove,
-+ .suspend = pxamci_suspend,
-+ .resume = pxamci_resume,
-+};
-+
-+static int __init pxamci_init(void)
-+{
-+ return driver_register(&pxamci_driver);
-+}
-+
-+static void __exit pxamci_exit(void)
-+{
-+ driver_unregister(&pxamci_driver);
-+}
-+
-+module_init(pxamci_init);
-+module_exit(pxamci_exit);
-+
-+MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmc.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,15 @@
-+/*
-+ * linux/drivers/media/mmc/mmc.h
-+ *
-+ * Copyright (C) 2003 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#ifndef _MMC_H
-+/* core-internal functions */
-+void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
-+int mmc_register_card(struct mmc_card *card);
-+void mmc_remove_card(struct mmc_card *card);
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmc_sysfs.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,231 @@
-+/*
-+ * linux/drivers/media/mmc/mmc_sysfs.c
-+ *
-+ * Copyright (C) 2003 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * MMC sysfs/driver model support.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+
-+#include <linux/mmc/card.h>
-+#include <linux/mmc/host.h>
-+
-+#include "mmc.h"
-+
-+#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
-+#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
-+
-+static void mmc_release_card(struct device *dev)
-+{
-+ struct mmc_card *card = dev_to_mmc_card(dev);
-+
-+ kfree(card);
-+}
-+
-+/*
-+ * This currently matches any MMC driver to any MMC card - drivers
-+ * themselves make the decision whether to drive this card in their
-+ * probe method.
-+ */
-+static int mmc_bus_match(struct device *dev, struct device_driver *drv)
-+{
-+ return 1;
-+}
-+
-+static int
-+mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
-+ int buf_size)
-+{
-+ struct mmc_card *card = dev_to_mmc_card(dev);
-+ char ccc[13];
-+ int i = 0;
-+
-+#define add_env(fmt,val) \
-+ ({ \
-+ int len, ret = -ENOMEM; \
-+ if (i < num_envp) { \
-+ envp[i++] = buf; \
-+ len = snprintf(buf, buf_size, fmt, val) + 1; \
-+ buf_size -= len; \
-+ buf += len; \
-+ if (buf_size >= 0) \
-+ ret = 0; \
-+ } \
-+ ret; \
-+ })
-+
-+ for (i = 0; i < 12; i++)
-+ ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
-+ ccc[12] = '\0';
-+
-+ i = 0;
-+ add_env("MMC_CCC=%s", ccc);
-+ add_env("MMC_MANFID=%03x", card->cid.manfid);
-+ add_env("MMC_SLOT_NAME=%s", card->dev.bus_id);
-+
-+ return 0;
-+}
-+
-+static int mmc_bus_suspend(struct device *dev, u32 state)
-+{
-+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
-+ struct mmc_card *card = dev_to_mmc_card(dev);
-+ int ret = 0;
-+
-+ if (dev->driver && drv->suspend)
-+ ret = drv->suspend(card, state);
-+ return ret;
-+}
-+
-+static int mmc_bus_resume(struct device *dev)
-+{
-+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
-+ struct mmc_card *card = dev_to_mmc_card(dev);
-+ int ret = 0;
-+
-+ if (dev->driver && drv->resume)
-+ ret = drv->resume(card);
-+ return ret;
-+}
-+
-+static struct bus_type mmc_bus_type = {
-+ .name = "mmc",
-+ .match = mmc_bus_match,
-+ .hotplug = mmc_bus_hotplug,
-+ .suspend = mmc_bus_suspend,
-+ .resume = mmc_bus_resume,
-+};
-+
-+
-+static int mmc_drv_probe(struct device *dev)
-+{
-+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
-+ struct mmc_card *card = dev_to_mmc_card(dev);
-+
-+ return drv->probe(card);
-+}
-+
-+static int mmc_drv_remove(struct device *dev)
-+{
-+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
-+ struct mmc_card *card = dev_to_mmc_card(dev);
-+
-+ drv->remove(card);
-+
-+ return 0;
-+}
-+
-+
-+/**
-+ * mmc_register_driver - register a media driver
-+ * @drv: MMC media driver
-+ */
-+int mmc_register_driver(struct mmc_driver *drv)
-+{
-+ drv->drv.bus = &mmc_bus_type;
-+ drv->drv.probe = mmc_drv_probe;
-+ drv->drv.remove = mmc_drv_remove;
-+ return driver_register(&drv->drv);
-+}
-+
-+EXPORT_SYMBOL(mmc_register_driver);
-+
-+/**
-+ * mmc_unregister_driver - unregister a media driver
-+ * @drv: MMC media driver
-+ */
-+void mmc_unregister_driver(struct mmc_driver *drv)
-+{
-+ drv->drv.bus = &mmc_bus_type;
-+ driver_unregister(&drv->drv);
-+}
-+
-+EXPORT_SYMBOL(mmc_unregister_driver);
-+
-+
-+#define MMC_ATTR(name, fmt, args...) \
-+static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \
-+{ \
-+ struct mmc_card *card = dev_to_mmc_card(dev); \
-+ return sprintf(buf, fmt, args); \
-+} \
-+static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)
-+
-+MMC_ATTR(date, "%02d/%04d\n", card->cid.month, 1997 + card->cid.year);
-+MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
-+MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
-+MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid);
-+MMC_ATTR(serial, "0x%06x\n", card->cid.serial);
-+MMC_ATTR(name, "%s\n", card->cid.prod_name);
-+
-+static struct device_attribute *mmc_dev_attributes[] = {
-+ &dev_attr_date,
-+ &dev_attr_fwrev,
-+ &dev_attr_hwrev,
-+ &dev_attr_manfid,
-+ &dev_attr_serial,
-+ &dev_attr_name,
-+};
-+
-+/*
-+ * Internal function. Initialise a MMC card structure.
-+ */
-+void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
-+{
-+ memset(card, 0, sizeof(struct mmc_card));
-+ card->host = host;
-+ device_initialize(&card->dev);
-+ card->dev.parent = card->host->dev;
-+ card->dev.bus = &mmc_bus_type;
-+ card->dev.release = mmc_release_card;
-+}
-+
-+/*
-+ * Internal function. Register a new MMC card with the driver model.
-+ */
-+int mmc_register_card(struct mmc_card *card)
-+{
-+ int ret, i;
-+
-+ snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
-+ "mmc%02x:%04x", card->host->host_num, card->rca);
-+
-+ ret = device_add(&card->dev);
-+ if (ret == 0)
-+ for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++)
-+ device_create_file(&card->dev, mmc_dev_attributes[i]);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Internal function. Unregister a new MMC card with the
-+ * driver model, and (eventually) free it.
-+ */
-+void mmc_remove_card(struct mmc_card *card)
-+{
-+ if (mmc_card_present(card))
-+ device_del(&card->dev);
-+
-+ put_device(&card->dev);
-+}
-+
-+
-+static int __init mmc_init(void)
-+{
-+ return bus_register(&mmc_bus_type);
-+}
-+
-+static void __exit mmc_exit(void)
-+{
-+ bus_unregister(&mmc_bus_type);
-+}
-+
-+module_init(mmc_init);
-+module_exit(mmc_exit);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmci.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,445 @@
-+/*
-+ * linux/drivers/media/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
-+ *
-+ * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/init.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+#include <linux/interrupt.h>
-+#include <linux/blkdev.h>
-+#include <linux/delay.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/protocol.h>
-+
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/hardware/amba.h>
-+
-+#include "mmci.h"
-+
-+#define DRIVER_NAME "mmci-pl18x"
-+
-+#ifdef CONFIG_MMC_DEBUG
-+#define DBG(x...) printk(KERN_DEBUG x)
-+#else
-+#define DBG(x...) do { } while (0)
-+#endif
-+
-+static int fmax = 515633;
-+
-+static void
-+mmci_request_end(struct mmci_host *host, struct mmc_request *req)
-+{
-+ writel(0, host->base + MMCICOMMAND);
-+ host->req = NULL;
-+ host->cmd = NULL;
-+ host->data = NULL;
-+
-+ if (req->data)
-+ req->data->bytes_xfered = host->data_xfered;
-+
-+ mmc_request_done(&host->mmc, req);
-+}
-+
-+static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
-+{
-+ unsigned int datactrl;
-+
-+ DBG("MMCI: data: blksz %04x blks %04x flags %08x\n",
-+ 1 << data->blksz_bits, data->blocks, data->flags);
-+
-+ datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
-+
-+ if (data->flags & MMC_DATA_READ)
-+ datactrl |= MCI_DPSM_DIRECTION;
-+
-+ host->data = data;
-+ host->buffer = data->rq->buffer;
-+ host->size = data->blocks << data->blksz_bits;
-+ host->data_xfered = 0;
-+
-+ writel(0x800000, host->base + MMCIDATATIMER);
-+ writel(host->size, host->base + MMCIDATALENGTH);
-+ writel(datactrl, host->base + MMCIDATACTRL);
-+}
-+
-+static void
-+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
-+{
-+ DBG("MMCI: cmd: op %02x arg %08x flags %08x\n",
-+ cmd->opcode, cmd->arg, cmd->flags);
-+
-+ if (readl(host->base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
-+ writel(0, host->base + MMCICOMMAND);
-+ udelay(1);
-+ }
-+
-+ c |= cmd->opcode | MCI_CPSM_ENABLE;
-+ switch (cmd->flags & MMC_RSP_MASK) {
-+ case MMC_RSP_NONE:
-+ default:
-+ break;
-+ case MMC_RSP_LONG:
-+ c |= MCI_CPSM_LONGRSP;
-+ case MMC_RSP_SHORT:
-+ c |= MCI_CPSM_RESPONSE;
-+ break;
-+ }
-+ if (/*interrupt*/0)
-+ c |= MCI_CPSM_INTERRUPT;
-+
-+ host->cmd = cmd;
-+
-+ writel(cmd->arg, host->base + MMCIARGUMENT);
-+ writel(c, host->base + MMCICOMMAND);
-+}
-+
-+static void
-+mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
-+ unsigned int status)
-+{
-+ if (status & MCI_DATABLOCKEND) {
-+ host->data_xfered += 1 << data->blksz_bits;
-+ }
-+ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
-+ if (status & MCI_DATACRCFAIL)
-+ data->error = MMC_ERR_BADCRC;
-+ else if (status & MCI_DATATIMEOUT)
-+ data->error = MMC_ERR_TIMEOUT;
-+ else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
-+ data->error = MMC_ERR_FIFO;
-+ status |= MCI_DATAEND;
-+ }
-+ if (status & MCI_DATAEND) {
-+ host->data = NULL;
-+ if (!data->stop) {
-+ mmci_request_end(host, data->req);
-+ } else /*if (readl(host->base + MMCIDATACNT) > 6)*/ {
-+ mmci_start_command(host, data->stop, 0);
-+ }
-+ }
-+}
-+
-+static void
-+mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
-+ unsigned int status)
-+{
-+ host->cmd = NULL;
-+
-+ cmd->resp[0] = readl(host->base + MMCIRESPONSE0);
-+ cmd->resp[1] = readl(host->base + MMCIRESPONSE1);
-+ cmd->resp[2] = readl(host->base + MMCIRESPONSE2);
-+ cmd->resp[3] = readl(host->base + MMCIRESPONSE3);
-+
-+ if (status & MCI_CMDTIMEOUT) {
-+ cmd->error = MMC_ERR_TIMEOUT;
-+ } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
-+ cmd->error = MMC_ERR_BADCRC;
-+ }
-+
-+ if (!cmd->data || cmd->error != MMC_ERR_NONE) {
-+ mmci_request_end(host, cmd->req);
-+ } else if (!(cmd->data->flags & MMC_DATA_READ)) {
-+ mmci_start_data(host, cmd->data);
-+ }
-+}
-+
-+static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ struct mmci_host *host = dev_id;
-+ u32 status;
-+ int ret = 0;
-+
-+ do {
-+ struct mmc_command *cmd;
-+ struct mmc_data *data;
-+
-+ status = readl(host->base + MMCISTATUS);
-+ writel(status, host->base + MMCICLEAR);
-+
-+ if (!(status & MCI_IRQMASK))
-+ break;
-+
-+ DBG("MMCI: irq %08x\n", status);
-+
-+ if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) {
-+ int count = host->size - (readl(host->base + MMCIFIFOCNT) << 2);
-+ if (count < 0)
-+ count = 0;
-+ if (count && host->buffer) {
-+ readsl(host->base + MMCIFIFO, host->buffer, count >> 2);
-+ host->buffer += count;
-+ host->size -= count;
-+ if (host->size == 0)
-+ host->buffer = NULL;
-+ } else {
-+ static int first = 1;
-+ if (first) {
-+ first = 0;
-+ printk(KERN_ERR "MMCI: sinking excessive data\n");
-+ }
-+ readl(host->base + MMCIFIFO);
-+ }
-+ }
-+ if (status & (MCI_TXFIFOEMPTY|MCI_TXFIFOHALFEMPTY)) {
-+ int count = host->size;
-+ if (count > MCI_FIFOHALFSIZE)
-+ count = MCI_FIFOHALFSIZE;
-+ if (count && host->buffer) {
-+ writesl(host->base + MMCIFIFO, host->buffer, count >> 2);
-+ host->buffer += count;
-+ host->size -= count;
-+ if (host->size == 0)
-+ host->buffer = NULL;
-+ } else {
-+ static int first = 1;
-+ if (first) {
-+ first = 0;
-+ printk(KERN_ERR "MMCI: ran out of source data\n");
-+ }
-+ }
-+ }
-+
-+ data = host->data;
-+ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
-+ MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND))
-+ mmci_data_irq(host, data, status);
-+
-+ cmd = host->cmd;
-+ if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
-+ mmci_cmd_irq(host, cmd, status);
-+
-+ ret = 1;
-+ } while (status);
-+
-+ return IRQ_RETVAL(ret);
-+}
-+
-+static void mmci_request(struct mmc_host *mmc, struct mmc_request *req)
-+{
-+ struct mmci_host *host = to_mmci_host(mmc);
-+
-+ WARN_ON(host->req != NULL);
-+
-+ host->req = req;
-+
-+ if (req->data && req->data->flags & MMC_DATA_READ)
-+ mmci_start_data(host, req->data);
-+
-+ mmci_start_command(host, req->cmd, 0);
-+}
-+
-+static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-+{
-+ struct mmci_host *host = to_mmci_host(mmc);
-+ u32 clk = 0, pwr = 0;
-+
-+ DBG("MMCI: set_ios: clock %dHz busmode %d powermode %d Vdd %d.%02d\n",
-+ ios->clock, ios->bus_mode, ios->power_mode,
-+ ios->vdd / 100, ios->vdd % 100);
-+
-+ if (ios->clock) {
-+ clk = host->mclk / (2 * ios->clock) - 1;
-+ if (clk > 256)
-+ clk = 255;
-+ clk |= MCI_CLK_ENABLE;
-+ }
-+
-+ switch (ios->power_mode) {
-+ case MMC_POWER_OFF:
-+ break;
-+ case MMC_POWER_UP:
-+ pwr |= MCI_PWR_UP;
-+ break;
-+ case MMC_POWER_ON:
-+ pwr |= MCI_PWR_ON;
-+ break;
-+ }
-+
-+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-+ pwr |= MCI_ROD;
-+
-+ writel(clk, host->base + MMCICLOCK);
-+
-+ if (host->pwr != pwr) {
-+ host->pwr = pwr;
-+ writel(pwr, host->base + MMCIPOWER);
-+ }
-+}
-+
-+static struct mmc_host_ops mmci_ops = {
-+ .request = mmci_request,
-+ .set_ios = mmci_set_ios,
-+};
-+
-+static int mmci_probe(struct amba_device *dev, void *id)
-+{
-+ struct mmci_host *host;
-+ int ret;
-+// void *tmp;
-+
-+ /* enable the interrupt via the VIC */
-+// tmp = ioremap(0xc3000000, SZ_4K);
-+// if (tmp) {
-+// u32 val = readl(tmp + 0x10);
-+// writel(val | 0x180, tmp + 0x10);
-+// iounmap(tmp);
-+// }
-+
-+ if (!request_mem_region(dev->res.start, SZ_4K, DRIVER_NAME))
-+ return -EBUSY;
-+
-+ host = kmalloc(sizeof(struct mmci_host), GFP_KERNEL);
-+ if (!host) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ memset(host, 0, sizeof(struct mmci_host));
-+
-+ ret = mmc_init_host(&host->mmc);
-+ if (ret)
-+ goto out;
-+
-+ host->base = ioremap(dev->res.start, SZ_4K);
-+ if (!host->base) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ host->irq = dev->irq;
-+ host->mclk = 33000000; /* impd1 */
-+ host->mmc.dev = &dev->dev;
-+ host->mmc.ops = &mmci_ops;
-+ host->mmc.f_min = (host->mclk + 511) / 512;
-+ host->mmc.f_max = host->mclk / 2;
-+ if (host->mmc.f_max > fmax)
-+ host->mmc.f_max = fmax;
-+
-+ host->mmc.ocr_avail = MMC_VDD_35_36;
-+
-+ writel(0, host->base + MMCIMASK0);
-+ writel(0, host->base + MMCIMASK1);
-+ writel(0xfff, host->base + MMCICLEAR);
-+
-+ ret = request_irq(host->irq, mmci_irq, SA_SHIRQ, DRIVER_NAME, host);
-+ if (ret)
-+ goto out;
-+
-+ writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-+
-+ amba_set_drvdata(dev, host);
-+
-+ mmc_add_host(&host->mmc);
-+
-+ return 0;
-+
-+ out:
-+ if (host) {
-+ if (host->base)
-+ iounmap(host->base);
-+ kfree(host);
-+ }
-+ release_mem_region(dev->res.start, SZ_4K);
-+ return ret;
-+}
-+
-+static int mmci_remove(struct amba_device *dev)
-+{
-+ struct mmci_host *host = amba_get_drvdata(dev);
-+
-+ amba_set_drvdata(dev, NULL);
-+
-+ if (host) {
-+ mmc_remove_host(&host->mmc);
-+
-+ writel(0, host->base + MMCIMASK0);
-+ writel(0, host->base + MMCIMASK1);
-+
-+ writel(0, host->base + MMCICOMMAND);
-+ writel(0, host->base + MMCIDATACTRL);
-+
-+ free_irq(host->irq, host);
-+
-+ iounmap(host->base);
-+
-+ kfree(host);
-+
-+ release_mem_region(dev->res.start, SZ_4K);
-+ }
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int mmci_suspend(struct amba_device *dev, u32 state)
-+{
-+ struct mmci_host *host = amba_get_drvdata(dev);
-+
-+ return host ? mmc_suspend_host(&host->mmc, state) : 0;
-+}
-+
-+static int mmci_resume(struct amba_device *dev)
-+{
-+ struct mmci_host *host = amba_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host) {
-+ writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-+ ret = mmc_resume_host(&host->mmc);
-+ }
-+
-+ return ret;
-+}
-+#else
-+#define mmci_suspend NULL
-+#define mmci_resume NULL
-+#endif
-+
-+static struct amba_id mmci_ids[] = {
-+ {
-+ .id = 0x00041180,
-+ .mask = 0x000fffff,
-+ },
-+ {
-+ .id = 0x00041181,
-+ .mask = 0x000fffff,
-+ },
-+ { 0, 0 },
-+};
-+
-+static struct amba_driver mmci_driver = {
-+ .drv = {
-+ .name = DRIVER_NAME,
-+ },
-+ .probe = mmci_probe,
-+ .remove = mmci_remove,
-+ .suspend = mmci_suspend,
-+ .resume = mmci_resume,
-+ .id_table = mmci_ids,
-+};
-+
-+static int __init mmci_init(void)
-+{
-+ return amba_driver_register(&mmci_driver);
-+}
-+
-+static void __exit mmci_exit(void)
-+{
-+ amba_driver_unregister(&mmci_driver);
-+}
-+
-+module_init(mmci_init);
-+module_exit(mmci_exit);
-+module_param(fmax, int, 0444);
-+
-+MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmc_queue.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,29 @@
-+#ifndef MMC_QUEUE_H
-+#define MMC_QUEUE_H
-+
-+struct request;
-+struct task_struct;
-+
-+struct mmc_queue {
-+ struct mmc_card *card;
-+ struct completion thread_complete;
-+ wait_queue_head_t thread_wq;
-+ struct task_struct *thread;
-+ struct request *req;
-+ int (*prep_fn)(struct mmc_queue *, struct request *);
-+ int (*issue_fn)(struct mmc_queue *, struct request *);
-+ void *data;
-+ struct request_queue *queue;
-+};
-+
-+struct mmc_io_request {
-+ struct request *rq;
-+ int num;
-+ struct mmc_command selcmd; /* mmc_queue private */
-+ struct mmc_command cmd[4]; /* max 4 commands */
-+};
-+
-+extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
-+extern void mmc_cleanup_queue(struct mmc_queue *);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmc_block.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,482 @@
-+/*
-+ * Block driver for media (i.e., flash cards)
-+ *
-+ * Copyright 2002 Hewlett-Packard Company
-+ *
-+ * Use consistent with the GNU GPL is permitted,
-+ * provided that this copyright notice is
-+ * preserved in its entirety in all copies and derived works.
-+ *
-+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
-+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
-+ * FITNESS FOR ANY PARTICULAR PURPOSE.
-+ *
-+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
-+ *
-+ * Author: Andrew Christian
-+ * 28 May 2002
-+ */
-+#include <linux/moduleparam.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/sched.h>
-+#include <linux/kernel.h> /* printk() */
-+#include <linux/fs.h> /* everything... */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/hdreg.h> /* HDIO_GETGEO */
-+#include <linux/kdev_t.h>
-+#include <linux/blkdev.h>
-+#include <linux/devfs_fs_kernel.h>
-+
-+#include <linux/mmc/card.h>
-+#include <linux/mmc/protocol.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "mmc_queue.h"
-+
-+#define MMC_SHIFT 3 /* max 8 partitions per card */
-+
-+static int mmc_major;
-+static int maxsectors = 8;
-+
-+/*
-+ * There is one mmc_blk_data per slot.
-+ */
-+struct mmc_blk_data {
-+ spinlock_t lock;
-+ struct gendisk *disk;
-+ struct mmc_queue queue;
-+
-+ unsigned int usage;
-+ unsigned int block_bits;
-+ unsigned int suspended;
-+};
-+
-+static DECLARE_MUTEX(open_lock);
-+
-+static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
-+{
-+ struct mmc_blk_data *md;
-+
-+ down(&open_lock);
-+ md = disk->private_data;
-+ if (md && md->usage == 0)
-+ md = NULL;
-+ if (md)
-+ md->usage++;
-+ up(&open_lock);
-+
-+ return md;
-+}
-+
-+static void mmc_blk_put(struct mmc_blk_data *md)
-+{
-+ down(&open_lock);
-+ md->usage--;
-+ if (md->usage == 0) {
-+ put_disk(md->disk);
-+ mmc_cleanup_queue(&md->queue);
-+ kfree(md);
-+ }
-+ up(&open_lock);
-+}
-+
-+static int mmc_blk_open(struct inode *inode, struct file *filp)
-+{
-+ struct mmc_blk_data *md;
-+ int ret = -ENXIO;
-+
-+ md = mmc_blk_get(inode->i_bdev->bd_disk);
-+ if (md) {
-+ if (md->usage == 2)
-+ check_disk_change(inode->i_bdev);
-+ ret = 0;
-+ }
-+
-+ return ret;
-+}
-+
-+static int mmc_blk_release(struct inode *inode, struct file *filp)
-+{
-+ struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
-+
-+ mmc_blk_put(md);
-+ return 0;
-+}
-+
-+static int
-+mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-+{
-+ struct block_device *bdev = inode->i_bdev;
-+
-+ if (cmd == HDIO_GETGEO) {
-+ struct hd_geometry geo;
-+
-+ memset(&geo, 0, sizeof(struct hd_geometry));
-+
-+ geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
-+ geo.heads = 4;
-+ geo.sectors = 16;
-+ geo.start = get_start_sect(bdev);
-+
-+ return copy_to_user((void *)arg, &geo, sizeof(geo))
-+ ? -EFAULT : 0;
-+ }
-+
-+ return -ENOTTY;
-+}
-+
-+static struct block_device_operations mmc_bdops = {
-+ .open = mmc_blk_open,
-+ .release = mmc_blk_release,
-+ .ioctl = mmc_blk_ioctl,
-+ .owner = THIS_MODULE,
-+};
-+
-+struct mmc_blk_request {
-+ struct mmc_request req;
-+ struct mmc_command cmd;
-+ struct mmc_command stop;
-+ struct mmc_data data;
-+};
-+
-+static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
-+{
-+ struct mmc_blk_data *md = mq->data;
-+
-+ /*
-+ * If we have no device, we haven't finished initialising.
-+ */
-+ if (!md || !mq->card) {
-+ printk("killing request - no device/host\n");
-+ goto kill;
-+ }
-+
-+ if (md->suspended) {
-+ blk_plug_device(md->queue.queue);
-+ goto defer;
-+ }
-+
-+ /*
-+ * Check for excessive requests.
-+ */
-+ if (req->sector + req->nr_sectors > get_capacity(req->rq_disk)) {
-+ printk("bad request size\n");
-+ goto kill;
-+ }
-+
-+ return BLKPREP_OK;
-+
-+ defer:
-+ return BLKPREP_DEFER;
-+ kill:
-+ return BLKPREP_KILL;
-+}
-+
-+static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
-+{
-+ struct mmc_blk_data *md = mq->data;
-+ struct mmc_card *card = md->queue.card;
-+ int err, sz = 0;
-+
-+ err = mmc_card_claim_host(card);
-+ if (err)
-+ goto cmd_err;
-+
-+ do {
-+ struct mmc_blk_request rq;
-+ struct mmc_command cmd;
-+
-+ memset(&rq, 0, sizeof(struct mmc_blk_request));
-+ rq.req.cmd = &rq.cmd;
-+ rq.req.data = &rq.data;
-+
-+ rq.cmd.arg = req->sector << 9;
-+ rq.cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
-+ rq.data.rq = req;
-+ rq.data.timeout_ns = card->csd.tacc_ns * 10;
-+ rq.data.timeout_clks = card->csd.tacc_clks * 10;
-+ rq.data.blksz_bits = md->block_bits;
-+ rq.data.blocks = req->current_nr_sectors >> (md->block_bits - 9);
-+ rq.stop.opcode = MMC_STOP_TRANSMISSION;
-+ rq.stop.arg = 0;
-+ rq.stop.flags = MMC_RSP_SHORT | MMC_RSP_CRC | MMC_RSP_BUSY;
-+
-+ if (rq_data_dir(req) == READ) {
-+ rq.cmd.opcode = rq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
-+ rq.data.flags |= MMC_DATA_READ;
-+ } else {
-+ rq.cmd.opcode = MMC_WRITE_BLOCK;
-+ rq.cmd.flags |= MMC_RSP_BUSY;
-+ rq.data.flags |= MMC_DATA_WRITE;
-+ rq.data.blocks = 1;
-+ }
-+ rq.req.stop = rq.data.blocks > 1 ? &rq.stop : NULL;
-+
-+ mmc_wait_for_req(card->host, &rq.req);
-+ if (rq.cmd.error) {
-+ err = rq.cmd.error;
-+ printk("error %d sending read/write command\n", err);
-+ goto cmd_err;
-+ }
-+
-+ if (rq_data_dir(req) == READ) {
-+ sz = rq.data.bytes_xfered;
-+ } else {
-+ sz = 0;
-+ }
-+
-+ if (rq.data.error) {
-+ err = rq.data.error;
-+ printk("error %d transferring data\n", err);
-+ goto cmd_err;
-+ }
-+
-+ if (rq.stop.error) {
-+ err = rq.stop.error;
-+ printk("error %d sending stop command\n", err);
-+ goto cmd_err;
-+ }
-+
-+ do {
-+ cmd.opcode = MMC_SEND_STATUS;
-+ cmd.arg = card->rca << 16;
-+ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
-+ err = mmc_wait_for_cmd(card->host, &cmd, 5);
-+ if (err) {
-+ printk("error %d requesting status\n", err);
-+ goto cmd_err;
-+ }
-+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
-+
-+#if 0
-+ if (cmd.resp[0] & ~0x00000900)
-+ printk("status = %08x\n", cmd.resp[0]);
-+ err = mmc_decode_status(cmd.resp);
-+ if (err)
-+ goto cmd_err;
-+#endif
-+
-+ sz = rq.data.bytes_xfered;
-+ } while (end_that_request_chunk(req, 1, sz));
-+
-+ mmc_card_release_host(card);
-+
-+ return 1;
-+
-+ cmd_err:
-+ mmc_card_release_host(card);
-+
-+ end_that_request_chunk(req, 1, sz);
-+ req->errors = err;
-+
-+ return 0;
-+}
-+
-+#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
-+
-+static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
-+
-+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
-+{
-+ struct mmc_blk_data *md;
-+ int devidx;
-+
-+ devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
-+ if (devidx >= MMC_NUM_MINORS)
-+ return NULL;
-+ __set_bit(devidx, dev_use);
-+
-+ md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
-+ if (md) {
-+ memset(md, 0, sizeof(struct mmc_blk_data));
-+
-+ md->disk = alloc_disk(1 << MMC_SHIFT);
-+ if (md->disk == NULL) {
-+ kfree(md);
-+ md = NULL;
-+ goto out;
-+ }
-+
-+ spin_lock_init(&md->lock);
-+ md->usage = 1;
-+
-+ mmc_init_queue(&md->queue, card, &md->lock);
-+ md->queue.prep_fn = mmc_blk_prep_rq;
-+ md->queue.issue_fn = mmc_blk_issue_rq;
-+ md->queue.data = md;
-+
-+ md->disk->major = mmc_major;
-+ md->disk->first_minor = devidx << MMC_SHIFT;
-+ md->disk->fops = &mmc_bdops;
-+ md->disk->private_data = md;
-+ md->disk->queue = md->queue.queue;
-+ md->disk->driverfs_dev = &card->dev;
-+
-+ sprintf(md->disk->disk_name, "mmcblk%d", devidx);
-+ sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
-+
-+ md->block_bits = md->queue.card->csd.read_blkbits;
-+
-+ blk_queue_max_sectors(md->queue.queue, maxsectors);
-+ blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
-+ set_capacity(md->disk, md->queue.card->csd.capacity);
-+ }
-+ out:
-+ return md;
-+}
-+
-+static int
-+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
-+{
-+ struct mmc_command cmd;
-+ int err;
-+
-+ mmc_card_claim_host(card);
-+ cmd.opcode = MMC_SET_BLOCKLEN;
-+ cmd.arg = 1 << card->csd.read_blkbits;
-+ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
-+ err = mmc_wait_for_cmd(card->host, &cmd, 5);
-+ mmc_card_release_host(card);
-+
-+ if (err) {
-+ printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
-+ md->disk->disk_name, cmd.arg, err);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int mmc_blk_probe(struct mmc_card *card)
-+{
-+ struct mmc_blk_data *md;
-+ int err;
-+
-+ if (card->csd.cmdclass & ~0x1ff)
-+ return -ENODEV;
-+
-+ if (card->csd.read_blkbits < 9) {
-+ printk(KERN_WARNING "%s: read blocksize too small (%u)\n",
-+ mmc_card_id(card), 1 << card->csd.read_blkbits);
-+ return -ENODEV;
-+ }
-+
-+ md = mmc_blk_alloc(card);
-+ if (md == NULL)
-+ return -ENOMEM;
-+
-+ err = mmc_blk_set_blksize(md, card);
-+ if (err)
-+ goto out;
-+
-+ printk(KERN_INFO "%s: %s %s %dKiB\n",
-+ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-+ (card->csd.capacity << card->csd.read_blkbits) / 1024);
-+
-+ mmc_set_drvdata(card, md);
-+ add_disk(md->disk);
-+ return 0;
-+
-+ out:
-+ mmc_blk_put(md);
-+
-+ return err;
-+}
-+
-+static void mmc_blk_remove(struct mmc_card *card)
-+{
-+ struct mmc_blk_data *md = mmc_get_drvdata(card);
-+
-+ if (md) {
-+ int devidx;
-+
-+ del_gendisk(md->disk);
-+
-+ /*
-+ * I think this is needed.
-+ */
-+ md->disk->queue = NULL;
-+
-+ devidx = md->disk->first_minor >> MMC_SHIFT;
-+ __clear_bit(devidx, dev_use);
-+
-+ mmc_blk_put(md);
-+ }
-+ mmc_set_drvdata(card, NULL);
-+}
-+
-+#ifdef CONFIG_PM
-+static int mmc_blk_suspend(struct mmc_card *card, u32 state)
-+{
-+ struct mmc_blk_data *md = mmc_get_drvdata(card);
-+
-+ if (md) {
-+ blk_stop_queue(md->queue.queue);
-+ }
-+ return 0;
-+}
-+
-+static int mmc_blk_resume(struct mmc_card *card)
-+{
-+ struct mmc_blk_data *md = mmc_get_drvdata(card);
-+
-+ if (md) {
-+ mmc_blk_set_blksize(md, md->queue.card);
-+ blk_start_queue(md->queue.queue);
-+ }
-+ return 0;
-+}
-+#else
-+#define mmc_blk_suspend NULL
-+#define mmc_blk_resume NULL
-+#endif
-+
-+static struct mmc_driver mmc_driver = {
-+ .drv = {
-+ .name = "mmcblk",
-+ },
-+ .probe = mmc_blk_probe,
-+ .remove = mmc_blk_remove,
-+ .suspend = mmc_blk_suspend,
-+ .resume = mmc_blk_resume,
-+};
-+
-+static int __init mmc_blk_init(void)
-+{
-+ int res = -ENOMEM;
-+
-+ res = register_blkdev(mmc_major, "mmc");
-+ if (res < 0) {
-+ printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
-+ mmc_major, res);
-+ goto out;
-+ }
-+ if (mmc_major == 0)
-+ mmc_major = res;
-+
-+ devfs_mk_dir("mmc");
-+ return mmc_register_driver(&mmc_driver);
-+
-+ out:
-+ return res;
-+}
-+
-+static void __exit mmc_blk_exit(void)
-+{
-+ mmc_unregister_driver(&mmc_driver);
-+ devfs_remove("mmc");
-+ unregister_blkdev(mmc_major, "mmc");
-+}
-+
-+module_init(mmc_blk_init);
-+module_exit(mmc_blk_exit);
-+module_param(maxsectors, int, 0444);
-+
-+MODULE_PARM_DESC(maxsectors, "Maximum number of sectors for a single request");
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/pxamci.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,94 @@
-+#undef MMC_STRPCL
-+#undef MMC_STAT
-+#undef MMC_CLKRT
-+#undef MMC_SPI
-+#undef MMC_CMDAT
-+#undef MMC_RESTO
-+#undef MMC_RDTO
-+#undef MMC_BLKLEN
-+#undef MMC_NOB
-+#undef MMC_PRTBUF
-+#undef MMC_I_MASK
-+#undef END_CMD_RES
-+#undef PRG_DONE
-+#undef DATA_TRAN_DONE
-+#undef MMC_I_REG
-+#undef MMC_CMD
-+#undef MMC_ARGH
-+#undef MMC_ARGL
-+#undef MMC_RES
-+#undef MMC_RXFIFO
-+#undef MMC_TXFIFO
-+
-+#define MMC_STRPCL 0x0000
-+#define STOP_CLOCK (1 << 0)
-+#define START_CLOCK (2 << 0)
-+
-+#define MMC_STAT 0x0004
-+#define STAT_END_CMD_RES (1 << 13)
-+#define STAT_PRG_DONE (1 << 12)
-+#define STAT_DATA_TRAN_DONE (1 << 11)
-+#define STAT_CLK_EN (1 << 8)
-+#define STAT_RECV_FIFO_FULL (1 << 7)
-+#define STAT_XMIT_FIFO_EMPTY (1 << 6)
-+#define STAT_RES_CRC_ERR (1 << 5)
-+#define STAT_SPI_READ_ERROR_TOKEN (1 << 4)
-+#define STAT_CRC_READ_ERROR (1 << 3)
-+#define STAT_CRC_WRITE_ERROR (1 << 2)
-+#define STAT_TIME_OUT_RESPONSE (1 << 1)
-+#define STAT_READ_TIME_OUT (1 << 0)
-+
-+#define MMC_CLKRT 0x0008 /* 3 bit */
-+
-+#define MMC_SPI 0x000c
-+#define SPI_CS_ADDRESS (1 << 3)
-+#define SPI_CS_EN (1 << 2)
-+#define CRC_ON (1 << 1)
-+#define SPI_EN (1 << 0)
-+
-+#define MMC_CMDAT 0x0010
-+#define CMDAT_DMAEN (1 << 7)
-+#define CMDAT_INIT (1 << 6)
-+#define CMDAT_BUSY (1 << 5)
-+#define CMDAT_STREAM (1 << 4) /* 1 = stream */
-+#define CMDAT_WRITE (1 << 3) /* 1 = write */
-+#define CMDAT_DATAEN (1 << 2)
-+#define CMDAT_RESP_NONE (0 << 0)
-+#define CMDAT_RESP_SHORT (1 << 0)
-+#define CMDAT_RESP_R2 (2 << 0)
-+#define CMDAT_RESP_R3 (3 << 0)
-+
-+#define MMC_RESTO 0x0014 /* 7 bit */
-+
-+#define MMC_RDTO 0x0018 /* 16 bit */
-+
-+#define MMC_BLKLEN 0x001c /* 10 bit */
-+
-+#define MMC_NOB 0x0020 /* 16 bit */
-+
-+#define MMC_PRTBUF 0x0024
-+#define BUF_PART_FULL (1 << 0)
-+
-+#define MMC_I_MASK 0x0028
-+#define TXFIFO_WR_REQ (1 << 6)
-+#define RXFIFO_RD_REQ (1 << 5)
-+#define CLK_IS_OFF (1 << 4)
-+#define STOP_CMD (1 << 3)
-+#define END_CMD_RES (1 << 2)
-+#define PRG_DONE (1 << 1)
-+#define DATA_TRAN_DONE (1 << 0)
-+
-+#define MMC_I_REG 0x002c
-+/* same as MMC_I_MASK */
-+
-+#define MMC_CMD 0x0030
-+
-+#define MMC_ARGH 0x0034 /* 16 bit */
-+
-+#define MMC_ARGL 0x0038 /* 16 bit */
-+
-+#define MMC_RES 0x003c /* 16 bit */
-+
-+#define MMC_RXFIFO 0x0040 /* 8 bit */
-+
-+#define MMC_TXFIFO 0x0044 /* 8 bit */
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmci.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,147 @@
-+/*
-+ * linux/drivers/media/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
-+ *
-+ * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#define MMCIPOWER 0x000
-+#define MCI_PWR_OFF 0x00
-+#define MCI_PWR_UP 0x02
-+#define MCI_PWR_ON 0x03
-+#define MCI_OD (1 << 6)
-+#define MCI_ROD (1 << 7)
-+
-+#define MMCICLOCK 0x004
-+#define MCI_CLK_ENABLE (1 << 8)
-+#define MCI_PWRSAVE (1 << 9)
-+#define MCI_BYPASS (1 << 10)
-+
-+#define MMCIARGUMENT 0x008
-+#define MMCICOMMAND 0x00c
-+#define MCI_CPSM_RESPONSE (1 << 6)
-+#define MCI_CPSM_LONGRSP (1 << 7)
-+#define MCI_CPSM_INTERRUPT (1 << 8)
-+#define MCI_CPSM_PENDING (1 << 9)
-+#define MCI_CPSM_ENABLE (1 << 10)
-+
-+#define MMCIRESPCMD 0x010
-+#define MMCIRESPONSE0 0x014
-+#define MMCIRESPONSE1 0x018
-+#define MMCIRESPONSE2 0x01c
-+#define MMCIRESPONSE3 0x020
-+#define MMCIDATATIMER 0x024
-+#define MMCIDATALENGTH 0x028
-+#define MMCIDATACTRL 0x02c
-+#define MCI_DPSM_ENABLE (1 << 0)
-+#define MCI_DPSM_DIRECTION (1 << 1)
-+#define MCI_DPSM_MODE (1 << 2)
-+#define MCI_DPSM_DMAENABLE (1 << 3)
-+
-+#define MMCIDATACNT 0x030
-+#define MMCISTATUS 0x034
-+#define MCI_CMDCRCFAIL (1 << 0)
-+#define MCI_DATACRCFAIL (1 << 1)
-+#define MCI_CMDTIMEOUT (1 << 2)
-+#define MCI_DATATIMEOUT (1 << 3)
-+#define MCI_TXUNDERRUN (1 << 4)
-+#define MCI_RXOVERRUN (1 << 5)
-+#define MCI_CMDRESPEND (1 << 6)
-+#define MCI_CMDSENT (1 << 7)
-+#define MCI_DATAEND (1 << 8)
-+#define MCI_DATABLOCKEND (1 << 10)
-+#define MCI_CMDACTIVE (1 << 11)
-+#define MCI_TXACTIVE (1 << 12)
-+#define MCI_RXACTIVE (1 << 13)
-+#define MCI_TXFIFOHALFEMPTY (1 << 14)
-+#define MCI_RXFIFOHALFFULL (1 << 15)
-+#define MCI_TXFIFOFULL (1 << 16)
-+#define MCI_RXFIFOFULL (1 << 17)
-+#define MCI_TXFIFOEMPTY (1 << 18)
-+#define MCI_RXFIFOEMPTY (1 << 19)
-+#define MCI_TXDATAAVLBL (1 << 20)
-+#define MCI_RXDATAAVLBL (1 << 21)
-+
-+#define MMCICLEAR 0x038
-+#define MCI_CMDCRCFAILCLR (1 << 0)
-+#define MCI_DATACRCFAILCLR (1 << 1)
-+#define MCI_CMDTIMEOUTCLR (1 << 2)
-+#define MCI_DATATIMEOUTCLR (1 << 3)
-+#define MCI_TXUNDERRUNCLR (1 << 4)
-+#define MCI_RXOVERRUNCLR (1 << 5)
-+#define MCI_CMDRESPENDCLR (1 << 6)
-+#define MCI_CMDSENTCLR (1 << 7)
-+#define MCI_DATAENDCLR (1 << 8)
-+#define MCI_DATABLOCKENDCLR (1 << 10)
-+
-+#define MMCIMASK0 0x03c
-+#define MCI_CMDCRCFAILMASK (1 << 0)
-+#define MCI_DATACRCFAILMASK (1 << 1)
-+#define MCI_CMDTIMEOUTMASK (1 << 2)
-+#define MCI_DATATIMEOUTMASK (1 << 3)
-+#define MCI_TXUNDERRUNMASK (1 << 4)
-+#define MCI_RXOVERRUNMASK (1 << 5)
-+#define MCI_CMDRESPENDMASK (1 << 6)
-+#define MCI_CMDSENTMASK (1 << 7)
-+#define MCI_DATAENDMASK (1 << 8)
-+#define MCI_DATABLOCKENDMASK (1 << 10)
-+#define MCI_CMDACTIVEMASK (1 << 11)
-+#define MCI_TXACTIVEMASK (1 << 12)
-+#define MCI_RXACTIVEMASK (1 << 13)
-+#define MCI_TXFIFOHALFEMPTYMASK (1 << 14)
-+#define MCI_RXFIFOHALFFULLMASK (1 << 15)
-+#define MCI_TXFIFOFULLMASK (1 << 16)
-+#define MCI_RXFIFOFULLMASK (1 << 17)
-+#define MCI_TXFIFOEMPTYMASK (1 << 18)
-+#define MCI_RXFIFOEMPTYMASK (1 << 19)
-+#define MCI_TXDATAAVLBLMASK (1 << 20)
-+#define MCI_RXDATAAVLBLMASK (1 << 21)
-+
-+#define MMCIMASK1 0x040
-+#define MMCIFIFOCNT 0x048
-+#define MMCIFIFO 0x080 /* to 0x0bc */
-+
-+#define MCI_IRQMASK \
-+ (MCI_CMDCRCFAIL|MCI_DATACRCFAIL|MCI_CMDTIMEOUT|MCI_DATATIMEOUT| \
-+ MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_CMDRESPEND|MCI_CMDSENT| \
-+ MCI_DATAEND|MCI_DATABLOCKEND| \
-+ MCI_TXFIFOHALFEMPTY|MCI_RXFIFOHALFFULL| \
-+ MCI_TXFIFOEMPTY|MCI_RXDATAAVLBL)
-+
-+#define MCI_IRQENABLE \
-+ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
-+ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
-+ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK| \
-+ MCI_DATABLOCKENDMASK|MCI_TXFIFOHALFEMPTYMASK| \
-+ MCI_RXFIFOHALFFULLMASK)
-+
-+#define MCI_FIFOSIZE 16
-+
-+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-+
-+struct mmci_host {
-+ struct mmc_host mmc;
-+ void *base;
-+ int irq;
-+ unsigned int mclk;
-+ u32 pwr;
-+
-+ struct mmc_request *req;
-+ struct mmc_command *cmd;
-+ struct mmc_data *data;
-+
-+ unsigned int data_xfered;
-+
-+ /* pio stuff */
-+ void *buffer;
-+ unsigned int size;
-+
-+ /* dma stuff */
-+// struct scatterlist *sg_list;
-+// int sg_len;
-+// int sg_dir;
-+};
-+
-+#define to_mmci_host(mmc) container_of(mmc, struct mmci_host, mmc)
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/mmc.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,801 @@
-+/*
-+ * linux/drivers/media/mmc/mmc.c
-+ *
-+ * Copyright (C) 2003 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/completion.h>
-+#include <linux/device.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+
-+#include <linux/mmc/card.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/protocol.h>
-+
-+#include "mmc.h"
-+
-+#ifdef CONFIG_MMC_DEBUG
-+#define DBG(x...) printk(KERN_DEBUG x)
-+#else
-+#define DBG(x...) do { } while (0)
-+#endif
-+
-+#define CMD_RETRIES 3
-+
-+/*
-+ * OCR Bit positions to 10s of Vdd mV.
-+ */
-+static const unsigned short mmc_ocr_bit_to_vdd[] = {
-+ 150, 155, 160, 165, 170, 180, 190, 200,
-+ 210, 220, 230, 240, 250, 260, 270, 280,
-+ 290, 300, 310, 320, 330, 340, 350, 360
-+};
-+
-+static const unsigned int tran_exp[] = {
-+ 10000, 100000, 1000000, 10000000,
-+ 0, 0, 0, 0
-+};
-+
-+static const unsigned char tran_mant[] = {
-+ 0, 10, 12, 13, 15, 20, 25, 30,
-+ 35, 40, 45, 50, 55, 60, 70, 80,
-+};
-+
-+static const unsigned int tacc_exp[] = {
-+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
-+};
-+
-+static const unsigned int tacc_mant[] = {
-+ 0, 10, 12, 13, 15, 20, 25, 30,
-+ 35, 40, 45, 50, 55, 60, 70, 80,
-+};
-+
-+
-+/**
-+ * mmc_request_done - finish processing an MMC command
-+ * @host: MMC host which completed command
-+ * @cmd: MMC command which completed
-+ * @err: MMC error code
-+ *
-+ * MMC drivers should call this function when they have completed
-+ * their processing of a command. This should be called before the
-+ * data part of the command has completed.
-+ */
-+void mmc_request_done(struct mmc_host *host, struct mmc_request *req)
-+{
-+ struct mmc_command *cmd = req->cmd;
-+ int err = req->cmd->error;
-+ DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode,
-+ err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-+
-+ if (err && cmd->retries) {
-+ cmd->retries--;
-+ cmd->error = 0;
-+ host->ops->request(host, req);
-+ } else if (req->done) {
-+ req->done(req);
-+ }
-+}
-+
-+EXPORT_SYMBOL(mmc_request_done);
-+
-+/**
-+ * mmc_start_request - start a command on a host
-+ * @host: MMC host to start command on
-+ * @cmd: MMC command to start
-+ *
-+ * Queue a command on the specified host. We expect the
-+ * caller to be holding the host lock with interrupts disabled.
-+ */
-+void
-+mmc_start_request(struct mmc_host *host, struct mmc_request *req)
-+{
-+ DBG("MMC: starting cmd %02x arg %08x flags %08x\n",
-+ req->cmd->opcode, req->cmd->arg, req->cmd->flags);
-+
-+ req->cmd->error = 0;
-+ req->cmd->req = req;
-+ if (req->data) {
-+ req->cmd->data = req->data;
-+ req->data->error = 0;
-+ req->data->req = req;
-+ if (req->stop) {
-+ req->data->stop = req->stop;
-+ req->stop->error = 0;
-+ req->stop->req = req;
-+ }
-+ }
-+ host->ops->request(host, req);
-+}
-+
-+EXPORT_SYMBOL(mmc_start_request);
-+
-+static void mmc_wait_done(struct mmc_request *req)
-+{
-+ complete(req->done_data);
-+}
-+
-+int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *req)
-+{
-+ DECLARE_COMPLETION(complete);
-+
-+ req->done_data = &complete;
-+ req->done = mmc_wait_done;
-+
-+ mmc_start_request(host, req);
-+
-+ wait_for_completion(&complete);
-+
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(mmc_wait_for_req);
-+
-+/**
-+ * mmc_wait_for_cmd - start a command and wait for completion
-+ * @host: MMC host to start command
-+ * @cmd: MMC command to start
-+ * @retries: maximum number of retries
-+ *
-+ * Start a new MMC command for a host, and wait for the command
-+ * to complete. Return any error that occurred while the command
-+ * was executing. Do not attempt to parse the response.
-+ */
-+int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
-+{
-+ struct mmc_request req;
-+
-+ BUG_ON(host->card_busy == NULL);
-+
-+ memset(&req, 0, sizeof(struct mmc_request));
-+
-+ memset(cmd->resp, 0, sizeof(cmd->resp));
-+ cmd->retries = retries;
-+
-+ req.cmd = cmd;
-+ cmd->data = NULL;
-+
-+ mmc_wait_for_req(host, &req);
-+
-+ return cmd->error;
-+}
-+
-+EXPORT_SYMBOL(mmc_wait_for_cmd);
-+
-+
-+
-+/**
-+ * __mmc_claim_host - exclusively claim a host
-+ * @host: mmc host to claim
-+ * @card: mmc card to claim host for
-+ *
-+ * Claim a host for a set of operations. If a valid card
-+ * is passed and this wasn't the last card selected, select
-+ * the card before returning.
-+ *
-+ * Note: you should use mmc_card_claim_host or mmc_claim_host.
-+ */
-+int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ unsigned long flags;
-+ int err = 0;
-+
-+ add_wait_queue(&host->wq, &wait);
-+ spin_lock_irqsave(&host->lock, flags);
-+ while (1) {
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ if (host->card_busy == NULL)
-+ break;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ schedule();
-+ spin_lock_irqsave(&host->lock, flags);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ host->card_busy = card;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+ remove_wait_queue(&host->wq, &wait);
-+
-+ if (card != (void *)-1 && host->card_selected != card) {
-+ struct mmc_command cmd;
-+
-+ host->card_selected = card;
-+
-+ cmd.opcode = MMC_SELECT_CARD;
-+ cmd.arg = card->rca << 16;
-+ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
-+
-+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-+ }
-+
-+ return err;
-+}
-+
-+EXPORT_SYMBOL(__mmc_claim_host);
-+
-+/**
-+ * mmc_release_host - release a host
-+ * @host: mmc host to release
-+ *
-+ * Release a MMC host, allowing others to claim the host
-+ * for their operations.
-+ */
-+void mmc_release_host(struct mmc_host *host)
-+{
-+ unsigned long flags;
-+
-+ BUG_ON(host->card_busy == NULL);
-+
-+ spin_lock_irqsave(&host->lock, flags);
-+ host->card_busy = NULL;
-+ spin_unlock_irqrestore(&host->lock, flags);
-+
-+ wake_up(&host->wq);
-+}
-+
-+EXPORT_SYMBOL(mmc_release_host);
-+
-+static void mmc_deselect_cards(struct mmc_host *host)
-+{
-+ struct mmc_command cmd;
-+
-+ /*
-+ * Ensure that no card is selected.
-+ */
-+ if (host->card_selected) {
-+ host->card_selected = NULL;
-+
-+ cmd.opcode = MMC_SELECT_CARD;
-+ cmd.arg = 0;
-+ cmd.flags = MMC_RSP_NONE;
-+
-+ mmc_wait_for_cmd(host, &cmd, 0);
-+ }
-+}
-+
-+
-+static inline void mmc_delay(unsigned int ms)
-+{
-+ if (ms < HZ / 1000) {
-+ yield();
-+ mdelay(ms);
-+ } else {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(ms * HZ / 1000);
-+ }
-+}
-+
-+static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
-+{
-+ int bit;
-+
-+ /*
-+ * Mask off any voltages we don't support
-+ */
-+ ocr &= host->ocr_avail;
-+
-+ /*
-+ * Select the lowest voltage
-+ */
-+ bit = ffs(ocr);
-+ if (bit) {
-+ bit -= 1;
-+
-+ ocr = 1 << bit;
-+
-+ host->ios.vdd = mmc_ocr_bit_to_vdd[bit];
-+ host->ops->set_ios(host, &host->ios);
-+ } else {
-+ ocr = 0;
-+ }
-+
-+ return ocr;
-+}
-+
-+static void mmc_decode_cid(struct mmc_cid *cid, u32 *resp)
-+{
-+ memset(cid, 0, sizeof(struct mmc_cid));
-+
-+ cid->manfid = resp[0] >> 8;
-+ cid->prod_name[0] = resp[0];
-+ cid->prod_name[1] = resp[1] >> 24;
-+ cid->prod_name[2] = resp[1] >> 16;
-+ cid->prod_name[3] = resp[1] >> 8;
-+ cid->prod_name[4] = resp[1];
-+ cid->prod_name[5] = resp[2] >> 24;
-+ cid->prod_name[6] = resp[2] >> 16;
-+ cid->prod_name[7] = '\0';
-+ cid->hwrev = (resp[2] >> 12) & 15;
-+ cid->fwrev = (resp[2] >> 8) & 15;
-+ cid->serial = (resp[2] & 255) << 16 | (resp[3] >> 16);
-+ cid->month = (resp[3] >> 12) & 15;
-+ cid->year = (resp[3] >> 8) & 15;
-+}
-+
-+static void mmc_decode_csd(struct mmc_csd *csd, u32 *resp)
-+{
-+ unsigned int e, m;
-+
-+ csd->mmc_prot = (resp[0] >> 26) & 15;
-+ m = (resp[0] >> 19) & 15;
-+ e = (resp[0] >> 16) & 7;
-+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-+ csd->tacc_clks = ((resp[0] >> 8) & 255) * 100;
-+
-+ m = (resp[0] >> 3) & 15;
-+ e = resp[0] & 7;
-+ csd->max_dtr = tran_exp[e] * tran_mant[m];
-+ csd->cmdclass = (resp[1] >> 20) & 0xfff;
-+
-+ e = (resp[2] >> 15) & 7;
-+ m = (resp[1] << 2 | resp[2] >> 30) & 0x3fff;
-+ csd->capacity = (1 + m) << (e + 2);
-+
-+ csd->read_blkbits = (resp[1] >> 16) & 15;
-+}
-+
-+/*
-+ * Locate a MMC card on this MMC host given a CID.
-+ */
-+static struct mmc_card *
-+mmc_find_card(struct mmc_host *host, struct mmc_cid *cid)
-+{
-+ struct mmc_card *card;
-+
-+ list_for_each_entry(card, &host->cards, node) {
-+ if (memcmp(&card->cid, cid, sizeof(struct mmc_cid)) == 0)
-+ return card;
-+ }
-+ return NULL;
-+}
-+
-+/*
-+ * Allocate a new MMC card, and assign a unique RCA.
-+ */
-+static struct mmc_card *
-+mmc_alloc_card(struct mmc_host *host, struct mmc_cid *cid, unsigned int *frca)
-+{
-+ struct mmc_card *card, *c;
-+ unsigned int rca = *frca;
-+
-+ card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
-+ if (!card)
-+ return ERR_PTR(-ENOMEM);
-+
-+ mmc_init_card(card, host);
-+ memcpy(&card->cid, cid, sizeof(struct mmc_cid));
-+
-+ again:
-+ list_for_each_entry(c, &host->cards, node)
-+ if (c->rca == rca) {
-+ rca++;
-+ goto again;
-+ }
-+
-+ card->rca = rca;
-+
-+ *frca = rca;
-+
-+ return card;
-+}
-+
-+/*
-+ * Apply power to the MMC stack.
-+ */
-+static void mmc_power_up(struct mmc_host *host)
-+{
-+ struct mmc_command cmd;
-+ int bit = fls(host->ocr_avail) - 1;
-+
-+ host->ios.vdd = mmc_ocr_bit_to_vdd[bit];
-+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-+ host->ios.power_mode = MMC_POWER_UP;
-+ host->ops->set_ios(host, &host->ios);
-+
-+ mmc_delay(1);
-+
-+ host->ios.clock = host->f_min;
-+ host->ios.power_mode = MMC_POWER_ON;
-+ host->ops->set_ios(host, &host->ios);
-+
-+ mmc_delay(2);
-+
-+ cmd.opcode = MMC_GO_IDLE_STATE;
-+ cmd.arg = 0;
-+ cmd.flags = MMC_RSP_NONE;
-+
-+ mmc_wait_for_cmd(host, &cmd, 0);
-+}
-+
-+static void mmc_power_off(struct mmc_host *host)
-+{
-+ host->ios.clock = 0;
-+ host->ios.vdd = 0;
-+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-+ host->ios.power_mode = MMC_POWER_OFF;
-+ host->ops->set_ios(host, &host->ios);
-+}
-+
-+static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-+{
-+ struct mmc_command cmd;
-+ int i, err = 0;
-+
-+ cmd.opcode = MMC_SEND_OP_COND;
-+ cmd.arg = ocr;
-+ cmd.flags = MMC_RSP_SHORT;
-+
-+ for (i = 100; i; i--) {
-+ err = mmc_wait_for_cmd(host, &cmd, 0);
-+ if (err != MMC_ERR_NONE)
-+ break;
-+
-+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
-+ break;
-+
-+ err = MMC_ERR_TIMEOUT;
-+ }
-+
-+ if (rocr)
-+ *rocr = cmd.resp[0];
-+
-+ return err;
-+}
-+
-+/*
-+ * Discover cards by requesting their CID. If this command
-+ * times out, it is not an error; there are no further cards
-+ * to be discovered. Add new cards to the list.
-+ *
-+ * Create a mmc_card entry for each discovered card, assigning
-+ * it an RCA, and save the CID.
-+ */
-+static void mmc_discover_cards(struct mmc_host *host)
-+{
-+ struct mmc_card *card;
-+ unsigned int first_rca = 1, err;
-+
-+ while (1) {
-+ struct mmc_command cmd;
-+ struct mmc_cid cid;
-+
-+ /*
-+ * Read CID
-+ */
-+ cmd.opcode = MMC_ALL_SEND_CID;
-+ cmd.arg = 0;
-+ cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
-+
-+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-+ if (err == MMC_ERR_TIMEOUT) {
-+ err = MMC_ERR_NONE;
-+ break;
-+ }
-+ if (err != MMC_ERR_NONE) {
-+ printk(KERN_ERR "MMC: mmc%d error requesting CID: %d\n",
-+ host->host_num, err);
-+ break;
-+ }
-+
-+ mmc_decode_cid(&cid, cmd.resp);
-+
-+ card = mmc_find_card(host, &cid);
-+ if (!card) {
-+ card = mmc_alloc_card(host, &cid, &first_rca);
-+ if (IS_ERR(card)) {
-+ err = PTR_ERR(card);
-+ break;
-+ }
-+ list_add(&card->node, &host->cards);
-+ }
-+
-+ card->state &= ~MMC_STATE_DEAD;
-+
-+ cmd.opcode = MMC_SET_RELATIVE_ADDR;
-+ cmd.arg = card->rca << 16;
-+ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
-+
-+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-+ if (err != MMC_ERR_NONE)
-+ card->state |= MMC_STATE_DEAD;
-+ }
-+}
-+
-+static void mmc_read_csds(struct mmc_host *host)
-+{
-+ struct mmc_card *card;
-+
-+ list_for_each_entry(card, &host->cards, node) {
-+ struct mmc_command cmd;
-+ int err;
-+
-+ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
-+ continue;
-+
-+ cmd.opcode = MMC_SEND_CSD;
-+ cmd.arg = card->rca << 16;
-+ cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
-+
-+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-+ if (err != MMC_ERR_NONE) {
-+ card->state |= MMC_STATE_DEAD;
-+ continue;
-+ }
-+
-+ mmc_decode_csd(&card->csd, cmd.resp);
-+ }
-+}
-+
-+static unsigned int mmc_calculate_clock(struct mmc_host *host)
-+{
-+ struct mmc_card *card;
-+ unsigned int max_dtr = host->f_max;
-+
-+ list_for_each_entry(card, &host->cards, node)
-+ if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr)
-+ max_dtr = card->csd.max_dtr;
-+
-+ DBG("MMC: selected %d.%03dMHz transfer rate\n",
-+ max_dtr / 1000000, (max_dtr / 1000) % 1000);
-+
-+ return max_dtr;
-+}
-+
-+/*
-+ * Check whether cards we already know about are still present.
-+ * We do this by requesting status, and checking whether a card
-+ * responds.
-+ *
-+ * A request for status does not cause a state change in data
-+ * transfer mode.
-+ */
-+static void mmc_check_cards(struct mmc_host *host)
-+{
-+ struct list_head *l, *n;
-+
-+ mmc_deselect_cards(host);
-+
-+ list_for_each_safe(l, n, &host->cards) {
-+ struct mmc_card *card = mmc_list_to_card(l);
-+ struct mmc_command cmd;
-+ int err;
-+
-+ cmd.opcode = MMC_SEND_STATUS;
-+ cmd.arg = card->rca << 16;
-+ cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
-+
-+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-+ if (err == MMC_ERR_NONE)
-+ continue;
-+
-+ /*
-+ * Ok, we believe this card has been removed.
-+ */
-+ card->state |= MMC_STATE_DEAD;
-+ }
-+}
-+
-+static void mmc_setup(struct mmc_host *host)
-+{
-+ if (host->ios.power_mode != MMC_POWER_ON) {
-+ int err;
-+ u32 ocr;
-+
-+ mmc_power_up(host);
-+
-+ err = mmc_send_op_cond(host, 0, &ocr);
-+ if (err != MMC_ERR_NONE)
-+ return;
-+
-+ host->ocr = mmc_select_voltage(host, ocr);
-+ } else {
-+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-+ host->ios.clock = host->f_min;
-+ host->ops->set_ios(host, &host->ios);
-+
-+ /*
-+ * We should remember the OCR mask from the existing
-+ * cards, and detect the new cards OCR mask, combine
-+ * the two and re-select the VDD. However, if we do
-+ * change VDD, we should do an idle, and then do a
-+ * full re-initialisation. We would need to notify
-+ * drivers so that they can re-setup the cards as
-+ * well, while keeping their queues at bay.
-+ *
-+ * For the moment, we take the easy way out - if the
-+ * new cards don't like our currently selected VDD,
-+ * they drop off the bus.
-+ */
-+ }
-+
-+ if (host->ocr == 0)
-+ return;
-+
-+ /*
-+ * Send the selected OCR multiple times... until the cards
-+ * all get the idea that they should be ready for CMD2.
-+ * (My SanDisk card seems to need this.)
-+ */
-+ mmc_send_op_cond(host, host->ocr, NULL);
-+
-+ mmc_discover_cards(host);
-+
-+ /*
-+ * Ok, now switch to push-pull mode.
-+ */
-+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
-+ host->ops->set_ios(host, &host->ios);
-+
-+ mmc_read_csds(host);
-+}
-+
-+
-+/**
-+ * mmc_detect_change - process change of state on a MMC socket
-+ * @host: host which changed state.
-+ *
-+ * All we know is that card(s) have been inserted or removed
-+ * from the socket(s). We don't know which socket or cards.
-+ */
-+void mmc_detect_change(struct mmc_host *host)
-+{
-+ struct list_head *l, *n;
-+
-+ mmc_claim_host(host);
-+
-+ if (host->ios.power_mode == MMC_POWER_ON)
-+ mmc_check_cards(host);
-+
-+ mmc_setup(host);
-+
-+ if (!list_empty(&host->cards)) {
-+ /*
-+ * (Re-)calculate the fastest clock rate which the
-+ * attached cards and the host support.
-+ */
-+ host->ios.clock = mmc_calculate_clock(host);
-+ host->ops->set_ios(host, &host->ios);
-+ }
-+
-+ mmc_release_host(host);
-+
-+ list_for_each_safe(l, n, &host->cards) {
-+ struct mmc_card *card = mmc_list_to_card(l);
-+
-+ /*
-+ * If this is a new and good card, register it.
-+ */
-+ if (!mmc_card_present(card) && !mmc_card_dead(card)) {
-+ if (mmc_register_card(card))
-+ card->state |= MMC_STATE_DEAD;
-+ else
-+ card->state |= MMC_STATE_PRESENT;
-+ }
-+
-+ /*
-+ * If this card is dead, destroy it.
-+ */
-+ if (mmc_card_dead(card)) {
-+ list_del(&card->node);
-+ mmc_remove_card(card);
-+ }
-+ }
-+
-+ /*
-+ * If we discover that there are no cards on the
-+ * bus, turn off the clock and power down.
-+ */
-+ if (list_empty(&host->cards))
-+ mmc_power_off(host);
-+}
-+
-+EXPORT_SYMBOL(mmc_detect_change);
-+
-+
-+/**
-+ * mmc_init_host - initialise the per-host structure.
-+ * @host: mmc host
-+ *
-+ * Initialise the per-host structure.
-+ */
-+int mmc_init_host(struct mmc_host *host)
-+{
-+ static unsigned int host_num;
-+
-+ memset(host, 0, sizeof(struct mmc_host));
-+
-+ host->host_num = host_num++;
-+
-+ spin_lock_init(&host->lock);
-+ init_waitqueue_head(&host->wq);
-+ INIT_LIST_HEAD(&host->cards);
-+
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(mmc_init_host);
-+
-+/**
-+ * mmc_add_host - initialise host hardware
-+ * @host: mmc host
-+ */
-+int mmc_add_host(struct mmc_host *host)
-+{
-+ mmc_power_off(host);
-+ mmc_detect_change(host);
-+
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(mmc_add_host);
-+
-+/**
-+ * mmc_remove_host - remove host hardware
-+ * @host: mmc host
-+ *
-+ * Unregister and remove all cards associated with this host,
-+ * and power down the MMC bus.
-+ */
-+void mmc_remove_host(struct mmc_host *host)
-+{
-+ struct list_head *l, *n;
-+
-+ list_for_each_safe(l, n, &host->cards) {
-+ struct mmc_card *card = mmc_list_to_card(l);
-+
-+ mmc_remove_card(card);
-+ }
-+
-+ mmc_power_off(host);
-+}
-+
-+EXPORT_SYMBOL(mmc_remove_host);
-+
-+#ifdef CONFIG_PM
-+
-+/**
-+ * mmc_suspend_host - suspend a host
-+ * @host: mmc host
-+ * @state: suspend mode (PM_SUSPEND_xxx)
-+ */
-+int mmc_suspend_host(struct mmc_host *host, u32 state)
-+{
-+ mmc_claim_host(host);
-+ mmc_deselect_cards(host);
-+ mmc_power_off(host);
-+ mmc_release_host(host);
-+
-+ return 0;
-+}
-+
-+/**
-+ * mmc_resume_host - resume a previously suspended host
-+ * @host: mmc host
-+ */
-+int mmc_resume_host(struct mmc_host *host)
-+{
-+ mmc_detect_change(host);
-+
-+ return 0;
-+}
-+
-+
-+#else /* CONFIG_PM is not set */
-+
-+int mmc_suspend_host(struct mmc_host *host, u32 state) { return 0; }
-+int mmc_resume_host(struct mmc_host *host) { return 0; }
-+
-+#endif
-+
-+EXPORT_SYMBOL(mmc_suspend_host);
-+EXPORT_SYMBOL(mmc_resume_host);
-+
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/media/mmc/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,21 @@
-+#
-+# Makefile for the kernel mmc device drivers.
-+#
-+
-+#
-+# Core
-+#
-+obj-$(CONFIG_MMC) += mmc_core.o
-+
-+#
-+# Media drivers
-+#
-+obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
-+
-+#
-+# Host drivers
-+#
-+obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
-+obj-$(CONFIG_MMC_PXA) += pxamci.o
-+
-+mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
---- linux-2.6.5/drivers/media/Makefile~heh 2004-04-03 22:38:15.000000000 -0500
-+++ linux-2.6.5/drivers/media/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -3,3 +3,6 @@
- #
-
- obj-y := video/ radio/ dvb/ common/
-+
-+obj-$(CONFIG_MMC) += mmc/
-+
---- linux-2.6.5/drivers/serial/Kconfig~heh 2004-04-03 22:38:15.000000000 -0500
-+++ linux-2.6.5/drivers/serial/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -315,6 +315,29 @@
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time.)
-
-+config SERIAL_PXA
-+ bool "PXA serial port support"
-+ depends on ARM && ARCH_PXA
-+ select SERIAL_CORE
-+ help
-+ If you have a machine based on an Intel XScale PXA2xx CPU you
-+ can enable its onboard serial ports by enabling this option.
-+
-+config SERIAL_PXA_CONSOLE
-+ bool "Console on PXA serial port"
-+ depends on SERIAL_PXA
-+ select SERIAL_CORE_CONSOLE
-+ help
-+ If you have enabled the serial port on the Intel XScale PXA
-+ CPU you can make it the console by answering Y to this option.
-+
-+ Even if you say Y here, the currently visible virtual console
-+ (/dev/tty0) will still be used as the system console by default, but
-+ you can alter that using a kernel command line option such as
-+ "console=ttySA0". (Try "man bootparam" or see the documentation of
-+ your boot loader (lilo or loadlin) about how to pass options to the
-+ kernel at boot time.)
-+
- config SERIAL_SA1100
- bool "SA1100 serial port support"
- depends on ARM && ARCH_SA1100
---- linux-2.6.5/drivers/serial/pxa.c~heh 2004-04-03 22:38:16.000000000 -0500
-+++ linux-2.6.5/drivers/serial/pxa.c 2004-04-30 20:57:36.000000000 -0400
-@@ -294,7 +294,6 @@
- unsigned char status;
- unsigned int ret;
-
--return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
- spin_lock_irqsave(&up->port.lock, flags);
- status = serial_in(up, UART_MSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
-@@ -800,6 +799,21 @@
- .ops = &serial_pxa_pops,
- .line = 2,
- },
-+ }, { /* HWUART */
-+ .name = "HWUART",
-+ .cken = CKEN4_HWUART,
-+ .port = {
-+ .type = PORT_PXA,
-+ .iotype = SERIAL_IO_MEM,
-+ .membase = (void *)&HWUART,
-+ .mapbase = __PREG(HWUART),
-+ .irq = IRQ_HWUART,
-+ .uartclk = 921600 * 16,
-+ .fifosize = 64,
-+ .flags = ASYNC_SKIP_TEST,
-+ .ops = &serial_pxa_pops,
-+ .line = 3,
-+ },
- }
- };
-
---- linux-2.6.5/drivers/serial/sa1100.c~heh 2004-04-03 22:36:24.000000000 -0500
-+++ linux-2.6.5/drivers/serial/sa1100.c 2004-04-30 20:57:36.000000000 -0400
-@@ -448,6 +448,15 @@
- unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
-
- /*
-+ * If we don't support modem control lines, don't allow
-+ * these to be set.
-+ */
-+ if (0) {
-+ termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
-+ termios->c_cflag |= CLOCAL;
-+ }
-+
-+ /*
- * We only support CS7 and CS8.
- */
- while ((termios->c_cflag & CSIZE) != CS7 &&
-@@ -894,6 +903,7 @@
- if (sa1100_ports[i].port.mapbase != res->start)
- continue;
-
-+ sa1100_ports[i].port.dev = _dev;
- uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
- dev_set_drvdata(_dev, &sa1100_ports[i]);
- break;
---- linux-2.6.5/drivers/mtd/mtd_blkdevs.c~heh 2004-04-03 22:36:14.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtd_blkdevs.c 2004-04-30 20:57:36.000000000 -0400
-@@ -81,7 +81,7 @@
- struct request_queue *rq = tr->blkcore_priv->rq;
-
- /* we might get involved when memory gets low, so use PF_MEMALLOC */
-- current->flags |= PF_MEMALLOC;
-+ current->flags |= PF_MEMALLOC|PF_IOTHREAD;
-
- daemonize("%sd", tr->name);
-
---- linux-2.6.5/drivers/mtd/devices/doc1000.c~heh 2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/doc1000.c 2004-04-30 20:57:36.000000000 -0400
-@@ -1,6 +1,6 @@
- /*======================================================================
-
-- $Id$
-+ $Id$
-
- ======================================================================*/
-
-@@ -20,6 +20,7 @@
- #include <linux/ioctl.h>
- #include <asm/io.h>
- #include <asm/system.h>
-+#include <asm/segment.h>
- #include <stdarg.h>
- #include <linux/delay.h>
- #include <linux/init.h>
-@@ -482,7 +483,7 @@
- else
- priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
- }
-- else if (erase->time + erase_timeout < jiffies)
-+ else if (time_after(jiffies, erase->time + erase_timeout))
- {
- printk("Flash erase timed out. The world is broken.\n");
-
---- linux-2.6.5/drivers/mtd/mtdconcat.c~heh 2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtdconcat.c 2004-04-30 20:57:36.000000000 -0400
-@@ -7,7 +7,7 @@
- *
- * This code is GPL
- *
-- * $Id$
-+ * $Id$
- */
-
- #include <linux/module.h>
-@@ -26,7 +26,7 @@
- */
- struct mtd_concat {
- struct mtd_info mtd;
-- int num_subdev;
-+ int num_subdev;
- struct mtd_info **subdev;
- };
-
-@@ -37,21 +37,20 @@
- #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \
- ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
-
--
- /*
- * Given a pointer to the MTD object in the mtd_concat structure,
- * we can retrieve the pointer to that structure with this macro.
- */
- #define CONCAT(x) ((struct mtd_concat *)(x))
-
--
- /*
- * MTD methods which look up the relevant subdevice, translate the
- * effective address and pass through to the subdevice.
- */
-
--static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf)
-+static int
-+concat_read(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -59,43 +58,43 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
-
-- if (from >= subdev->size)
-- { /* Not destined for this subdev */
-- size = 0;
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
- from -= subdev->size;
-+ continue;
- }
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
- else
-- {
-- if (from + len > subdev->size)
-- size = subdev->size - from; /* First part goes into this subdev */
-- else
-- size = len; /* Entire transaction goes into this subdev */
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-
-- err = subdev->read(subdev, from, size, &retsize, buf);
-+ err = subdev->read(subdev, from, size, &retsize, buf);
-
-- if(err)
-- break;
-+ if (err)
-+ break;
-
-- *retlen += retsize;
-- len -= size;
-- if(len == 0)
-- break;
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-
-- err = -EINVAL;
-- buf += size;
-- from = 0;
-- }
-+ err = -EINVAL;
-+ buf += size;
-+ from = 0;
- }
- return err;
- }
-
--static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf)
-+static int
-+concat_write(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -106,46 +105,44 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
-
-- if (to >= subdev->size)
-- {
-- size = 0;
-+ if (to >= subdev->size) {
-+ size = 0;
- to -= subdev->size;
-+ continue;
- }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
- else
-- {
-- if (to + len > subdev->size)
-- size = subdev->size - to;
-- else
-- size = len;
-+ size = len;
-
-- if (!(subdev->flags & MTD_WRITEABLE))
-- err = -EROFS;
-- else
-- err = subdev->write(subdev, to, size, &retsize, buf);
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else
-+ err = subdev->write(subdev, to, size, &retsize, buf);
-
-- if(err)
-- break;
-+ if (err)
-+ break;
-
-- *retlen += retsize;
-- len -= size;
-- if(len == 0)
-- break;
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-
-- err = -EINVAL;
-- buf += size;
-- to = 0;
-- }
-+ err = -EINVAL;
-+ buf += size;
-+ to = 0;
- }
- return err;
- }
-
--static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
-+static int
-+concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf, u_char * eccbuf,
-+ struct nand_oobinfo *oobsel)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -153,53 +150,56 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
--
-- if (from >= subdev->size)
-- { /* Not destined for this subdev */
-- size = 0;
-+
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
- from -= subdev->size;
-+ continue;
- }
-+
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
- else
-- {
-- if (from + len > subdev->size)
-- size = subdev->size - from; /* First part goes into this subdev */
-- else
-- size = len; /* Entire transaction goes into this subdev */
--
-- if (subdev->read_ecc)
-- err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel);
-- else
-- err = -EINVAL;
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-
-- if(err)
-- break;
-+ if (subdev->read_ecc)
-+ err = subdev->read_ecc(subdev, from, size,
-+ &retsize, buf, eccbuf, oobsel);
-+ else
-+ err = -EINVAL;
-
-- *retlen += retsize;
-- len -= size;
-- if(len == 0)
-- break;
-+ if (err)
-+ break;
-
-- err = -EINVAL;
-- buf += size;
-- if (eccbuf)
-- {
-- eccbuf += subdev->oobsize;
-- /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus',
-- we must account for these */
-- eccbuf += 2 * (sizeof(int));
-- }
-- from = 0;
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ if (eccbuf) {
-+ eccbuf += subdev->oobsize;
-+ /* in nand.c at least, eccbufs are
-+ tagged with 2 (int)eccstatus'; we
-+ must account for these */
-+ eccbuf += 2 * (sizeof (int));
- }
-+ from = 0;
- }
- return err;
- }
-
--static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
-+static int
-+concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf, u_char * eccbuf,
-+ struct nand_oobinfo *oobsel)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -210,50 +210,48 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
--
-- if (to >= subdev->size)
-- {
-- size = 0;
-+
-+ if (to >= subdev->size) {
-+ size = 0;
- to -= subdev->size;
-+ continue;
- }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
- else
-- {
-- if (to + len > subdev->size)
-- size = subdev->size - to;
-- else
-- size = len;
-+ size = len;
-
-- if (!(subdev->flags & MTD_WRITEABLE))
-- err = -EROFS;
-- else if (subdev->write_ecc)
-- err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel);
-- else
-- err = -EINVAL;
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else if (subdev->write_ecc)
-+ err = subdev->write_ecc(subdev, to, size,
-+ &retsize, buf, eccbuf, oobsel);
-+ else
-+ err = -EINVAL;
-
-- if(err)
-- break;
-+ if (err)
-+ break;
-
-- *retlen += retsize;
-- len -= size;
-- if(len == 0)
-- break;
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-
-- err = -EINVAL;
-- buf += size;
-- if (eccbuf)
-- eccbuf += subdev->oobsize;
-- to = 0;
-- }
-+ err = -EINVAL;
-+ buf += size;
-+ if (eccbuf)
-+ eccbuf += subdev->oobsize;
-+ to = 0;
- }
- return err;
- }
-
--static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-- size_t *retlen, u_char *buf)
-+static int
-+concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-+ size_t * retlen, u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -261,46 +259,47 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
--
-- if (from >= subdev->size)
-- { /* Not destined for this subdev */
-- size = 0;
-+
-+ if (from >= subdev->size) {
-+ /* Not destined for this subdev */
-+ size = 0;
- from -= subdev->size;
-+ continue;
- }
-+ if (from + len > subdev->size)
-+ /* First part goes into this subdev */
-+ size = subdev->size - from;
- else
-- {
-- if (from + len > subdev->size)
-- size = subdev->size - from; /* First part goes into this subdev */
-- else
-- size = len; /* Entire transaction goes into this subdev */
--
-- if (subdev->read_oob)
-- err = subdev->read_oob(subdev, from, size, &retsize, buf);
-- else
-- err = -EINVAL;
-+ /* Entire transaction goes into this subdev */
-+ size = len;
-
-- if(err)
-- break;
-+ if (subdev->read_oob)
-+ err = subdev->read_oob(subdev, from, size,
-+ &retsize, buf);
-+ else
-+ err = -EINVAL;
-
-- *retlen += retsize;
-- len -= size;
-- if(len == 0)
-- break;
-+ if (err)
-+ break;
-
-- err = -EINVAL;
-- buf += size;
-- from = 0;
-- }
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-+
-+ err = -EINVAL;
-+ buf += size;
-+ from = 0;
- }
- return err;
- }
-
--static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-- size_t *retlen, const u_char *buf)
-+static int
-+concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-+ size_t * retlen, const u_char * buf)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
-@@ -311,50 +310,46 @@
-
- *retlen = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size, retsize;
--
-- if (to >= subdev->size)
-- {
-- size = 0;
-+
-+ if (to >= subdev->size) {
-+ size = 0;
- to -= subdev->size;
-+ continue;
- }
-+ if (to + len > subdev->size)
-+ size = subdev->size - to;
- else
-- {
-- if (to + len > subdev->size)
-- size = subdev->size - to;
-- else
-- size = len;
-+ size = len;
-
-- if (!(subdev->flags & MTD_WRITEABLE))
-- err = -EROFS;
-- else if (subdev->write_oob)
-- err = subdev->write_oob(subdev, to, size, &retsize, buf);
-- else
-- err = -EINVAL;
-+ if (!(subdev->flags & MTD_WRITEABLE))
-+ err = -EROFS;
-+ else if (subdev->write_oob)
-+ err = subdev->write_oob(subdev, to, size, &retsize,
-+ buf);
-+ else
-+ err = -EINVAL;
-
-- if(err)
-- break;
-+ if (err)
-+ break;
-
-- *retlen += retsize;
-- len -= size;
-- if(len == 0)
-- break;
-+ *retlen += retsize;
-+ len -= size;
-+ if (len == 0)
-+ break;
-
-- err = -EINVAL;
-- buf += size;
-- to = 0;
-- }
-+ err = -EINVAL;
-+ buf += size;
-+ to = 0;
- }
- return err;
- }
-
--
--static void concat_erase_callback (struct erase_info *instr)
-+static void concat_erase_callback(struct erase_info *instr)
- {
-- wake_up((wait_queue_head_t *)instr->priv);
-+ wake_up((wait_queue_head_t *) instr->priv);
- }
-
- static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
-@@ -370,18 +365,18 @@
-
- erase->mtd = mtd;
- erase->callback = concat_erase_callback;
-- erase->priv = (unsigned long)&waitq;
--
-+ erase->priv = (unsigned long) &waitq;
-+
- /*
- * FIXME: Allow INTERRUPTIBLE. Which means
- * not having the wait_queue head on the stack.
- */
- err = mtd->erase(mtd, erase);
-- if (!err)
-- {
-+ if (!err) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&waitq, &wait);
-- if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
-+ if (erase->state != MTD_ERASE_DONE
-+ && erase->state != MTD_ERASE_FAILED)
- schedule();
- remove_wait_queue(&waitq, &wait);
- set_current_state(TASK_RUNNING);
-@@ -391,7 +386,7 @@
- return err;
- }
-
--static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
-+static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- struct mtd_info *subdev;
-@@ -402,10 +397,10 @@
- if (!(mtd->flags & MTD_WRITEABLE))
- return -EROFS;
-
-- if(instr->addr > concat->mtd.size)
-+ if (instr->addr > concat->mtd.size)
- return -EINVAL;
-
-- if(instr->len + instr->addr > concat->mtd.size)
-+ if (instr->len + instr->addr > concat->mtd.size)
- return -EINVAL;
-
- /*
-@@ -414,23 +409,22 @@
- * region info rather than looking at each particular sub-device
- * in turn.
- */
-- if (!concat->mtd.numeraseregions)
-- { /* the easy case: device has uniform erase block size */
-- if(instr->addr & (concat->mtd.erasesize - 1))
-+ if (!concat->mtd.numeraseregions) {
-+ /* the easy case: device has uniform erase block size */
-+ if (instr->addr & (concat->mtd.erasesize - 1))
- return -EINVAL;
-- if(instr->len & (concat->mtd.erasesize - 1))
-+ if (instr->len & (concat->mtd.erasesize - 1))
- return -EINVAL;
-- }
-- else
-- { /* device has variable erase size */
-- struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
-+ } else {
-+ /* device has variable erase size */
-+ struct mtd_erase_region_info *erase_regions =
-+ concat->mtd.eraseregions;
-
- /*
- * Find the erase region where the to-be-erased area begins:
- */
-- for(i = 0; i < concat->mtd.numeraseregions &&
-- instr->addr >= erase_regions[i].offset; i++)
-- ;
-+ for (i = 0; i < concat->mtd.numeraseregions &&
-+ instr->addr >= erase_regions[i].offset; i++) ;
- --i;
-
- /*
-@@ -438,25 +432,26 @@
- * to-be-erased area begins. Verify that the starting
- * offset is aligned to this region's erase size:
- */
-- if (instr->addr & (erase_regions[i].erasesize-1))
-+ if (instr->addr & (erase_regions[i].erasesize - 1))
- return -EINVAL;
-
- /*
- * now find the erase region where the to-be-erased area ends:
- */
-- for(; i < concat->mtd.numeraseregions &&
-- (instr->addr + instr->len) >= erase_regions[i].offset ; ++i)
-- ;
-+ for (; i < concat->mtd.numeraseregions &&
-+ (instr->addr + instr->len) >= erase_regions[i].offset;
-+ ++i) ;
- --i;
- /*
- * check if the ending offset is aligned to this region's erase size
- */
-- if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
-+ if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
-+ 1))
- return -EINVAL;
- }
-
- /* make a local copy of instr to avoid modifying the caller's struct */
-- erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
-+ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
-
- if (!erase)
- return -ENOMEM;
-@@ -468,39 +463,40 @@
- * find the subdevice where the to-be-erased area begins, adjust
- * starting offset to be relative to the subdevice start
- */
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- subdev = concat->subdev[i];
-- if(subdev->size <= erase->addr)
-+ if (subdev->size <= erase->addr)
- erase->addr -= subdev->size;
- else
- break;
-- }
-- if(i >= concat->num_subdev) /* must never happen since size */
-- BUG(); /* limit has been verified above */
-+ }
-+
-+ /* must never happen since size limit has been verified above */
-+ if (i >= concat->num_subdev)
-+ BUG();
-
- /* now do the erase: */
- err = 0;
-- for(;length > 0; i++) /* loop for all subevices affected by this request */
-- {
-- subdev = concat->subdev[i]; /* get current subdevice */
-+ for (; length > 0; i++) {
-+ /* loop for all subdevices affected by this request */
-+ subdev = concat->subdev[i]; /* get current subdevice */
-
- /* limit length to subdevice's size: */
-- if(erase->addr + length > subdev->size)
-+ if (erase->addr + length > subdev->size)
- erase->len = subdev->size - erase->addr;
- else
- erase->len = length;
-
-- if (!(subdev->flags & MTD_WRITEABLE))
-- {
-+ if (!(subdev->flags & MTD_WRITEABLE)) {
- err = -EROFS;
- break;
- }
- length -= erase->len;
-- if ((err = concat_dev_erase(subdev, erase)))
-- {
-- if(err == -EINVAL) /* sanity check: must never happen since */
-- BUG(); /* block alignment has been checked above */
-+ if ((err = concat_dev_erase(subdev, erase))) {
-+ /* sanity check: should never happen since
-+ * block alignment has been checked above */
-+ if (err == -EINVAL)
-+ BUG();
- break;
- }
- /*
-@@ -523,85 +519,79 @@
- return 0;
- }
-
--static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int i, err = -EINVAL;
-
-- if ((len + ofs) > mtd->size)
-+ if ((len + ofs) > mtd->size)
- return -EINVAL;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size;
-
-- if (ofs >= subdev->size)
-- {
-- size = 0;
-+ if (ofs >= subdev->size) {
-+ size = 0;
- ofs -= subdev->size;
-+ continue;
- }
-+ if (ofs + len > subdev->size)
-+ size = subdev->size - ofs;
- else
-- {
-- if (ofs + len > subdev->size)
-- size = subdev->size - ofs;
-- else
-- size = len;
-+ size = len;
-
-- err = subdev->lock(subdev, ofs, size);
-+ err = subdev->lock(subdev, ofs, size);
-
-- if(err)
-- break;
-+ if (err)
-+ break;
-
-- len -= size;
-- if(len == 0)
-- break;
-+ len -= size;
-+ if (len == 0)
-+ break;
-
-- err = -EINVAL;
-- ofs = 0;
-- }
-+ err = -EINVAL;
-+ ofs = 0;
- }
-+
- return err;
- }
-
--static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- struct mtd_concat *concat = CONCAT(mtd);
- int i, err = 0;
-
-- if ((len + ofs) > mtd->size)
-+ if ((len + ofs) > mtd->size)
- return -EINVAL;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- size_t size;
-
-- if (ofs >= subdev->size)
-- {
-- size = 0;
-+ if (ofs >= subdev->size) {
-+ size = 0;
- ofs -= subdev->size;
-+ continue;
- }
-+ if (ofs + len > subdev->size)
-+ size = subdev->size - ofs;
- else
-- {
-- if (ofs + len > subdev->size)
-- size = subdev->size - ofs;
-- else
-- size = len;
-+ size = len;
-
-- err = subdev->unlock(subdev, ofs, size);
-+ err = subdev->unlock(subdev, ofs, size);
-
-- if(err)
-- break;
-+ if (err)
-+ break;
-
-- len -= size;
-- if(len == 0)
-- break;
-+ len -= size;
-+ if (len == 0)
-+ break;
-
-- err = -EINVAL;
-- ofs = 0;
-- }
-+ err = -EINVAL;
-+ ofs = 0;
- }
-+
- return err;
- }
-
-@@ -610,8 +600,7 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- subdev->sync(subdev);
- }
-@@ -622,10 +611,9 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i, rc = 0;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
-- if((rc = subdev->suspend(subdev)) < 0)
-+ if ((rc = subdev->suspend(subdev)) < 0)
- return rc;
- }
- return rc;
-@@ -636,8 +624,7 @@
- struct mtd_concat *concat = CONCAT(mtd);
- int i;
-
-- for(i = 0; i < concat->num_subdev; i++)
-- {
-+ for (i = 0; i < concat->num_subdev; i++) {
- struct mtd_info *subdev = concat->subdev[i];
- subdev->resume(subdev);
- }
-@@ -649,11 +636,10 @@
- * stored to *new_dev upon success. This function does _not_
- * register any devices: this is the caller's responsibility.
- */
--struct mtd_info *mtd_concat_create(
-- struct mtd_info *subdev[], /* subdevices to concatenate */
-- int num_devs, /* number of subdevices */
-- char *name) /* name for the new device */
--{
-+struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */
-+ int num_devs, /* number of subdevices */
-+ char *name)
-+{ /* name for the new device */
- int i;
- size_t size;
- struct mtd_concat *concat;
-@@ -661,94 +647,103 @@
- int num_erase_region;
-
- printk(KERN_NOTICE "Concatenating MTD devices:\n");
-- for(i = 0; i < num_devs; i++)
-+ for (i = 0; i < num_devs; i++)
- printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
- printk(KERN_NOTICE "into device \"%s\"\n", name);
-
- /* allocate the device structure */
- size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
-- concat = kmalloc (size, GFP_KERNEL);
-- if(!concat)
-- {
-- printk ("memory allocation error while creating concatenated device \"%s\"\n",
-- name);
-- return NULL;
-+ concat = kmalloc(size, GFP_KERNEL);
-+ if (!concat) {
-+ printk
-+ ("memory allocation error while creating concatenated device \"%s\"\n",
-+ name);
-+ return NULL;
- }
- memset(concat, 0, size);
-- concat->subdev = (struct mtd_info **)(concat + 1);
-+ concat->subdev = (struct mtd_info **) (concat + 1);
-
- /*
- * Set up the new "super" device's MTD object structure, check for
- * incompatibilites between the subdevices.
- */
-- concat->mtd.type = subdev[0]->type;
-- concat->mtd.flags = subdev[0]->flags;
-- concat->mtd.size = subdev[0]->size;
-+ concat->mtd.type = subdev[0]->type;
-+ concat->mtd.flags = subdev[0]->flags;
-+ concat->mtd.size = subdev[0]->size;
- concat->mtd.erasesize = subdev[0]->erasesize;
-- concat->mtd.oobblock = subdev[0]->oobblock;
-- concat->mtd.oobsize = subdev[0]->oobsize;
-- concat->mtd.ecctype = subdev[0]->ecctype;
-- concat->mtd.eccsize = subdev[0]->eccsize;
-+ concat->mtd.oobblock = subdev[0]->oobblock;
-+ concat->mtd.oobsize = subdev[0]->oobsize;
-+ concat->mtd.ecctype = subdev[0]->ecctype;
-+ concat->mtd.eccsize = subdev[0]->eccsize;
-+ if (subdev[0]->read_ecc)
-+ concat->mtd.read_ecc = concat_read_ecc;
-+ if (subdev[0]->write_ecc)
-+ concat->mtd.write_ecc = concat_write_ecc;
-+ if (subdev[0]->read_oob)
-+ concat->mtd.read_oob = concat_read_oob;
-+ if (subdev[0]->write_oob)
-+ concat->mtd.write_oob = concat_write_oob;
-
-- concat->subdev[0] = subdev[0];
-+ concat->subdev[0] = subdev[0];
-
-- for(i = 1; i < num_devs; i++)
-- {
-- if(concat->mtd.type != subdev[i]->type)
-- {
-+ for (i = 1; i < num_devs; i++) {
-+ if (concat->mtd.type != subdev[i]->type) {
- kfree(concat);
-- printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible device type on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
- }
-- if(concat->mtd.flags != subdev[i]->flags)
-- { /*
-- * Expect all flags except MTD_WRITEABLE to be equal on
-- * all subdevices.
-+ if (concat->mtd.flags != subdev[i]->flags) {
-+ /*
-+ * Expect all flags except MTD_WRITEABLE to be
-+ * equal on all subdevices.
- */
-- if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
-- {
-+ if ((concat->mtd.flags ^ subdev[i]->
-+ flags) & ~MTD_WRITEABLE) {
- kfree(concat);
-- printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible device flags on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
-- }
-- else /* if writeable attribute differs, make super device writeable */
-- concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
-+ } else
-+ /* if writeable attribute differs,
-+ make super device writeable */
-+ concat->mtd.flags |=
-+ subdev[i]->flags & MTD_WRITEABLE;
- }
- concat->mtd.size += subdev[i]->size;
-- if(concat->mtd.oobblock != subdev[i]->oobblock ||
-- concat->mtd.oobsize != subdev[i]->oobsize ||
-- concat->mtd.ecctype != subdev[i]->ecctype ||
-- concat->mtd.eccsize != subdev[i]->eccsize)
-- {
-+ if (concat->mtd.oobblock != subdev[i]->oobblock ||
-+ concat->mtd.oobsize != subdev[i]->oobsize ||
-+ concat->mtd.ecctype != subdev[i]->ecctype ||
-+ concat->mtd.eccsize != subdev[i]->eccsize ||
-+ !concat->mtd.read_ecc != !subdev[i]->read_ecc ||
-+ !concat->mtd.write_ecc != !subdev[i]->write_ecc ||
-+ !concat->mtd.read_oob != !subdev[i]->read_oob ||
-+ !concat->mtd.write_oob != !subdev[i]->write_oob) {
- kfree(concat);
-- printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
-+ printk("Incompatible OOB or ECC data on \"%s\"\n",
-+ subdev[i]->name);
- return NULL;
- }
- concat->subdev[i] = subdev[i];
--
-+
- }
-
-- concat->num_subdev = num_devs;
-- concat->mtd.name = name;
-+ concat->num_subdev = num_devs;
-+ concat->mtd.name = name;
-
- /*
- * NOTE: for now, we do not provide any readv()/writev() methods
- * because they are messy to implement and they are not
- * used to a great extent anyway.
- */
-- concat->mtd.erase = concat_erase;
-- concat->mtd.read = concat_read;
-- concat->mtd.write = concat_write;
-- concat->mtd.read_ecc = concat_read_ecc;
-- concat->mtd.write_ecc = concat_write_ecc;
-- concat->mtd.read_oob = concat_read_oob;
-- concat->mtd.write_oob = concat_write_oob;
-- concat->mtd.sync = concat_sync;
-- concat->mtd.lock = concat_lock;
-- concat->mtd.unlock = concat_unlock;
-- concat->mtd.suspend = concat_suspend;
-- concat->mtd.resume = concat_resume;
--
-+ concat->mtd.erase = concat_erase;
-+ concat->mtd.read = concat_read;
-+ concat->mtd.write = concat_write;
-+ concat->mtd.sync = concat_sync;
-+ concat->mtd.lock = concat_lock;
-+ concat->mtd.unlock = concat_unlock;
-+ concat->mtd.suspend = concat_suspend;
-+ concat->mtd.resume = concat_resume;
-
- /*
- * Combine the erase block size info of the subdevices:
-@@ -758,44 +753,44 @@
- */
- max_erasesize = curr_erasesize = subdev[0]->erasesize;
- num_erase_region = 1;
-- for(i = 0; i < num_devs; i++)
-- {
-- if(subdev[i]->numeraseregions == 0)
-- { /* current subdevice has uniform erase size */
-- if(subdev[i]->erasesize != curr_erasesize)
-- { /* if it differs from the last subdevice's erase size, count it */
-+ for (i = 0; i < num_devs; i++) {
-+ if (subdev[i]->numeraseregions == 0) {
-+ /* current subdevice has uniform erase size */
-+ if (subdev[i]->erasesize != curr_erasesize) {
-+ /* if it differs from the last subdevice's erase size, count it */
- ++num_erase_region;
- curr_erasesize = subdev[i]->erasesize;
-- if(curr_erasesize > max_erasesize)
-+ if (curr_erasesize > max_erasesize)
- max_erasesize = curr_erasesize;
- }
-- }
-- else
-- { /* current subdevice has variable erase size */
-+ } else {
-+ /* current subdevice has variable erase size */
- int j;
-- for(j = 0; j < subdev[i]->numeraseregions; j++)
-- { /* walk the list of erase regions, count any changes */
-- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
-- {
-+ for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+
-+ /* walk the list of erase regions, count any changes */
-+ if (subdev[i]->eraseregions[j].erasesize !=
-+ curr_erasesize) {
- ++num_erase_region;
-- curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-- if(curr_erasesize > max_erasesize)
-+ curr_erasesize =
-+ subdev[i]->eraseregions[j].
-+ erasesize;
-+ if (curr_erasesize > max_erasesize)
- max_erasesize = curr_erasesize;
- }
- }
- }
- }
-
-- if(num_erase_region == 1)
-- { /*
-+ if (num_erase_region == 1) {
-+ /*
- * All subdevices have the same uniform erase size.
- * This is easy:
- */
- concat->mtd.erasesize = curr_erasesize;
- concat->mtd.numeraseregions = 0;
-- }
-- else
-- { /*
-+ } else {
-+ /*
- * erase block size varies across the subdevices: allocate
- * space to store the data describing the variable erase regions
- */
-@@ -804,13 +799,14 @@
-
- concat->mtd.erasesize = max_erasesize;
- concat->mtd.numeraseregions = num_erase_region;
-- concat->mtd.eraseregions = erase_region_p = kmalloc (
-- num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-- if(!erase_region_p)
-- {
-+ concat->mtd.eraseregions = erase_region_p =
-+ kmalloc(num_erase_region *
-+ sizeof (struct mtd_erase_region_info), GFP_KERNEL);
-+ if (!erase_region_p) {
- kfree(concat);
-- printk ("memory allocation error while creating erase region list"
-- " for device \"%s\"\n", name);
-+ printk
-+ ("memory allocation error while creating erase region list"
-+ " for device \"%s\"\n", name);
- return NULL;
- }
-
-@@ -820,46 +816,53 @@
- */
- curr_erasesize = subdev[0]->erasesize;
- begin = position = 0;
-- for(i = 0; i < num_devs; i++)
-- {
-- if(subdev[i]->numeraseregions == 0)
-- { /* current subdevice has uniform erase size */
-- if(subdev[i]->erasesize != curr_erasesize)
-- { /*
-+ for (i = 0; i < num_devs; i++) {
-+ if (subdev[i]->numeraseregions == 0) {
-+ /* current subdevice has uniform erase size */
-+ if (subdev[i]->erasesize != curr_erasesize) {
-+ /*
- * fill in an mtd_erase_region_info structure for the area
- * we have walked so far:
- */
-- erase_region_p->offset = begin;
-- erase_region_p->erasesize = curr_erasesize;
-- erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+ erase_region_p->offset = begin;
-+ erase_region_p->erasesize =
-+ curr_erasesize;
-+ erase_region_p->numblocks =
-+ (position - begin) / curr_erasesize;
- begin = position;
-
- curr_erasesize = subdev[i]->erasesize;
- ++erase_region_p;
- }
- position += subdev[i]->size;
-- }
-- else
-- { /* current subdevice has variable erase size */
-+ } else {
-+ /* current subdevice has variable erase size */
- int j;
-- for(j = 0; j < subdev[i]->numeraseregions; j++)
-- { /* walk the list of erase regions, count any changes */
-- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
-- {
-- erase_region_p->offset = begin;
-- erase_region_p->erasesize = curr_erasesize;
-- erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+ for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+ /* walk the list of erase regions, count any changes */
-+ if (subdev[i]->eraseregions[j].
-+ erasesize != curr_erasesize) {
-+ erase_region_p->offset = begin;
-+ erase_region_p->erasesize =
-+ curr_erasesize;
-+ erase_region_p->numblocks =
-+ (position -
-+ begin) / curr_erasesize;
- begin = position;
-
-- curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-+ curr_erasesize =
-+ subdev[i]->eraseregions[j].
-+ erasesize;
- ++erase_region_p;
- }
-- position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
-+ position +=
-+ subdev[i]->eraseregions[j].
-+ numblocks * curr_erasesize;
- }
- }
- }
- /* Now write the final entry */
-- erase_region_p->offset = begin;
-+ erase_region_p->offset = begin;
- erase_region_p->erasesize = curr_erasesize;
- erase_region_p->numblocks = (position - begin) / curr_erasesize;
- }
-@@ -874,16 +877,14 @@
- void mtd_concat_destroy(struct mtd_info *mtd)
- {
- struct mtd_concat *concat = CONCAT(mtd);
-- if(concat->mtd.numeraseregions)
-+ if (concat->mtd.numeraseregions)
- kfree(concat->mtd.eraseregions);
- kfree(concat);
- }
-
--
- EXPORT_SYMBOL(mtd_concat_create);
- EXPORT_SYMBOL(mtd_concat_destroy);
-
--
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
- MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
---- linux-2.6.5/drivers/mtd/maps/Makefile~heh 2004-04-03 22:36:12.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -17,12 +17,14 @@
- obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
- obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o
- obj-$(CONFIG_MTD_IQ80310) += iq80310.o
-+obj-$(CONFIG_MTD_IQ80321) += iq80321.o
- obj-$(CONFIG_MTD_L440GX) += l440gx.o
- obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
- obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o
- obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
- obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
- obj-$(CONFIG_MTD_MBX860) += mbx860.o
-+obj-$(CONFIG_MTD_NORA) += nora.o
- obj-$(CONFIG_MTD_CEIVA) += ceiva.o
- obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
- obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
---- linux-2.6.5/drivers/mtd/maps/sa1100-flash.c~heh 2004-04-03 22:36:51.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/sa1100-flash.c 2004-04-30 20:57:36.000000000 -0400
-@@ -14,6 +14,7 @@
- #include <linux/init.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
-+#include <linux/device.h>
-
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-@@ -887,6 +888,7 @@
- int width;
- void *vbase;
- void (*set_vpp)(struct map_info *, int);
-+ char name[16];
- struct map_info *map;
- struct mtd_info *mtd;
- struct resource *res;
-@@ -925,6 +927,8 @@
- }
-
- sa[i].map = maps + i;
-+ sa[i].map->name = sa[i].name;
-+ sprintf(sa[i].name, "sa1100-%d", i);
-
- sa[i].vbase = ioremap(sa[i].base, sa[i].size);
- if (!sa[i].vbase) {
-@@ -986,7 +990,7 @@
- */
- #ifdef CONFIG_MTD_CONCAT
- *rmtd = mtd_concat_create(subdev, found,
-- "sa1100 flash");
-+ "sa1100");
- if (*rmtd == NULL)
- ret = -ENXIO;
- #else
-@@ -1044,13 +1048,9 @@
- * - Is the MSC setup for flash (no -> failure)
- * - Probe for flash
- */
--
--static struct map_info sa1100_probe_map __initdata = {
-- .name = "SA1100-flash",
--};
--
--static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
-+static void sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
- {
-+ struct map_info map;
- struct mtd_info *mtd;
-
- printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
-@@ -1066,19 +1066,23 @@
- return;
- }
-
-- sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
-- sa1100_probe_map.size = SZ_1M;
-- sa1100_probe_map.phys = phys;
-- sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
-- if (sa1100_probe_map.virt == 0)
-+ memset(&map, 0, sizeof(map));
-+
-+ map.name = "Probe";
-+ map.buswidth = msc & MSC_RBW ? 2 : 4;
-+ map.size = SZ_1M;
-+ map.phys = NO_XIP;
-+ map.virt = (unsigned long)ioremap(phys, SZ_1M);
-+ if (map.virt == 0)
- goto fail;
-- simple_map_init(&sa1100_probe_map);
-+
-+ simple_map_init(&map);
-
- /* Shame cfi_probe blurts out kernel messages... */
-- mtd = do_map_probe("cfi_probe", &sa1100_probe_map);
-+ mtd = do_map_probe("cfi_probe", &map);
- if (mtd)
- map_destroy(mtd);
-- iounmap((void *)sa1100_probe_map.virt);
-+ iounmap((void *)map.virt);
-
- if (!mtd)
- goto fail;
-@@ -1090,7 +1094,7 @@
- printk("failed\n");
- }
-
--static void __init sa1100_probe_flash(void)
-+static void sa1100_probe_flash(void)
- {
- printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n");
- sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
-@@ -1321,10 +1325,9 @@
- kfree(parsed_parts);
- }
-
--static struct mtd_info *mymtd;
--
--static int __init sa1100_mtd_init(void)
-+static int __init sa1100_mtd_probe(struct device *dev)
- {
-+ struct mtd_info *mtd;
- int ret;
- int nr;
-
-@@ -1332,21 +1335,74 @@
- if (nr < 0)
- return nr;
-
-- ret = sa1100_setup_mtd(info, nr, &mymtd);
-- if (ret == 0)
-- sa1100_locate_partitions(mymtd);
-+ ret = sa1100_setup_mtd(info, nr, &mtd);
-+ if (ret == 0) {
-+ sa1100_locate_partitions(mtd);
-+ dev_set_drvdata(dev, mtd);
-+ }
-
- return ret;
- }
-
--static void __exit sa1100_mtd_cleanup(void)
-+static int __exit sa1100_mtd_remove(struct device *dev)
- {
-- sa1100_destroy_mtd(info, mymtd);
-+ struct mtd_info *mtd = dev_get_drvdata(dev);
-+ sa1100_destroy_mtd(info, mtd);
- sa1100_destroy_partitions();
-+ return 0;
-+}
-+
-+static int sa1100_mtd_suspend(struct device *dev, u32 level, u32 state)
-+{
-+ struct mtd_info *mtd = dev_get_drvdata(dev);
-+ if (level == SUSPEND_SAVE_STATE)
-+ mtd->suspend(mtd);
-+ return 0;
-+}
-+
-+static int sa1100_mtd_resume(struct device *dev, u32 level)
-+{
-+ struct mtd_info *mtd = dev_get_drvdata(dev);
-+ if (level == RESUME_RESTORE_STATE)
-+ mtd->resume(mtd);
-+ return 0;
-+}
-+
-+static struct platform_device sa1100_mtd_device = {
-+ .name = "flash",
-+ .id = 0,
-+};
-+
-+static struct device_driver sa1100_mtd_driver = {
-+ .name = "flash",
-+ .bus = &platform_bus_type,
-+ .probe = sa1100_mtd_probe,
-+#ifdef MODULE
-+ .remove = sa1100_mtd_remove,
-+#endif
-+ .suspend = sa1100_mtd_suspend,
-+ .resume = sa1100_mtd_resume,
-+};
-+
-+static int __init sa1100_mtd_init(void)
-+{
-+ int ret = driver_register(&sa1100_mtd_driver);
-+ if (ret == 0) {
-+ ret = platform_device_register(&sa1100_mtd_device);
-+ if (ret)
-+ driver_unregister(&sa1100_mtd_driver);
-+ }
-+ return ret;
-+}
-+
-+static void __exit sa1100_mtd_exit(void)
-+{
-+ platform_device_unregister(&sa1100_mtd_device);
-+ driver_unregister(&sa1100_mtd_driver);
- }
-
- module_init(sa1100_mtd_init);
--module_exit(sa1100_mtd_cleanup);
-+module_exit(sa1100_mtd_exit);
-
- MODULE_AUTHOR("Nicolas Pitre");
- MODULE_DESCRIPTION("SA1100 CFI map driver");
---- linux-2.6.5/drivers/mtd/maps/pcmciamtd.c~heh 2004-04-03 22:36:19.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pcmciamtd.c 2004-04-30 20:57:36.000000000 -0400
-@@ -25,10 +25,9 @@
- #include <pcmcia/ds.h>
-
- #include <linux/mtd/map.h>
--#include <linux/mtd/mtd.h>
-
--#ifdef CONFIG_MTD_DEBUG
--static int debug = CONFIG_MTD_DEBUG_VERBOSE;
-+#if 1 //def CONFIG_MTD_DEBUG
-+static int debug = 5; //CONFIG_MTD_DEBUG_VERBOSE;
- MODULE_PARM(debug, "i");
- MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
- #undef DEBUG
-@@ -88,7 +87,7 @@
- static int setvpp;
-
- /* Force card to be treated as FLASH, ROM or RAM */
--static int mem_type;
-+static int mem_type = 1;
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
---- linux-2.6.5/drivers/mtd/maps/pci.c~heh 2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pci.c 2004-04-30 20:57:36.000000000 -0400
-@@ -22,6 +22,8 @@
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-
-+#include <asm/io.h>
-+
- struct map_pci_info;
-
- struct mtd_pci_info {
---- linux-2.6.5/drivers/input/Kconfig~heh 2004-04-03 22:36:18.000000000 -0500
-+++ linux-2.6.5/drivers/input/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -80,7 +80,7 @@
- module will be called joydev.
-
- config INPUT_TSDEV
-- tristate "Touchscreen interface"
-+ tristate "Compaq Touchscreen interface"
- depends on INPUT
- ---help---
- Say Y here if you have an application that only can understand the
-@@ -102,6 +102,10 @@
- depends on INPUT_TSDEV
- default "320"
-
-+config INPUT_TSLIBDEV
-+ tristate "TSLIB Touchscreen interface"
-+ depends on INPUT
-+
- config INPUT_EVDEV
- tristate "Event interface"
- depends on INPUT
---- linux-2.6.5/drivers/input/serio/Kconfig~heh 2004-04-03 22:37:07.000000000 -0500
-+++ linux-2.6.5/drivers/input/serio/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -80,7 +80,7 @@
-
- config SERIO_RPCKBD
- tristate "Acorn RiscPC keyboard controller"
-- depends on ARCH_ACORN && SERIO
-+ depends on (ARCH_ACORN || ARCH_CLPS7500) && SERIO
- default y
- help
- Say Y here if you have the Acorn RiscPC and want to use an AT
-@@ -89,6 +89,18 @@
- To compile this driver as a module, choose M here: the
- module will be called rpckbd.
-
-+config SERIO_CLPS7500
-+ tristate "CLPS7500 PS/2 mouse port controller"
-+ depends on ARCH_CLPS7500 && SERIO
-+ help
-+ Say Y here if you have CLPS7500 based hardware and want to use
-+ the mouse port.
-+
-+ This driver is also available as a module ( = code which can be
-+ inserted in and removed from the running kernel whenever you want).
-+ The module will be called clps7500ps2. If you want to compile it
-+ as a module, say M here and read <file:Documentation/modules.txt>.
-+
- config SERIO_AMBAKMI
- tristate "AMBA KMI keyboard controller"
- depends on ARCH_INTEGRATOR && SERIO
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/input/serio/sa1100ir.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,90 @@
-+/*
-+ * linux/drivers/input/serio/sa1100ir.c
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/serio.h>
-+
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/hardware.h>
-+
-+
-+
-+struct sa1100_kbd {
-+ struct serio io;
-+ void *base;
-+ int irq;
-+};
-+
-+static void sa1100ir_int(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ struct sa1100_kbd *kbd = dev_id;
-+ unsigned int status;
-+
-+ do {
-+ unsigned int flag, data;
-+
-+ status = readl(kbd->base + UTSR1);
-+ if (!(status & UTSR1_RNE))
-+ break;
-+
-+ flag = (status & UTSR1_FRE ? SERIO_FRAME : 0) |
-+ (status & UTSR1_PRE ? SERIO_PARITY : 0);
-+
-+ data = readl(kbd->base + UTDR);
-+
-+ serio_interrupt(&kbd->io, data, flag);
-+ } while (1);
-+
-+ status = readl(kbd->base + UTSR0) & UTSR0_RID | UTSR0_RBB | UTSR0_REB;
-+ if (status)
-+ writel(status, kbd->base + UTSR0);
-+}
-+
-+static int sa1100ir_kbd_open(struct serio *io)
-+{
-+ struct sa1100_kbd *kbd = io->driver;
-+ int ret;
-+
-+ ret = request_irq(kbd->irq, sa1100ir_int, 0, kbd->io.phys, kbd);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static void sa1100ir_kbd_close(struct serio *io)
-+{
-+ struct sa1100_kbd *kbd = io->driver;
-+
-+ free_irq(kbd->irq, kbd);
-+}
-+
-+static struct sa1100_kbd sa1100_kbd = {
-+ .io = {
-+ .type = 0,
-+ .open = sa1100ir_kbd_open,
-+ .close = sa1100ir_kbd_close,
-+ .name = "SA11x0 IR port",
-+ .phys = "sa11x0/ir",
-+ .driver = &sa1100_kbd,
-+ },
-+};
-+
-+static int __init sa1100_kbd_init(void)
-+{
-+ serio_register_port(&sa1100_kbd.io);
-+}
-+
-+static void __exit sa1100_kbd_exit(void)
-+{
-+ serio_unregister_port(&sa1100_kbd.io);
-+}
-+
-+module_init(sa1100_kbd_init);
-+module_exit(sa1100_kbd_exit);
---- linux-2.6.5/drivers/input/serio/Makefile~heh 2004-04-03 22:36:16.000000000 -0500
-+++ linux-2.6.5/drivers/input/serio/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -10,6 +10,7 @@
- obj-$(CONFIG_SERIO_SERPORT) += serport.o
- obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
- obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
-+obj-$(CONFIG_SERIO_CLPS7500) += clps7500ps2.o
- obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
- obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o
- obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/input/tslibdev.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,358 @@
-+/*
-+ * linux/drivers/input/tslibdev.c
-+ *
-+ * Copyright (C) 2002 Russell King
-+ *
-+ * From tsdev.c:
-+ *
-+ * Copyright (c) 2001 "Crazy" james Simmons
-+ *
-+ * Input driver to Touchscreen device driver module.
-+ *
-+ * Sponsored by Transvirtual Technology
-+ */
-+
-+/*
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Should you need to contact me, the author, you can do so either by
-+ * e-mail - mail your message to <jsimmons@transvirtual.com>.
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/poll.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/input.h>
-+#include <linux/config.h>
-+#include <linux/smp_lock.h>
-+#include <linux/random.h>
-+#include <linux/time.h>
-+#include <linux/list.h>
-+#include <linux/miscdevice.h>
-+
-+struct ucb1x00_dev {
-+ int exist;
-+ char name[16];
-+ wait_queue_head_t wait;
-+ struct list_head list;
-+ struct input_handle handle;
-+ int x;
-+ int y;
-+ int pressure;
-+};
-+
-+struct ts_event {
-+ u16 pressure;
-+ u16 x;
-+ u16 y;
-+ u16 pad;
-+ struct timeval stamp;
-+};
-+
-+#define TSDEV_BUFFER_SIZE 64
-+
-+struct ucb1x00_list {
-+ struct list_head list;
-+ struct fasync_struct *fasync;
-+ struct ucb1x00_dev *tsdev;
-+ unsigned int head;
-+ unsigned int tail;
-+ struct ts_event event[TSDEV_BUFFER_SIZE];
-+};
-+
-+static struct input_handler ucb1x00_handler;
-+static struct ucb1x00_dev *ucb1x00_dev;
-+
-+static void ucb1x00_remove(struct ucb1x00_dev *tsdev);
-+
-+
-+static int ucb1x00_fasync(int fd, struct file *file, int on)
-+{
-+ struct ucb1x00_list *list = file->private_data;
-+ int retval;
-+
-+ retval = fasync_helper(fd, file, on, &list->fasync);
-+ return retval < 0 ? retval : 0;
-+}
-+
-+static int ucb1x00_open(struct inode *inode, struct file *file)
-+{
-+ struct ucb1x00_list *list;
-+ int empty;
-+
-+ if (!ucb1x00_dev || !ucb1x00_dev->exist)
-+ return -ENODEV;
-+
-+ printk(KERN_WARNING
-+ "tslibdev: process %s (%d) uses obsolete tslib device\n",
-+ current->comm, current->pid);
-+
-+ list = kmalloc(sizeof(struct ucb1x00_list), GFP_KERNEL);
-+ if (!list)
-+ return -ENOMEM;
-+
-+ memset(list, 0, sizeof(struct ucb1x00_list));
-+
-+ empty = list_empty(&ucb1x00_dev->list);
-+
-+ list->tsdev = ucb1x00_dev;
-+ list_add(&list->list, &list->tsdev->list);
-+
-+ file->private_data = list;
-+
-+ if (empty && list->tsdev->exist)
-+ input_open_device(&list->tsdev->handle);
-+
-+ return 0;
-+}
-+
-+static int ucb1x00_release(struct inode *inode, struct file *file)
-+{
-+ struct ucb1x00_list *list = file->private_data;
-+
-+ ucb1x00_fasync(-1, file, 0);
-+
-+ list_del(&list->list);
-+
-+ ucb1x00_remove(list->tsdev);
-+
-+ kfree(list);
-+
-+ return 0;
-+}
-+
-+static ssize_t
-+ucb1x00_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct ucb1x00_list *list = file->private_data;
-+ int retval = 0;
-+
-+ if (list->head == list->tail) {
-+ add_wait_queue(&list->tsdev->wait, &wait);
-+
-+ while (list->head == list->tail) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+
-+ if (!list->tsdev->exist) {
-+ retval = -ENODEV;
-+ break;
-+ }
-+ if (file->f_flags & O_NONBLOCK) {
-+ retval = -EAGAIN;
-+ break;
-+ }
-+ if (signal_pending(current)) {
-+ retval = -ERESTARTSYS;
-+ break;
-+ }
-+ schedule();
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&list->tsdev->wait, &wait);
-+ }
-+
-+ if (retval)
-+ return retval;
-+
-+ while (list->head != list->tail && count >= sizeof(struct ts_event)) {
-+ if (copy_to_user(buffer, list->event + list->tail,
-+ sizeof(struct ts_event)))
-+ return retval ? retval : -EFAULT;
-+ list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
-+ retval += sizeof(struct ts_event);
-+ buffer += sizeof(struct ts_event);
-+ count -= sizeof(struct ts_event);
-+ }
-+ return retval;
-+}
-+
-+/* No kernel lock - fine */
-+static unsigned int ucb1x00_poll(struct file *file, poll_table * wait)
-+{
-+ struct ucb1x00_list *list = file->private_data;
-+
-+ poll_wait(file, &list->tsdev->wait, wait);
-+ if (list->head != list->tail || !list->tsdev->exist)
-+ return POLLIN | POLLRDNORM;
-+ return 0;
-+}
-+
-+static int
-+ucb1x00_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ return -EINVAL;
-+}
-+
-+struct file_operations ucb1x00_fops = {
-+ .owner = THIS_MODULE,
-+ .open = ucb1x00_open,
-+ .release = ucb1x00_release,
-+ .read = ucb1x00_read,
-+ .poll = ucb1x00_poll,
-+ .fasync = ucb1x00_fasync,
-+ .ioctl = ucb1x00_ioctl,
-+};
-+
-+/*
-+ * The official UCB1x00 touchscreen is a miscdevice:
-+ * 10 char Non-serial mice, misc features
-+ * 14 = /dev/touchscreen/ucb1x00 UCB 1x00 touchscreen
-+ */
-+static struct miscdevice ucb1x00_ts_dev = {
-+ .minor = 14,
-+ .name = "touchscreen/ucb1x00",
-+ .fops = &ucb1x00_fops,
-+ .devfs_name = "touchscreen/ucb1x00",
-+};
-+
-+static void ucb1x00_remove(struct ucb1x00_dev *tsdev)
-+{
-+ if (list_empty(&tsdev->list)) {
-+ if (tsdev->exist) {
-+ input_close_device(&tsdev->handle);
-+ wake_up_interruptible(&tsdev->wait);
-+ } else {
-+ misc_deregister(&ucb1x00_ts_dev);
-+ ucb1x00_dev = NULL;
-+ kfree(tsdev);
-+ }
-+ }
-+}
-+
-+
-+static void
-+ucb1x00_event(struct input_handle *handle, unsigned int type, unsigned int code,
-+ int value)
-+{
-+ struct ucb1x00_dev *tsdev = handle->private;
-+ struct list_head *l;
-+
-+ /* sorry, we only handle absolute stuff */
-+ if (type == EV_ABS) {
-+ switch (code) {
-+ case ABS_X:
-+ tsdev->x = value;
-+ break;
-+ case ABS_Y:
-+ tsdev->y = value;
-+ break;
-+ case ABS_PRESSURE:
-+ tsdev->pressure = value;
-+ break;
-+ }
-+ return;
-+ }
-+
-+ if (type != EV_SYN || code != SYN_REPORT)
-+ return;
-+
-+ list_for_each(l, &tsdev->list) {
-+ struct ucb1x00_list *list = list_entry(l, struct ucb1x00_list, list);
-+ list->event[list->head].pressure = tsdev->pressure;
-+ if (tsdev->pressure) {
-+ list->event[list->head].x = tsdev->x;
-+ list->event[list->head].y = tsdev->y;
-+ } else {
-+ list->event[list->head].x = 0;
-+ list->event[list->head].y = 0;
-+ }
-+ do_gettimeofday(&list->event[list->head].stamp);
-+ list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
-+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
-+ }
-+ wake_up_interruptible(&tsdev->wait);
-+}
-+
-+static struct input_handle *
-+ucb1x00_connect(struct input_handler *handler, struct input_dev *dev,
-+ struct input_device_id *id)
-+{
-+ struct ucb1x00_dev *tsdev;
-+
-+ if (ucb1x00_dev)
-+ return NULL;
-+
-+ tsdev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL);
-+ if (!tsdev)
-+ return NULL;
-+
-+ memset(tsdev, 0, sizeof(struct ucb1x00_dev));
-+ init_waitqueue_head(&tsdev->wait);
-+ INIT_LIST_HEAD(&tsdev->list);
-+
-+ ucb1x00_dev = tsdev;
-+
-+ strcpy(tsdev->name, ucb1x00_ts_dev.name);
-+
-+ tsdev->handle.dev = dev;
-+ tsdev->handle.name = tsdev->name;
-+ tsdev->handle.handler = handler;
-+ tsdev->handle.private = tsdev;
-+
-+ misc_register(&ucb1x00_ts_dev);
-+
-+ tsdev->exist = 1;
-+
-+ return &tsdev->handle;
-+}
-+
-+static void ucb1x00_disconnect(struct input_handle *handle)
-+{
-+ struct ucb1x00_dev *tsdev = handle->private;
-+
-+ tsdev->exist = 0;
-+ ucb1x00_remove(tsdev);
-+}
-+
-+static struct input_device_id ucb1x00_ids[] = {
-+ {
-+ .flags = INPUT_DEVICE_ID_MATCH_ABSBIT,
-+ .evbit = { BIT(EV_ABS) },
-+ .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
-+ },
-+
-+ {},/* Terminating entry */
-+};
-+
-+MODULE_DEVICE_TABLE(input, ucb1x00_ids);
-+
-+static struct input_handler ucb1x00_handler = {
-+ .event = ucb1x00_event,
-+ .connect = ucb1x00_connect,
-+ .disconnect = ucb1x00_disconnect,
-+ .name = "touchscreen/ucb1x00",
-+ .id_table = ucb1x00_ids,
-+};
-+
-+static int __init ucb1x00_init(void)
-+{
-+ input_register_handler(&ucb1x00_handler);
-+ printk(KERN_INFO "ts: UCB1x00 touchscreen protocol output\n");
-+ return 0;
-+}
-+
-+static void __exit ucb1x00_exit(void)
-+{
-+ input_unregister_handler(&ucb1x00_handler);
-+}
-+
-+module_init(ucb1x00_init);
-+module_exit(ucb1x00_exit);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("Input driver to UCB1x00 touchscreen converter");
---- linux-2.6.5/drivers/input/Makefile~heh 2004-04-03 22:38:17.000000000 -0500
-+++ linux-2.6.5/drivers/input/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -8,6 +8,7 @@
- obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
- obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
- obj-$(CONFIG_INPUT_EVDEV) += evdev.o
-+obj-$(CONFIG_INPUT_TSLIBDEV) += tslibdev.o
- obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
- obj-$(CONFIG_INPUT_POWER) += power.o
- obj-$(CONFIG_INPUT_EVBUG) += evbug.o
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/char/sa1100-rtc.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,416 @@
-+/*
-+ * Real Time Clock interface for Linux on Intel SA11x0/PXA2xx
-+ *
-+ * Copyright (c) 2000 Nils Faerber
-+ *
-+ * Based on rtc.c by Paul Gortmaker
-+ * Date/time conversion routines taken from arch/arm/kernel/time.c
-+ * by Linus Torvalds and Russel King
-+ * and the GNU C Library
-+ * ( ... I love the GPL ... just take what you need! ;)
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version
-+ * 2 of the License, or (at your option) any later version.
-+ *
-+ * 1.00 2001-06-08 Nicolas Pitre <nico@cam.org>
-+ * - added periodic timer capability using OSMR1
-+ * - flag compatibility with other RTC chips
-+ * - permission checks for ioctls
-+ * - major cleanup, partial rewrite
-+ *
-+ * 0.03 2001-03-07 CIH <cih@coventive.com>
-+ * - Modify the bug setups RTC clock.
-+ *
-+ * 0.02 2001-02-27 Nils Faerber <nils@@kernelconcepts.de>
-+ * - removed mktime(), added alarm irq clear
-+ *
-+ * 0.01 2000-10-01 Nils Faerber <nils@@kernelconcepts.de>
-+ * - initial release
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/string.h>
-+#include <linux/init.h>
-+#include <linux/poll.h>
-+#include <linux/proc_fs.h>
-+#include <linux/interrupt.h>
-+#include <linux/rtc.h>
-+
-+#include <asm/bitops.h>
-+#include <asm/hardware.h>
-+#include <asm/irq.h>
-+#include <asm/rtc.h>
-+
-+#define TIMER_FREQ 3686400
-+
-+#define RTC_DEF_DIVIDER 32768 - 1
-+#define RTC_DEF_TRIM 0
-+
-+/* Those are the bits from a classic RTC we want to mimic */
-+#define RTC_IRQF 0x80 /* any of the following 3 is active */
-+#define RTC_PF 0x40
-+#define RTC_AF 0x20
-+#define RTC_UF 0x10
-+
-+static unsigned long rtc_freq = 1024;
-+static struct rtc_time rtc_alarm = {
-+ .tm_year = 0,
-+ .tm_mon = 0,
-+ .tm_mday = 0,
-+ .tm_hour = 0,
-+ .tm_mon = 0,
-+ .tm_sec = 0,
-+};
-+
-+extern spinlock_t rtc_lock;
-+
-+static int rtc_update_alarm(struct rtc_time *alrm)
-+{
-+ struct rtc_time alarm_tm, now_tm;
-+ unsigned long now, time;
-+ int ret;
-+
-+ do {
-+ now = RCNR;
-+ rtc_time_to_tm(now, &now_tm);
-+ rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
-+ ret = rtc_tm_to_time(&alarm_tm, &time);
-+ if (ret != 0)
-+ break;
-+
-+ RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
-+ RTAR = time;
-+ } while (now != RCNR);
-+
-+ return ret;
-+}
-+
-+static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ unsigned int rtsr;
-+ unsigned long events = 0;
-+
-+ spin_lock(&rtc_lock);
-+
-+ rtsr = RTSR;
-+ /* clear interrupt sources */
-+ RTSR = 0;
-+ RTSR = (RTSR_AL|RTSR_HZ) & (rtsr >> 2);
-+
-+ /* clear alarm interrupt if it has occurred */
-+ if (rtsr & RTSR_AL)
-+ rtsr &= ~RTSR_ALE;
-+ RTSR = rtsr & (RTSR_ALE|RTSR_HZE);
-+
-+ /* update irq data & counter */
-+ if (rtsr & RTSR_AL)
-+ events |= (RTC_AF|RTC_IRQF);
-+ if (rtsr & RTSR_HZ)
-+ events |= (RTC_UF|RTC_IRQF);
-+
-+ rtc_update(1, events);
-+
-+ if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
-+ rtc_update_alarm(&rtc_alarm);
-+
-+ spin_unlock(&rtc_lock);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+#if 0
-+static unsigned long rtc_irq_data;
-+
-+static irqreturn_t timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ /*
-+ * If we match for the first time, the periodic interrupt flag won't
-+ * be set. If it is, then we did wrap around (very unlikely but
-+ * still possible) and compute the amount of missed periods.
-+ * The match reg is updated only when the data is actually retrieved
-+ * to avoid unnecessary interrupts.
-+ */
-+ OSSR = OSSR_M1; /* clear match on timer1 */
-+ if (rtc_irq_data & RTC_PF) {
-+ rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8;
-+ } else {
-+ rtc_update(1, RTC_PF | RTC_IRQF);
-+ }
-+
-+ wake_up_interruptible(&rtc_wait);
-+ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
-+
-+ return IRQ_HANDLED;
-+}
-+#endif
-+
-+static int sa1100_rtc_open(void)
-+{
-+ int ret;
-+
-+ ret = request_irq(IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL);
-+ if (ret) {
-+ printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
-+ goto fail_ui;
-+ }
-+ ret = request_irq(IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL);
-+ if (ret) {
-+ printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
-+ goto fail_ai;
-+ }
-+#if 0
-+ ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL);
-+ if (ret) {
-+ printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1);
-+ goto fail_pi;
-+ }
-+ rtc_irq_data = 0;
-+#endif
-+ return 0;
-+
-+ fail_pi:
-+ free_irq(IRQ_RTCAlrm, NULL);
-+ fail_ai:
-+ free_irq(IRQ_RTC1Hz, NULL);
-+ fail_ui:
-+ return ret;
-+}
-+
-+static void sa1100_rtc_release(void)
-+{
-+ spin_lock_irq (&rtc_lock);
-+ RTSR = 0;
-+ OIER &= ~OIER_E1;
-+ OSSR = OSSR_M1;
-+ spin_unlock_irq (&rtc_lock);
-+
-+// free_irq(IRQ_OST1, NULL);
-+ free_irq(IRQ_RTCAlrm, NULL);
-+ free_irq(IRQ_RTC1Hz, NULL);
-+}
-+
-+#if 0
-+ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ unsigned long data;
-+ ssize_t retval;
-+
-+ if (count < sizeof(unsigned long))
-+ return -EINVAL;
-+
-+ add_wait_queue(&rtc_wait, &wait);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ for (;;) {
-+ spin_lock_irq (&rtc_lock);
-+ data = rtc_irq_data;
-+ if (data != 0) {
-+ rtc_irq_data = 0;
-+ break;
-+ }
-+ spin_unlock_irq (&rtc_lock);
-+
-+ if (file->f_flags & O_NONBLOCK) {
-+ retval = -EAGAIN;
-+ goto out;
-+ }
-+
-+ if (signal_pending(current)) {
-+ retval = -ERESTARTSYS;
-+ goto out;
-+ }
-+
-+ schedule();
-+ }
-+
-+ if (data & RTC_PF) {
-+ /* interpolate missed periods and set match for the next one */
-+ unsigned long period = TIMER_FREQ/rtc_freq;
-+ unsigned long oscr = OSCR;
-+ unsigned long osmr1 = OSMR1;
-+ unsigned long missed = (oscr - osmr1)/period;
-+ data += missed << 8;
-+ OSSR = OSSR_M1; /* clear match on timer 1 */
-+ OSMR1 = osmr1 + (missed + 1)*period;
-+ /* ensure we didn't miss another match in the mean time */
-+ while( (signed long)((osmr1 = OSMR1) - OSCR) <= 0 ) {
-+ data += 0x100;
-+ OSSR = OSSR_M1; /* clear match on timer 1 */
-+ OSMR1 = osmr1 + period;
-+ }
-+ }
-+ spin_unlock_irq (&rtc_lock);
-+
-+ data -= 0x100; /* the first IRQ wasn't actually missed */
-+
-+ retval = put_user(data, (unsigned long *)buf);
-+ if (!retval)
-+ retval = sizeof(unsigned long);
-+
-+out:
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&rtc_wait, &wait);
-+ return retval;
-+}
-+#endif
-+
-+static int sa1100_rtc_ioctl(unsigned int cmd, unsigned long arg)
-+{
-+ switch (cmd) {
-+ case RTC_AIE_OFF:
-+ spin_lock_irq(&rtc_lock);
-+ RTSR &= ~RTSR_ALE;
-+// rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+ return 0;
-+ case RTC_AIE_ON:
-+ spin_lock_irq(&rtc_lock);
-+ RTSR |= RTSR_ALE;
-+// rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+ return 0;
-+ case RTC_UIE_OFF:
-+ spin_lock_irq(&rtc_lock);
-+ RTSR &= ~RTSR_HZE;
-+// rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+ return 0;
-+ case RTC_UIE_ON:
-+ spin_lock_irq(&rtc_lock);
-+ RTSR |= RTSR_HZE;
-+// rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+ return 0;
-+#if 0
-+ case RTC_PIE_OFF:
-+ spin_lock_irq(&rtc_lock);
-+ OIER &= ~OIER_E1;
-+// rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+ return 0;
-+ case RTC_PIE_ON:
-+ if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
-+ return -EACCES;
-+ spin_lock_irq(&rtc_lock);
-+ OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
-+ OIER |= OIER_E1;
-+// rtc_irq_data = 0;
-+ spin_unlock_irq(&rtc_lock);
-+ return 0;
-+ case RTC_IRQP_READ:
-+ return put_user(rtc_freq, (unsigned long *)arg);
-+ case RTC_IRQP_SET:
-+ if (arg < 1 || arg > TIMER_FREQ)
-+ return -EINVAL;
-+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
-+ return -EACCES;
-+ rtc_freq = arg;
-+ return 0;
-+#endif
-+ }
-+ return -EINVAL;
-+}
-+
-+static void sa1100_rtc_read_time(struct rtc_time *tm)
-+{
-+ rtc_time_to_tm(RCNR, tm);
-+}
-+
-+static int sa1100_rtc_set_time(struct rtc_time *tm)
-+{
-+ unsigned long time;
-+ int ret;
-+
-+ ret = rtc_tm_to_time(tm, &time);
-+ if (ret == 0)
-+ RCNR = time;
-+ return ret;
-+}
-+
-+static void sa1100_rtc_read_alarm(struct rtc_wkalrm *alrm)
-+{
-+ memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
-+ alrm->pending = RTSR & RTSR_AL ? 1 : 0;
-+}
-+
-+static int sa1100_rtc_set_alarm(struct rtc_wkalrm *alrm)
-+{
-+ int ret;
-+
-+ spin_lock_irq(&rtc_lock);
-+ ret = rtc_update_alarm(&alrm->time);
-+ if (ret == 0) {
-+ memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
-+
-+ if (alrm->enabled)
-+ enable_irq_wake(IRQ_RTCAlrm);
-+ else
-+ disable_irq_wake(IRQ_RTCAlrm);
-+ }
-+ spin_unlock_irq(&rtc_lock);
-+
-+ return ret;
-+}
-+
-+static int sa1100_rtc_proc(char *buf)
-+{
-+ char *p = buf;
-+
-+ p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR);
-+ p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" );
-+ p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no");
-+ p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no");
-+ p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq);
-+
-+ return p - buf;
-+}
-+
-+static struct rtc_ops sa1100_rtc_ops = {
-+ .owner = THIS_MODULE,
-+ .open = sa1100_rtc_open,
-+ .release = sa1100_rtc_release,
-+ .ioctl = sa1100_rtc_ioctl,
-+
-+ .read_time = sa1100_rtc_read_time,
-+ .set_time = sa1100_rtc_set_time,
-+ .read_alarm = sa1100_rtc_read_alarm,
-+ .set_alarm = sa1100_rtc_set_alarm,
-+ .proc = sa1100_rtc_proc,
-+};
-+
-+static int __init rtc_init(void)
-+{
-+ /*
-+ * According to the manual we should be able to let RTTR be zero
-+ * and then a default diviser for a 32.768KHz clock is used.
-+ * Apparently this doesn't work, at least for my SA1110 rev 5.
-+ * If the clock divider is uninitialized then reset it to the
-+ * default value to get the 1Hz clock.
-+ */
-+ if (RTTR == 0) {
-+ RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
-+ printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
-+ /* The current RTC value probably doesn't make sense either */
-+ RCNR = 0;
-+ }
-+
-+ register_rtc(&sa1100_rtc_ops);
-+
-+ return 0;
-+}
-+
-+static void __exit rtc_exit(void)
-+{
-+ unregister_rtc(&sa1100_rtc_ops);
-+}
-+
-+module_init(rtc_init);
-+module_exit(rtc_exit);
-+
-+MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>");
-+MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
-+MODULE_LICENSE("GPL"); /* so says the header */
---- linux-2.6.5/drivers/char/Kconfig~heh 2004-04-03 22:36:15.000000000 -0500
-+++ linux-2.6.5/drivers/char/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -814,6 +814,10 @@
-
- If unsure, say N.
-
-+config SA1100_RTC
-+ tristate "SA1100 or PXA Real Time Clock"
-+ depends on ARCH_SA1100 || ARCH_PXA
-+
- config DTLK
- tristate "Double Talk PC internal speech card support"
- help
---- linux-2.6.5/drivers/char/tty_io.c~heh 2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/char/tty_io.c 2004-04-30 20:57:36.000000000 -0400
-@@ -1535,10 +1535,17 @@
- return 0;
- }
-
-+/*
-+ * In the case of pty's, "tty" is the master side
-+ * and "real_tty" is the slave side.
-+ */
- static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
- struct winsize * arg)
- {
- struct winsize tmp_ws;
-+ struct task_struct *p;
-+ struct list_head *l;
-+ struct pid *pid;
-
- if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
- return -EFAULT;
-@@ -1558,8 +1565,21 @@
- #endif
- if (tty->pgrp > 0)
- kill_pg(tty->pgrp, SIGWINCH, 1);
-- if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
-- kill_pg(real_tty->pgrp, SIGWINCH, 1);
-+
-+ /*
-+ * Send SIGWINCH to the whole session on the slave tty.
-+ * However, in the case of non-master pty's, be careful
-+ * not to send two SIGWINCH to the same procress group.
-+ */
-+ if (real_tty->session > 0) {
-+ read_lock(&tasklist_lock);
-+ for_each_task_pid(real_tty->session, PIDTYPE_SID, p, l, pid) {
-+ if (process_group(p) != tty->pgrp)
-+ group_send_sig_info(SIGWINCH, (void *)1L, p);
-+ }
-+ read_unlock(&tasklist_lock);
-+ }
-+
- tty->winsize = tmp_ws;
- real_tty->winsize = tmp_ws;
- return 0;
---- linux-2.6.5/drivers/Makefile~heh 2004-04-03 22:37:43.000000000 -0500
-+++ linux-2.6.5/drivers/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -11,6 +11,8 @@
- # PnP must come after ACPI since it will eventually need to check if acpi
- # was used and do nothing if so
- obj-$(CONFIG_PNP) += pnp/
-+obj-$(CONFIG_I2C) += i2c/
-+obj-$(CONFIG_L3) += l3/
-
- # char/ comes before serial/ etc so that the VT console is the boot-time
- # default.
-@@ -41,7 +43,6 @@
- obj-$(CONFIG_GAMEPORT) += input/gameport/
- obj-$(CONFIG_SERIO) += input/serio/
- obj-$(CONFIG_I2O) += message/
--obj-$(CONFIG_I2C) += i2c/
- obj-$(CONFIG_PHONE) += telephony/
- obj-$(CONFIG_MD) += md/
- obj-$(CONFIG_BT) += bluetooth/
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/l3/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,24 @@
-+#
-+# L3 bus configuration
-+#
-+
-+menu "L3 serial bus support"
-+
-+config L3
-+ tristate "L3 support"
-+
-+config L3_ALGOBIT
-+ bool "L3 bit-banging interfaces"
-+ depends on L3=y
-+
-+config L3_BIT_SA1100_GPIO
-+ bool "SA11x0 GPIO adapter"
-+ depends on L3_ALGOBIT && ARCH_SA1100
-+
-+# i2c must come before this
-+config BIT_SA1100_GPIO
-+ bool
-+ depends on L3_BIT_SA1100_GPIO || I2C_BIT_SA1100_GPIO=y
-+ default y
-+
-+endmenu
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/l3/l3-core.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,203 @@
-+/*
-+ * linux/drivers/l3/l3-core.c
-+ *
-+ * Copyright (C) 2001 Russell King
-+ *
-+ * General structure taken from i2c-core.c by Simon G. Vogl
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * See linux/Documentation/l3 for further documentation.
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/proc_fs.h>
-+#include <linux/kmod.h>
-+#include <linux/init.h>
-+#include <linux/l3/l3.h>
-+
-+static DECLARE_MUTEX(adapter_lock);
-+static LIST_HEAD(adapter_list);
-+
-+static DECLARE_MUTEX(driver_lock);
-+static LIST_HEAD(driver_list);
-+
-+/**
-+ * l3_add_adapter - register a new L3 bus adapter
-+ * @adap: l3_adapter structure for the registering adapter
-+ *
-+ * Make the adapter available for use by clients using name adap->name.
-+ * The adap->adapters list is initialised by this function.
-+ *
-+ * Returns 0;
-+ */
-+int l3_add_adapter(struct l3_adapter *adap)
-+{
-+ down(&adapter_lock);
-+ list_add(&adap->adapters, &adapter_list);
-+ up(&adapter_lock);
-+ return 0;
-+}
-+
-+/**
-+ * l3_del_adapter - unregister a L3 bus adapter
-+ * @adap: l3_adapter structure to unregister
-+ *
-+ * Remove an adapter from the list of available L3 Bus adapters.
-+ *
-+ * Returns 0;
-+ */
-+int l3_del_adapter(struct l3_adapter *adap)
-+{
-+ down(&adapter_lock);
-+ list_del(&adap->adapters);
-+ up(&adapter_lock);
-+ return 0;
-+}
-+
-+static struct l3_adapter *__l3_get_adapter(const char *name)
-+{
-+ struct list_head *l;
-+
-+ list_for_each(l, &adapter_list) {
-+ struct l3_adapter *adap = list_entry(l, struct l3_adapter, adapters);
-+
-+ if (strcmp(adap->name, name) == 0)
-+ return adap;
-+ }
-+
-+ return NULL;
-+}
-+
-+/**
-+ * l3_get_adapter - get a reference to an adapter
-+ * @name: driver name
-+ *
-+ * Obtain a l3_adapter structure for the specified adapter. If the adapter
-+ * is not currently load, then load it. The adapter will be locked in core
-+ * until all references are released via l3_put_adapter.
-+ */
-+struct l3_adapter *l3_get_adapter(const char *name)
-+{
-+ struct l3_adapter *adap;
-+ int try;
-+
-+ for (try = 0; try < 2; try ++) {
-+ down(&adapter_lock);
-+ adap = __l3_get_adapter(name);
-+ if (adap && !try_module_get(adap->owner))
-+ adap = NULL;
-+ up(&adapter_lock);
-+
-+ if (adap)
-+ break;
-+
-+ if (try == 0)
-+ request_module(name);
-+ }
-+
-+ return adap;
-+}
-+
-+/**
-+ * l3_put_adapter - release a reference to an adapter
-+ * @adap: driver to release reference
-+ *
-+ * Indicate to the L3 core that you no longer require the adapter reference.
-+ * The adapter module may be unloaded when there are no references to its
-+ * data structure.
-+ *
-+ * You must not use the reference after calling this function.
-+ */
-+void l3_put_adapter(struct l3_adapter *adap)
-+{
-+ if (adap && adap->owner)
-+ module_put(adap->owner);
-+}
-+
-+/**
-+ * l3_transfer - transfer information on an L3 bus
-+ * @adap: adapter structure to perform transfer on
-+ * @msgs: array of l3_msg structures describing transfer
-+ * @num: number of l3_msg structures
-+ *
-+ * Transfer the specified messages to/from a device on the L3 bus.
-+ *
-+ * Returns number of messages successfully transferred, otherwise negative
-+ * error code.
-+ */
-+int l3_transfer(struct l3_adapter *adap, struct l3_msg msgs[], int num)
-+{
-+ int ret = -ENOSYS;
-+
-+ if (adap->algo->xfer) {
-+ down(adap->lock);
-+ ret = adap->algo->xfer(adap, msgs, num);
-+ up(adap->lock);
-+ }
-+ return ret;
-+}
-+
-+/**
-+ * l3_write - send data to a device on an L3 bus
-+ * @adap: L3 bus adapter
-+ * @addr: L3 bus address
-+ * @buf: buffer for bytes to send
-+ * @len: number of bytes to send
-+ *
-+ * Send len bytes pointed to by buf to device address addr on the L3 bus
-+ * described by client.
-+ *
-+ * Returns the number of bytes transferred, or negative error code.
-+ */
-+int l3_write(struct l3_adapter *adap, int addr, const char *buf, int len)
-+{
-+ struct l3_msg msg;
-+ int ret;
-+
-+ msg.addr = addr;
-+ msg.flags = 0;
-+ msg.buf = (char *)buf;
-+ msg.len = len;
-+
-+ ret = l3_transfer(adap, &msg, 1);
-+ return ret == 1 ? len : ret;
-+}
-+
-+/**
-+ * l3_read - receive data from a device on an L3 bus
-+ * @adap: L3 bus adapter
-+ * @addr: L3 bus address
-+ * @buf: buffer for bytes to receive
-+ * @len: number of bytes to receive
-+ *
-+ * Receive len bytes from device address addr on the L3 bus described by
-+ * client to a buffer pointed to by buf.
-+ *
-+ * Returns the number of bytes transferred, or negative error code.
-+ */
-+int l3_read(struct l3_adapter *adap, int addr, char *buf, int len)
-+{
-+ struct l3_msg msg;
-+ int ret;
-+
-+ msg.addr = addr;
-+ msg.flags = L3_M_RD;
-+ msg.buf = buf;
-+ msg.len = len;
-+
-+ ret = l3_transfer(adap, &msg, 1);
-+ return ret == 1 ? len : ret;
-+}
-+
-+EXPORT_SYMBOL(l3_add_adapter);
-+EXPORT_SYMBOL(l3_del_adapter);
-+EXPORT_SYMBOL(l3_get_adapter);
-+EXPORT_SYMBOL(l3_put_adapter);
-+EXPORT_SYMBOL(l3_transfer);
-+EXPORT_SYMBOL(l3_write);
-+EXPORT_SYMBOL(l3_read);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/l3/l3-algo-bit.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,175 @@
-+/*
-+ * L3 bus algorithm module.
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * Note that L3 buses can share the same pins as I2C buses, so we must
-+ * _not_ generate an I2C start condition. An I2C start condition is
-+ * defined as a high-to-low transition of the data line while the clock
-+ * is high. Therefore, we must only change the data line while the
-+ * clock is low.
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/sched.h>
-+#include <linux/l3/l3.h>
-+#include <linux/l3/algo-bit.h>
-+
-+#define setdat(adap,val) adap->setdat(adap->data, val)
-+#define setclk(adap,val) adap->setclk(adap->data, val)
-+#define setmode(adap,val) adap->setmode(adap->data, val)
-+#define setdatin(adap) adap->setdir(adap->data, 1)
-+#define setdatout(adap) adap->setdir(adap->data, 0)
-+#define getdat(adap) adap->getdat(adap->data)
-+
-+/*
-+ * Send one byte of data to the chip. Data is latched into the chip on
-+ * the rising edge of the clock.
-+ */
-+static void sendbyte(struct l3_algo_bit_data *adap, unsigned int byte)
-+{
-+ int i;
-+
-+ for (i = 0; i < 8; i++) {
-+ setclk(adap, 0);
-+ udelay(adap->data_hold);
-+ setdat(adap, byte & 1);
-+ udelay(adap->data_setup);
-+ setclk(adap, 1);
-+ udelay(adap->clock_high);
-+ byte >>= 1;
-+ }
-+}
-+
-+/*
-+ * Send a set of bytes to the chip. We need to pulse the MODE line
-+ * between each byte, but never at the start nor at the end of the
-+ * transfer.
-+ */
-+static void sendbytes(struct l3_algo_bit_data *adap, const char *buf, int len)
-+{
-+ int i;
-+
-+ for (i = 0; i < len; i++) {
-+ if (i) {
-+ udelay(adap->mode_hold);
-+ setmode(adap, 0);
-+ udelay(adap->mode);
-+ }
-+ setmode(adap, 1);
-+ udelay(adap->mode_setup);
-+ sendbyte(adap, buf[i]);
-+ }
-+}
-+
-+/*
-+ * Read one byte of data from the chip. Data is latched into the chip on
-+ * the rising edge of the clock.
-+ */
-+static unsigned int readbyte(struct l3_algo_bit_data *adap)
-+{
-+ unsigned int byte = 0;
-+ int i;
-+
-+ for (i = 0; i < 8; i++) {
-+ setclk(adap, 0);
-+ udelay(adap->data_hold + adap->data_setup);
-+ setclk(adap, 1);
-+ if (getdat(adap))
-+ byte |= 1 << i;
-+ udelay(adap->clock_high);
-+ }
-+
-+ return byte;
-+}
-+
-+/*
-+ * Read a set of bytes from the chip. We need to pulse the MODE line
-+ * between each byte, but never at the start nor at the end of the
-+ * transfer.
-+ */
-+static void readbytes(struct l3_algo_bit_data *adap, char *buf, int len)
-+{
-+ int i;
-+
-+ for (i = 0; i < len; i++) {
-+ if (i) {
-+ udelay(adap->mode_hold);
-+ setmode(adap, 0);
-+ }
-+ setmode(adap, 1);
-+ udelay(adap->mode_setup);
-+ buf[i] = readbyte(adap);
-+ }
-+}
-+
-+static int l3_xfer(struct l3_adapter *l3_adap, struct l3_msg msgs[], int num)
-+{
-+ struct l3_algo_bit_data *adap = l3_adap->algo_data;
-+ int i;
-+
-+ /*
-+ * If we share an I2C bus, ensure that it is in STOP mode
-+ */
-+ setclk(adap, 1);
-+ setdat(adap, 1);
-+ setmode(adap, 1);
-+ setdatout(adap);
-+ udelay(adap->mode);
-+
-+ for (i = 0; i < num; i++) {
-+ struct l3_msg *pmsg = &msgs[i];
-+
-+ if (!(pmsg->flags & L3_M_NOADDR)) {
-+ setmode(adap, 0);
-+ udelay(adap->mode_setup);
-+ sendbyte(adap, pmsg->addr);
-+ udelay(adap->mode_hold);
-+ }
-+
-+ if (pmsg->flags & L3_M_RD) {
-+ setdatin(adap);
-+ readbytes(adap, pmsg->buf, pmsg->len);
-+ } else {
-+ setdatout(adap);
-+ sendbytes(adap, pmsg->buf, pmsg->len);
-+ }
-+ }
-+
-+ /*
-+ * Ensure that we leave the bus in I2C stop mode.
-+ */
-+ setclk(adap, 1);
-+ setdat(adap, 1);
-+ setmode(adap, 0);
-+ setdatin(adap);
-+
-+ return num;
-+}
-+
-+static struct l3_algorithm l3_bit_algo = {
-+ name: "L3 bit-shift algorithm",
-+ xfer: l3_xfer,
-+};
-+
-+int l3_bit_add_bus(struct l3_adapter *adap)
-+{
-+ adap->algo = &l3_bit_algo;
-+ return l3_add_adapter(adap);
-+}
-+
-+int l3_bit_del_bus(struct l3_adapter *adap)
-+{
-+ return l3_del_adapter(adap);
-+}
-+
-+EXPORT_SYMBOL(l3_bit_add_bus);
-+EXPORT_SYMBOL(l3_bit_del_bus);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/l3/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,11 @@
-+#
-+# Makefile for the L3 bus driver.
-+#
-+
-+# Link order:
-+# (core, adapters, algorithms, drivers) then clients
-+
-+l3-$(CONFIG_L3_ALGOBIT) += l3-algo-bit.o
-+l3-$(CONFIG_BIT_SA1100_GPIO) += l3-bit-sa1100.o
-+
-+obj-$(CONFIG_L3) += l3-core.o $(l3-y) $(l3-drv-y)
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/l3/l3-bit-sa1100.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,271 @@
-+/*
-+ * linux/drivers/l3/l3-bit-sa1100.c
-+ *
-+ * Copyright (C) 2001 Russell King
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This is a combined I2C and L3 bus driver.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/ioport.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/l3/algo-bit.h>
-+
-+#include <asm/system.h>
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/arch/assabet.h>
-+
-+#define NAME "l3-bit-sa1100-gpio"
-+
-+struct bit_data {
-+ unsigned int sda;
-+ unsigned int scl;
-+ unsigned int l3_mode;
-+};
-+
-+static int getsda(void *data)
-+{
-+ struct bit_data *bits = data;
-+
-+ return GPLR & bits->sda;
-+}
-+
-+#ifdef CONFIG_I2C_BIT_SA1100_GPIO
-+static void i2c_setsda(void *data, int state)
-+{
-+ struct bit_data *bits = data;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ if (state)
-+ GPDR &= ~bits->sda;
-+ else {
-+ GPCR = bits->sda;
-+ GPDR |= bits->sda;
-+ }
-+ local_irq_restore(flags);
-+}
-+
-+static void i2c_setscl(void *data, int state)
-+{
-+ struct bit_data *bits = data;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ if (state)
-+ GPDR &= ~bits->scl;
-+ else {
-+ GPCR = bits->scl;
-+ GPDR |= bits->scl;
-+ }
-+ local_irq_restore(flags);
-+}
-+
-+static int i2c_getscl(void *data)
-+{
-+ struct bit_data *bits = data;
-+
-+ return GPLR & bits->scl;
-+}
-+
-+static struct i2c_algo_bit_data i2c_bit_data = {
-+ .setsda = i2c_setsda,
-+ .setscl = i2c_setscl,
-+ .getsda = getsda,
-+ .getscl = i2c_getscl,
-+ .udelay = 10,
-+ .mdelay = 10,
-+ .timeout = 100,
-+};
-+
-+static struct i2c_adapter i2c_adapter = {
-+ .algo_data = &i2c_bit_data,
-+};
-+
-+#define LOCK &i2c_adapter.bus_lock
-+
-+static int __init i2c_init(struct bit_data *bits)
-+{
-+ i2c_bit_data.data = bits;
-+ return i2c_bit_add_bus(&i2c_adapter);
-+}
-+
-+static void i2c_exit(void)
-+{
-+ i2c_bit_del_bus(&i2c_adapter);
-+}
-+
-+#else
-+static DECLARE_MUTEX(l3_lock);
-+#define LOCK &l3_lock
-+#define i2c_init(bits) (0)
-+#define i2c_exit() do { } while (0)
-+#endif
-+
-+#ifdef CONFIG_L3_BIT_SA1100_GPIO
-+/*
-+ * iPAQs need the clock line driven hard high and low.
-+ */
-+static void l3_setscl(void *data, int state)
-+{
-+ struct bit_data *bits = data;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ if (state)
-+ GPSR = bits->scl;
-+ else
-+ GPCR = bits->scl;
-+ GPDR |= bits->scl;
-+ local_irq_restore(flags);
-+}
-+
-+static void l3_setsda(void *data, int state)
-+{
-+ struct bit_data *bits = data;
-+
-+ if (state)
-+ GPSR = bits->sda;
-+ else
-+ GPCR = bits->sda;
-+}
-+
-+static void l3_setdir(void *data, int in)
-+{
-+ struct bit_data *bits = data;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ if (in)
-+ GPDR &= ~bits->sda;
-+ else
-+ GPDR |= bits->sda;
-+ local_irq_restore(flags);
-+}
-+
-+static void l3_setmode(void *data, int state)
-+{
-+ struct bit_data *bits = data;
-+
-+ if (state)
-+ GPSR = bits->l3_mode;
-+ else
-+ GPCR = bits->l3_mode;
-+}
-+
-+static struct l3_algo_bit_data l3_bit_data = {
-+ .data = NULL,
-+ .setdat = l3_setsda,
-+ .setclk = l3_setscl,
-+ .setmode = l3_setmode,
-+ .setdir = l3_setdir,
-+ .getdat = getsda,
-+ .data_hold = 1,
-+ .data_setup = 1,
-+ .clock_high = 1,
-+ .mode_hold = 1,
-+ .mode_setup = 1,
-+};
-+
-+static struct l3_adapter l3_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = NAME,
-+ .algo_data = &l3_bit_data,
-+ .lock = LOCK,
-+};
-+
-+static int __init l3_init(struct bit_data *bits)
-+{
-+ l3_bit_data.data = bits;
-+ return l3_bit_add_bus(&l3_adapter);
-+}
-+
-+static void __exit l3_exit(void)
-+{
-+ l3_bit_del_bus(&l3_adapter);
-+}
-+#else
-+#define l3_init(bits) (0)
-+#define l3_exit() do { } while (0)
-+#endif
-+
-+static struct bit_data bit_data;
-+
-+static int __init bus_init(void)
-+{
-+ struct bit_data *bit = &bit_data;
-+ unsigned long flags;
-+ int ret;
-+
-+ if (machine_is_assabet() || machine_is_pangolin()) {
-+ bit->sda = GPIO_GPIO15;
-+ bit->scl = GPIO_GPIO18;
-+ bit->l3_mode = GPIO_GPIO17;
-+ }
-+
-+ if (machine_is_h3600() || machine_is_h3100()) {
-+ bit->sda = GPIO_GPIO14;
-+ bit->scl = GPIO_GPIO16;
-+ bit->l3_mode = GPIO_GPIO15;
-+ }
-+
-+ if (machine_is_stork()) {
-+ bit->sda = GPIO_GPIO15;
-+ bit->scl = GPIO_GPIO18;
-+ bit->l3_mode = GPIO_GPIO17;
-+ }
-+
-+ if (!bit->sda)
-+ return -ENODEV;
-+
-+ /*
-+ * Default level for L3 mode is low.
-+ * We set SCL and SDA high (i2c idle state).
-+ */
-+ local_irq_save(flags);
-+ GPDR &= ~(bit->scl | bit->sda);
-+ GPCR = bit->l3_mode | bit->scl | bit->sda;
-+ GPDR |= bit->l3_mode;
-+ local_irq_restore(flags);
-+
-+ if (machine_is_assabet()) {
-+ /*
-+ * Release reset on UCB1300, ADI7171 and UDA1341. We
-+ * need to do this here so that we can communicate on
-+ * the I2C/L3 buses.
-+ */
-+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
-+ mdelay(1);
-+ ASSABET_BCR_clear(ASSABET_BCR_CODEC_RST);
-+ mdelay(1);
-+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
-+ }
-+
-+ ret = i2c_init(bit);
-+ if (ret == 0 && bit->l3_mode) {
-+ ret = l3_init(bit);
-+ if (ret)
-+ i2c_exit();
-+ }
-+
-+ return ret;
-+}
-+
-+static void __exit bus_exit(void)
-+{
-+ l3_exit();
-+ i2c_exit();
-+}
-+
-+module_init(bus_init);
-+module_exit(bus_exit);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/switches.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,22 @@
-+/*
-+ * linux/drivers/misc/switches.h
-+ *
-+ * Copyright (C) 2001 John Dorsey
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 19 December 2001 - created.
-+ */
-+
-+#if !defined(_SWITCHES_H)
-+# define _SWITCHES_H
-+
-+#include <linux/switches.h>
-+
-+#define SWITCHES_NAME "switches"
-+
-+extern int switches_event(switches_mask_t *mask);
-+
-+#endif /* !defined(_SWITCHES_H) */
---- linux-2.6.5/drivers/misc/Kconfig~heh 2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/drivers/misc/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -21,5 +21,62 @@
-
- If unsure, say N.
-
-+menu "Multimedia Capabilities Port drivers"
-+
-+config MCP
-+ tristate "Multimedia drivers"
-+
-+# Interface drivers
-+config MCP_SA1100
-+ tristate "Support SA1100 MCP interface"
-+ depends on MCP && ARCH_SA1100
-+
-+# Chip drivers
-+config MCP_UCB1200
-+ tristate "Support for UCB1200 / UCB1300"
-+ depends on MCP
-+
-+config MCP_UCB1200_AUDIO
-+ tristate "Audio / Telephony interface support"
-+ depends on MCP_UCB1200 && SOUND
-+
-+config MCP_UCB1200_TS
-+ tristate "Touchscreen interface support"
-+ depends on MCP_UCB1200 && INPUT
-+
-+endmenu
-+
-+
-+menu "Console Switches"
-+
-+config SWITCHES
-+ tristate "Console Switch Support"
-+ help
-+ Say Y here to include support for simple console momentary switches.
-+ This driver implements a miscellaneous character device (named
-+ `switches' in /proc/misc) which can be read by userland programs
-+ to respond to switch press events. This mechanism is efficient for
-+ systems which may not implement a traditional heavyweight console
-+ server.
-+
-+ It is also possible to say M to build this driver as a module (named
-+ `switches.o').
-+
-+config SWITCHES_SA1100
-+ tristate "SA-1100 switches"
-+ depends on SWITCHES && ARCH_SA1100
-+ help
-+ Say Y here to include support for switches routed directly to
-+ interruptable signals on StrongARM SA-1100 systems.
-+
-+config SWITCHES_UCB1X00
-+ tristate "UCB1x00 switches"
-+ depends on SWITCHES && MCP_UCB1200
-+ help
-+ Say Y here to include support for switches routed through a
-+ UCB1x00 modem/audio analog front-end device.
-+
-+endmenu
-+
- endmenu
-
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/ucb1x00-assabet.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,73 @@
-+/*
-+ * linux/drivers/misc/ucb1x00-assabet.c
-+ *
-+ * Copyright (C) 2001-2003 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * We handle the machine-specific bits of the UCB1x00 driver here.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/proc_fs.h>
-+#include <linux/device.h>
-+
-+#include <asm/dma.h>
-+
-+#include "ucb1x00.h"
-+
-+#define UCB1X00_ATTR(name,input)\
-+static ssize_t name##_show(struct class_device *dev, char *buf) \
-+{ \
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); \
-+ int val; \
-+ ucb1x00_adc_enable(ucb); \
-+ val = ucb1x00_adc_read(ucb, input, UCB_NOSYNC); \
-+ ucb1x00_adc_disable(ucb); \
-+ return sprintf(buf, "%d\n", val); \
-+} \
-+static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
-+
-+UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
-+UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
-+UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
-+
-+static int ucb1x00_assabet_add(struct class_device *dev)
-+{
-+ class_device_create_file(dev, &class_device_attr_vbatt);
-+ class_device_create_file(dev, &class_device_attr_vcharger);
-+ class_device_create_file(dev, &class_device_attr_batt_temp);
-+ return 0;
-+}
-+
-+static void ucb1x00_assabet_remove(struct class_device *dev)
-+{
-+ class_device_remove_file(dev, &class_device_attr_batt_temp);
-+ class_device_remove_file(dev, &class_device_attr_vcharger);
-+ class_device_remove_file(dev, &class_device_attr_vbatt);
-+}
-+
-+static struct class_interface ucb1x00_assabet_interface = {
-+ .add = ucb1x00_assabet_add,
-+ .remove = ucb1x00_assabet_remove,
-+};
-+
-+static int __init ucb1x00_assabet_init(void)
-+{
-+ return ucb1x00_register_interface(&ucb1x00_assabet_interface);
-+}
-+
-+static void __exit ucb1x00_assabet_exit(void)
-+{
-+ ucb1x00_unregister_interface(&ucb1x00_assabet_interface);
-+}
-+
-+module_init(ucb1x00_assabet_init);
-+module_exit(ucb1x00_assabet_exit);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("Assabet noddy testing only example ADC driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/mcp-pxa.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,57 @@
-+/*
-+ * linux/drivers/misc/mcp-pxa.c
-+ *
-+ * 2002-01-10 Jeff Sutherland <jeffs@accelent.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * NOTE: This is a quick hack to gain access to the aclink codec's
-+ * touch screen facility. Its audio is handled by a separate
-+ * (non-mcp) driver at the present time.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/ac97_codec.h>
-+
-+#include "mcp.h"
-+
-+
-+extern int pxa_ac97_get(struct ac97_codec **codec);
-+extern void pxa_ac97_put(void);
-+
-+
-+struct mcp *mcp_get(void)
-+{
-+ struct ac97_codec *codec;
-+ if (pxa_ac97_get(&codec) < 0)
-+ return NULL;
-+ return (struct mcp *)codec;
-+}
-+
-+void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
-+{
-+ struct ac97_codec *codec = (struct ac97_codec *)mcp;
-+ codec->codec_write(codec, reg, val);
-+}
-+
-+unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
-+{
-+ struct ac97_codec *codec = (struct ac97_codec *)mcp;
-+ return codec->codec_read(codec, reg);
-+}
-+
-+void mcp_enable(struct mcp *mcp)
-+{
-+ /*
-+ * Should we do something here to make sure the aclink
-+ * codec is alive???
-+ * A: not for now --NP
-+ */
-+}
-+
-+void mcp_disable(struct mcp *mcp)
-+{
-+}
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/mcp-core.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,235 @@
-+/*
-+ * linux/drivers/misc/mcp-core.c
-+ *
-+ * Copyright (C) 2001 Russell King
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * Generic MCP (Multimedia Communications Port) layer. All MCP locking
-+ * is solely held within this file.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/smp.h>
-+#include <linux/device.h>
-+
-+#include <asm/dma.h>
-+#include <asm/system.h>
-+
-+#include "mcp.h"
-+
-+#define to_mcp(d) container_of(d, struct mcp, attached_device)
-+#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
-+
-+static int mcp_bus_match(struct device *dev, struct device_driver *drv)
-+{
-+ return 1;
-+}
-+
-+static int mcp_bus_probe(struct device *dev)
-+{
-+ struct mcp *mcp = to_mcp(dev);
-+ struct mcp_driver *drv = to_mcp_driver(dev->driver);
-+
-+ return drv->probe(mcp);
-+}
-+
-+static int mcp_bus_remove(struct device *dev)
-+{
-+ struct mcp *mcp = to_mcp(dev);
-+ struct mcp_driver *drv = to_mcp_driver(dev->driver);
-+
-+ drv->remove(mcp);
-+ return 0;
-+}
-+
-+static int mcp_bus_suspend(struct device *dev, u32 state)
-+{
-+ struct mcp *mcp = to_mcp(dev);
-+ int ret = 0;
-+
-+ if (dev->driver) {
-+ struct mcp_driver *drv = to_mcp_driver(dev->driver);
-+
-+ ret = drv->suspend(mcp, state);
-+ }
-+ return ret;
-+}
-+
-+static int mcp_bus_resume(struct device *dev)
-+{
-+ struct mcp *mcp = to_mcp(dev);
-+ int ret = 0;
-+
-+ if (dev->driver) {
-+ struct mcp_driver *drv = to_mcp_driver(dev->driver);
-+
-+ ret = drv->resume(mcp);
-+ }
-+ return ret;
-+}
-+
-+static struct bus_type mcp_bus_type = {
-+ .name = "mcp",
-+ .match = mcp_bus_match,
-+ .suspend = mcp_bus_suspend,
-+ .resume = mcp_bus_resume,
-+};
-+
-+/**
-+ * mcp_set_telecom_divisor - set the telecom divisor
-+ * @mcp: MCP interface structure
-+ * @div: SIB clock divisor
-+ *
-+ * Set the telecom divisor on the MCP interface. The resulting
-+ * sample rate is SIBCLOCK/div.
-+ */
-+void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
-+{
-+ spin_lock_irq(&mcp->lock);
-+ mcp->set_telecom_divisor(mcp, div);
-+ spin_unlock_irq(&mcp->lock);
-+}
-+
-+/**
-+ * mcp_set_audio_divisor - set the audio divisor
-+ * @mcp: MCP interface structure
-+ * @div: SIB clock divisor
-+ *
-+ * Set the audio divisor on the MCP interface.
-+ */
-+void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
-+{
-+ spin_lock_irq(&mcp->lock);
-+ mcp->set_audio_divisor(mcp, div);
-+ spin_unlock_irq(&mcp->lock);
-+}
-+
-+/**
-+ * mcp_reg_write - write a device register
-+ * @mcp: MCP interface structure
-+ * @reg: 4-bit register index
-+ * @val: 16-bit data value
-+ *
-+ * Write a device register. The MCP interface must be enabled
-+ * to prevent this function hanging.
-+ */
-+void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&mcp->lock, flags);
-+ mcp->reg_write(mcp, reg, val);
-+ spin_unlock_irqrestore(&mcp->lock, flags);
-+}
-+
-+/**
-+ * mcp_reg_read - read a device register
-+ * @mcp: MCP interface structure
-+ * @reg: 4-bit register index
-+ *
-+ * Read a device register and return its value. The MCP interface
-+ * must be enabled to prevent this function hanging.
-+ */
-+unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
-+{
-+ unsigned long flags;
-+ unsigned int val;
-+
-+ spin_lock_irqsave(&mcp->lock, flags);
-+ val = mcp->reg_read(mcp, reg);
-+ spin_unlock_irqrestore(&mcp->lock, flags);
-+
-+ return val;
-+}
-+
-+/**
-+ * mcp_enable - enable the MCP interface
-+ * @mcp: MCP interface to enable
-+ *
-+ * Enable the MCP interface. Each call to mcp_enable will need
-+ * a corresponding call to mcp_disable to disable the interface.
-+ */
-+void mcp_enable(struct mcp *mcp)
-+{
-+ spin_lock_irq(&mcp->lock);
-+ if (mcp->use_count++ == 0)
-+ mcp->enable(mcp);
-+ spin_unlock_irq(&mcp->lock);
-+}
-+
-+/**
-+ * mcp_disable - disable the MCP interface
-+ * @mcp: MCP interface to disable
-+ *
-+ * Disable the MCP interface. The MCP interface will only be
-+ * disabled once the number of calls to mcp_enable matches the
-+ * number of calls to mcp_disable.
-+ */
-+void mcp_disable(struct mcp *mcp)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&mcp->lock, flags);
-+ if (--mcp->use_count == 0)
-+ mcp->disable(mcp);
-+ spin_unlock_irqrestore(&mcp->lock, flags);
-+}
-+
-+int mcp_host_register(struct mcp *mcp, struct device *parent)
-+{
-+ mcp->attached_device.parent = parent;
-+ mcp->attached_device.bus = &mcp_bus_type;
-+ mcp->attached_device.dma_mask = parent->dma_mask;
-+ strcpy(mcp->attached_device.bus_id, "mcp0");
-+ return device_register(&mcp->attached_device);
-+}
-+
-+void mcp_host_unregister(struct mcp *mcp)
-+{
-+ device_unregister_wait(&mcp->attached_device);
-+}
-+
-+int mcp_driver_register(struct mcp_driver *mcpdrv)
-+{
-+ mcpdrv->drv.bus = &mcp_bus_type;
-+ mcpdrv->drv.probe = mcp_bus_probe;
-+ mcpdrv->drv.remove = mcp_bus_remove;
-+ return driver_register(&mcpdrv->drv);
-+}
-+
-+void mcp_driver_unregister(struct mcp_driver *mcpdrv)
-+{
-+ driver_unregister(&mcpdrv->drv);
-+}
-+
-+static int __init mcp_init(void)
-+{
-+ return bus_register(&mcp_bus_type);
-+}
-+
-+static void __exit mcp_exit(void)
-+{
-+ bus_unregister(&mcp_bus_type);
-+}
-+
-+module_init(mcp_init);
-+module_exit(mcp_exit);
-+
-+EXPORT_SYMBOL(mcp_set_telecom_divisor);
-+EXPORT_SYMBOL(mcp_set_audio_divisor);
-+EXPORT_SYMBOL(mcp_reg_write);
-+EXPORT_SYMBOL(mcp_reg_read);
-+EXPORT_SYMBOL(mcp_enable);
-+EXPORT_SYMBOL(mcp_disable);
-+EXPORT_SYMBOL(mcp_host_register);
-+EXPORT_SYMBOL(mcp_host_unregister);
-+EXPORT_SYMBOL(mcp_driver_register);
-+EXPORT_SYMBOL(mcp_driver_unregister);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("Core multimedia communications port driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/ucb1x00-ts.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,465 @@
-+/*
-+ * linux/drivers/misc/ucb1x00-ts.c
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 21-Jan-2002 <jco@ict.es> :
-+ *
-+ * Added support for synchronous A/D mode. This mode is useful to
-+ * avoid noise induced in the touchpanel by the LCD, provided that
-+ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
-+ * It is important to note that the signal connected to the ADCSYNC
-+ * pin should provide pulses even when the LCD is blanked, otherwise
-+ * a pen touch needed to unblank the LCD will never be read.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/smp.h>
-+#include <linux/smp_lock.h>
-+#include <linux/sched.h>
-+#include <linux/completion.h>
-+#include <linux/delay.h>
-+#include <linux/string.h>
-+#include <linux/input.h>
-+#include <linux/device.h>
-+#include <linux/slab.h>
-+
-+#include <asm/dma.h>
-+#include <asm/semaphore.h>
-+
-+#include "ucb1x00.h"
-+
-+
-+struct ucb1x00_ts {
-+ struct input_dev idev;
-+ struct ucb1x00 *ucb;
-+
-+ struct semaphore irq_wait;
-+ struct semaphore sem;
-+ struct completion init_exit;
-+ struct task_struct *rtask;
-+ int use_count;
-+ u16 x_res;
-+ u16 y_res;
-+
-+ int restart:1;
-+ int adcsync:1;
-+};
-+
-+static int adcsync = UCB_NOSYNC;
-+
-+static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
-+{
-+ input_report_abs(&ts->idev, ABS_X, x);
-+ input_report_abs(&ts->idev, ABS_Y, y);
-+ input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
-+ input_sync(&ts->idev);
-+}
-+
-+static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
-+{
-+ input_report_abs(&ts->idev, ABS_PRESSURE, 0);
-+ input_sync(&ts->idev);
-+}
-+
-+/*
-+ * Switch to interrupt mode.
-+ */
-+static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
-+{
-+ if (ts->ucb->id == UCB_ID_1400_BUGGY)
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
-+ UCB_TS_CR_MODE_INT);
-+ else
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
-+ UCB_TS_CR_MODE_INT);
-+}
-+
-+/*
-+ * Switch to pressure mode, and read pressure. We don't need to wait
-+ * here, since both plates are being driven.
-+ */
-+static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
-+{
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+
-+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
-+}
-+
-+/*
-+ * Switch to X position mode and measure Y plate. We switch the plate
-+ * configuration in pressure mode, then switch to position mode. This
-+ * gives a faster response time. Even so, we need to wait about 55us
-+ * for things to stabilise.
-+ */
-+static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
-+{
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
-+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
-+
-+ udelay(55);
-+
-+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
-+}
-+
-+/*
-+ * Switch to Y position mode and measure X plate. We switch the plate
-+ * configuration in pressure mode, then switch to position mode. This
-+ * gives a faster response time. Even so, we need to wait about 55us
-+ * for things to stabilise.
-+ */
-+static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
-+{
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
-+
-+ udelay(55);
-+
-+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
-+}
-+
-+/*
-+ * Switch to X plate resistance mode. Set MX to ground, PX to
-+ * supply. Measure current.
-+ */
-+static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
-+{
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
-+}
-+
-+/*
-+ * Switch to Y plate resistance mode. Set MY to ground, PY to
-+ * supply. Measure current.
-+ */
-+static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
-+{
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
-+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-+ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
-+}
-+
-+/*
-+ * This is a RT kernel thread that handles the ADC accesses
-+ * (mainly so we can use semaphores in the UCB1200 core code
-+ * to serialise accesses to the ADC, and in the UCB1400 case where
-+ * any register access may sleep).
-+ */
-+static int ucb1x00_thread(void *_ts)
-+{
-+ struct ucb1x00_ts *ts = _ts;
-+ struct task_struct *tsk = current;
-+ int valid;
-+
-+ ts->rtask = tsk;
-+
-+ daemonize("ktsd");
-+ /* only want to receive SIGKILL */
-+ allow_signal(SIGKILL);
-+
-+ /*
-+ * We could run as a real-time thread. However, thus far
-+ * this doesn't seem to be necessary.
-+ */
-+// tsk->policy = SCHED_FIFO;
-+// tsk->rt_priority = 1;
-+
-+ complete(&ts->init_exit);
-+
-+ valid = 0;
-+
-+ for (;;) {
-+ unsigned int x, y, p, val;
-+
-+ ts->restart = 0;
-+
-+ ucb1x00_adc_enable(ts->ucb);
-+
-+ x = ucb1x00_ts_read_xpos(ts);
-+ y = ucb1x00_ts_read_ypos(ts);
-+ p = ucb1x00_ts_read_pressure(ts);
-+
-+ /*
-+ * Switch back to interrupt mode.
-+ */
-+ ucb1x00_ts_mode_int(ts);
-+ ucb1x00_adc_disable(ts->ucb);
-+
-+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-+ schedule_timeout(HZ / 100);
-+ if (signal_pending(tsk))
-+ break;
-+
-+ ucb1x00_enable(ts->ucb);
-+ val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
-+
-+ if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) {
-+ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
-+ ucb1x00_disable(ts->ucb);
-+
-+ /*
-+ * If we spat out a valid sample set last time,
-+ * spit out a "pen off" sample here.
-+ */
-+ if (valid) {
-+ ucb1x00_ts_event_release(ts);
-+ valid = 0;
-+ }
-+
-+ /*
-+ * Since ucb1x00_enable_irq() might sleep due
-+ * to the way the UCB1400 regs are accessed, we
-+ * can't use set_task_state() before that call,
-+ * and not changing state before enabling the
-+ * interrupt is racy. A semaphore solves all
-+ * those issues quite nicely.
-+ */
-+ down_interruptible(&ts->irq_wait);
-+ } else {
-+ ucb1x00_disable(ts->ucb);
-+
-+ /*
-+ * Filtering is policy. Policy belongs in user
-+ * space. We therefore leave it to user space
-+ * to do any filtering they please.
-+ */
-+ if (!ts->restart) {
-+ ucb1x00_ts_evt_add(ts, p, x, y);
-+ valid = 1;
-+ }
-+
-+ set_task_state(tsk, TASK_INTERRUPTIBLE);
-+ }
-+
-+ schedule_timeout(HZ / 100);
-+ if (signal_pending(tsk))
-+ break;
-+ }
-+
-+ ts->rtask = NULL;
-+ complete_and_exit(&ts->init_exit, 0);
-+}
-+
-+/*
-+ * We only detect touch screen _touches_ with this interrupt
-+ * handler, and even then we just schedule our task.
-+ */
-+static void ucb1x00_ts_irq(int idx, void *id)
-+{
-+ struct ucb1x00_ts *ts = id;
-+ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
-+ up(&ts->irq_wait);
-+}
-+
-+static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
-+{
-+ input_report_abs(&ts->idev, ABS_PRESSURE, 0);
-+}
-+
-+static int ucb1x00_ts_open(struct input_dev *idev)
-+{
-+ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
-+ int ret = 0;
-+
-+ if (down_interruptible(&ts->sem))
-+ return -EINTR;
-+
-+ if (ts->use_count++ != 0)
-+ goto out;
-+
-+ if (ts->rtask)
-+ panic("ucb1x00: rtask running?");
-+
-+ sema_init(&ts->irq_wait, 0);
-+ ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
-+ if (ret < 0)
-+ goto out;
-+
-+ /*
-+ * If we do this at all, we should allow the user to
-+ * measure and read the X and Y resistance at any time.
-+ */
-+ ucb1x00_adc_enable(ts->ucb);
-+ ts->x_res = ucb1x00_ts_read_xres(ts);
-+ ts->y_res = ucb1x00_ts_read_yres(ts);
-+ ucb1x00_adc_disable(ts->ucb);
-+
-+ init_completion(&ts->init_exit);
-+ ret = kernel_thread(ucb1x00_thread, ts, CLONE_KERNEL);
-+ if (ret >= 0) {
-+ wait_for_completion(&ts->init_exit);
-+ ret = 0;
-+ } else {
-+ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
-+ }
-+
-+ out:
-+ if (ret)
-+ ts->use_count--;
-+ up(&ts->sem);
-+ return ret;
-+}
-+
-+/*
-+ * Release touchscreen resources. Disable IRQs.
-+ */
-+static void ucb1x00_ts_close(struct input_dev *idev)
-+{
-+ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
-+
-+ down(&ts->sem);
-+ if (--ts->use_count == 0) {
-+ if (ts->rtask) {
-+ send_sig(SIGKILL, ts->rtask, 1);
-+ wait_for_completion(&ts->init_exit);
-+ }
-+
-+ ucb1x00_enable(ts->ucb);
-+ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
-+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
-+ ucb1x00_disable(ts->ucb);
-+ }
-+ up(&ts->sem);
-+}
-+
-+#if 0
-+static int ucb1x00_ts_resume(struct device *_dev, u32 level)
-+{
-+ struct ucb1x00_device *dev = ucb1x00_dev(_dev);
-+ struct ucb1x00_ts *ts = ucb1x00_get_drvdata(dev);
-+
-+ if (level == RESUME_ENABLE && ts->rtask != NULL) {
-+ /*
-+ * Restart the TS thread to ensure the
-+ * TS interrupt mode is set up again
-+ * after sleep.
-+ */
-+ ts->restart = 1;
-+ up(&ts->irq_wait);
-+ }
-+ return 0;
-+}
-+#endif
-+
-+
-+/*
-+ * Initialisation.
-+ */
-+static int ucb1x00_ts_add(struct class_device *dev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+ struct ucb1x00_ts *ts;
-+
-+ ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
-+ if (!ts)
-+ return -ENOMEM;
-+
-+ memset(ts, 0, sizeof(struct ucb1x00_ts));
-+
-+ ts->ucb = ucb;
-+ ts->adcsync = adcsync;
-+ init_MUTEX(&ts->sem);
-+
-+ ts->idev.name = "Touchscreen panel";
-+ ts->idev.id.product = ts->ucb->id;
-+ ts->idev.open = ucb1x00_ts_open;
-+ ts->idev.close = ucb1x00_ts_close;
-+
-+ __set_bit(EV_ABS, ts->idev.evbit);
-+ __set_bit(ABS_X, ts->idev.absbit);
-+ __set_bit(ABS_Y, ts->idev.absbit);
-+ __set_bit(ABS_PRESSURE, ts->idev.absbit);
-+
-+ input_register_device(&ts->idev);
-+
-+ ucb->ts_data = ts;
-+
-+ return 0;
-+}
-+
-+static void ucb1x00_ts_remove(struct class_device *dev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+ struct ucb1x00_ts *ts = ucb->ts_data;
-+
-+ input_unregister_device(&ts->idev);
-+ kfree(ts);
-+}
-+
-+static struct class_interface ucb1x00_ts_interface = {
-+ .add = ucb1x00_ts_add,
-+ .remove = ucb1x00_ts_remove,
-+};
-+
-+static int __init ucb1x00_ts_init(void)
-+{
-+ return ucb1x00_register_interface(&ucb1x00_ts_interface);
-+}
-+
-+static void __exit ucb1x00_ts_exit(void)
-+{
-+ ucb1x00_unregister_interface(&ucb1x00_ts_interface);
-+}
-+
-+#ifndef MODULE
-+
-+/*
-+ * Parse kernel command-line options.
-+ *
-+ * syntax : ucbts=[sync|nosync],...
-+ */
-+static int __init ucb1x00_ts_setup(char *str)
-+{
-+ char *p;
-+
-+ while ((p = strsep(&str, ",")) != NULL) {
-+ if (strcmp(p, "sync") == 0)
-+ adcsync = UCB_SYNC;
-+ }
-+
-+ return 1;
-+}
-+
-+__setup("ucbts=", ucb1x00_ts_setup);
-+
-+#else
-+
-+MODULE_PARM(adcsync, "i");
-+MODULE_PARM_DESC(adcsync, "Enable use of ADCSYNC signal");
-+
-+#endif
-+
-+module_init(ucb1x00_ts_init);
-+module_exit(ucb1x00_ts_exit);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/ucb1x00-core.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,624 @@
-+/*
-+ * linux/drivers/misc/ucb1x00-core.c
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * The UCB1x00 core driver provides basic services for handling IO,
-+ * the ADC, interrupts, and accessing registers. It is designed
-+ * such that everything goes through this layer, thereby providing
-+ * a consistent locking methodology, as well as allowing the drivers
-+ * to be used on other non-MCP-enabled hardware platforms.
-+ *
-+ * Note that all locks are private to this file. Nothing else may
-+ * touch them.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/device.h>
-+
-+#include <asm/dma.h>
-+#include <asm/hardware.h>
-+#include <asm/irq.h>
-+
-+#include "ucb1x00.h"
-+
-+/**
-+ * ucb1x00_io_set_dir - set IO direction
-+ * @ucb: UCB1x00 structure describing chip
-+ * @in: bitfield of IO pins to be set as inputs
-+ * @out: bitfield of IO pins to be set as outputs
-+ *
-+ * Set the IO direction of the ten general purpose IO pins on
-+ * the UCB1x00 chip. The @in bitfield has priority over the
-+ * @out bitfield, in that if you specify a pin as both input
-+ * and output, it will end up as an input.
-+ *
-+ * ucb1x00_enable must have been called to enable the comms
-+ * before using this function.
-+ *
-+ * This function takes a spinlock, disabling interrupts.
-+ */
-+void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ucb->io_lock, flags);
-+ ucb->io_dir |= out;
-+ ucb->io_dir &= ~in;
-+
-+ ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
-+ spin_unlock_irqrestore(&ucb->io_lock, flags);
-+}
-+
-+/**
-+ * ucb1x00_io_write - set or clear IO outputs
-+ * @ucb: UCB1x00 structure describing chip
-+ * @set: bitfield of IO pins to set to logic '1'
-+ * @clear: bitfield of IO pins to set to logic '0'
-+ *
-+ * Set the IO output state of the specified IO pins. The value
-+ * is retained if the pins are subsequently configured as inputs.
-+ * The @clear bitfield has priority over the @set bitfield -
-+ * outputs will be cleared.
-+ *
-+ * ucb1x00_enable must have been called to enable the comms
-+ * before using this function.
-+ *
-+ * This function takes a spinlock, disabling interrupts.
-+ */
-+void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ucb->io_lock, flags);
-+ ucb->io_out |= set;
-+ ucb->io_out &= ~clear;
-+
-+ ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
-+ spin_unlock_irqrestore(&ucb->io_lock, flags);
-+}
-+
-+/**
-+ * ucb1x00_io_read - read the current state of the IO pins
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Return a bitfield describing the logic state of the ten
-+ * general purpose IO pins.
-+ *
-+ * ucb1x00_enable must have been called to enable the comms
-+ * before using this function.
-+ *
-+ * This function does not take any semaphores or spinlocks.
-+ */
-+unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
-+{
-+ return ucb1x00_reg_read(ucb, UCB_IO_DATA);
-+}
-+
-+/*
-+ * UCB1300 data sheet says we must:
-+ * 1. enable ADC => 5us (including reference startup time)
-+ * 2. select input => 51*tsibclk => 4.3us
-+ * 3. start conversion => 102*tsibclk => 8.5us
-+ * (tsibclk = 1/11981000)
-+ * Period between SIB 128-bit frames = 10.7us
-+ */
-+
-+/**
-+ * ucb1x00_adc_enable - enable the ADC converter
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Enable the ucb1x00 and ADC converter on the UCB1x00 for use.
-+ * Any code wishing to use the ADC converter must call this
-+ * function prior to using it.
-+ *
-+ * This function takes the ADC semaphore to prevent two or more
-+ * concurrent uses, and therefore may sleep. As a result, it
-+ * can only be called from process context, not interrupt
-+ * context.
-+ *
-+ * You should release the ADC as soon as possible using
-+ * ucb1x00_adc_disable.
-+ */
-+void ucb1x00_adc_enable(struct ucb1x00 *ucb)
-+{
-+ down(&ucb->adc_sem);
-+
-+ ucb->adc_cr |= UCB_ADC_ENA;
-+
-+ ucb1x00_enable(ucb);
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
-+}
-+
-+/**
-+ * ucb1x00_adc_read - read the specified ADC channel
-+ * @ucb: UCB1x00 structure describing chip
-+ * @adc_channel: ADC channel mask
-+ * @sync: wait for syncronisation pulse.
-+ *
-+ * Start an ADC conversion and wait for the result. Note that
-+ * synchronised ADC conversions (via the ADCSYNC pin) must wait
-+ * until the trigger is asserted and the conversion is finished.
-+ *
-+ * This function currently spins waiting for the conversion to
-+ * complete (2 frames max without sync).
-+ *
-+ * If called for a synchronised ADC conversion, it may sleep
-+ * with the ADC semaphore held.
-+ *
-+ * See ucb1x00.h for definition of the UCB_ADC_DAT macro. It
-+ * addresses a bug in the ucb1200/1300 which, of course, Philips
-+ * decided to finally fix in the ucb1400 ;-) -jws
-+ */
-+unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
-+{
-+ unsigned int val;
-+
-+ if (sync)
-+ adc_channel |= UCB_ADC_SYNC_ENA;
-+
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel);
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
-+
-+ for (;;) {
-+ val = ucb1x00_reg_read(ucb, UCB_ADC_DATA);
-+ if (val & UCB_ADC_DAT_VAL)
-+ break;
-+ /* yield to other processes */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(1);
-+ }
-+
-+ return UCB_ADC_DAT(val);
-+}
-+
-+/**
-+ * ucb1x00_adc_disable - disable the ADC converter
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Disable the ADC converter and release the ADC semaphore.
-+ */
-+void ucb1x00_adc_disable(struct ucb1x00 *ucb)
-+{
-+ ucb->adc_cr &= ~UCB_ADC_ENA;
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
-+ ucb1x00_disable(ucb);
-+
-+ up(&ucb->adc_sem);
-+}
-+
-+/*
-+ * UCB1x00 Interrupt handling.
-+ *
-+ * The UCB1x00 can generate interrupts when the SIBCLK is stopped.
-+ * Since we need to read an internal register, we must re-enable
-+ * SIBCLK to talk to the chip. We leave the clock running until
-+ * we have finished processing all interrupts from the chip.
-+ *
-+ * A restriction with interrupts exists when using the ucb1400, as
-+ * the codec read/write routines may sleep while waiting for codec
-+ * access completion and uses semaphores for access control to the
-+ * AC97 bus. A complete codec read cycle could take anywhere from
-+ * 60 to 100uSec so we *definitely* don't want to spin inside the
-+ * interrupt handler waiting for codec access. So, we handle the
-+ * interrupt by scheduling a RT kernel thread to run in process
-+ * context instead of interrupt context.
-+ */
-+
-+static int ucb1x00_thread(void *_ucb)
-+{
-+ struct task_struct *tsk = current;
-+ DECLARE_WAITQUEUE(wait, tsk);
-+ struct ucb1x00 *ucb = _ucb;
-+ struct ucb1x00_irq *irq;
-+ unsigned int isr, i;
-+
-+ ucb->rtask = tsk;
-+
-+ daemonize();
-+ reparent_to_init();
-+ tsk->tty = NULL;
-+ tsk->policy = SCHED_FIFO;
-+ tsk->rt_priority = 1;
-+ strcpy(tsk->comm, "kUCB1x00d");
-+
-+ /* only want to receive SIGKILL */
-+ spin_lock_irq(&tsk->sigmask_lock);
-+ siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
-+ recalc_sigpending();
-+ spin_unlock_irq(&tsk->sigmask_lock);
-+
-+ add_wait_queue(&ucb->irq_wait, &wait);
-+ set_task_state(tsk, TASK_INTERRUPTIBLE);
-+ complete(&ucb->complete);
-+
-+ for (;;) {
-+ if (signal_pending(tsk))
-+ break;
-+ enable_irq(ucb->irq);
-+ schedule();
-+
-+ ucb1x00_enable(ucb);
-+ isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
-+
-+ for (i = 0, irq = ucb->irq_handler;
-+ i < 16 && isr;
-+ i++, isr >>= 1, irq++)
-+ if (isr & 1 && irq->fn)
-+ irq->fn(i, irq->devid);
-+ ucb1x00_disable(ucb);
-+
-+ set_task_state(tsk, TASK_INTERRUPTIBLE);
-+ }
-+
-+ remove_wait_queue(&ucb->irq_wait, &wait);
-+ ucb->rtask = NULL;
-+ complete_and_exit(&ucb->complete, 0);
-+}
-+
-+static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
-+{
-+ struct ucb1x00 *ucb = devid;
-+ disable_irq(irqnr);
-+ wake_up(&ucb->irq_wait);
-+ return IRQ_HANDLED;
-+}
-+
-+/**
-+ * ucb1x00_hook_irq - hook a UCB1x00 interrupt
-+ * @ucb: UCB1x00 structure describing chip
-+ * @idx: interrupt index
-+ * @fn: function to call when interrupt is triggered
-+ * @devid: device id to pass to interrupt handler
-+ *
-+ * Hook the specified interrupt. You can only register one handler
-+ * for each interrupt source. The interrupt source is not enabled
-+ * by this function; use ucb1x00_enable_irq instead.
-+ *
-+ * Interrupt handlers will be called with other interrupts enabled.
-+ *
-+ * Returns zero on success, or one of the following errors:
-+ * -EINVAL if the interrupt index is invalid
-+ * -EBUSY if the interrupt has already been hooked
-+ */
-+int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
-+{
-+ struct ucb1x00_irq *irq;
-+ int ret = -EINVAL;
-+
-+ if (idx < 16) {
-+ irq = ucb->irq_handler + idx;
-+ ret = -EBUSY;
-+
-+ spin_lock_irq(&ucb->lock);
-+ if (irq->fn == NULL) {
-+ irq->devid = devid;
-+ irq->fn = fn;
-+ ret = 0;
-+ }
-+ spin_unlock_irq(&ucb->lock);
-+ }
-+ return ret;
-+}
-+
-+/**
-+ * ucb1x00_enable_irq - enable an UCB1x00 interrupt source
-+ * @ucb: UCB1x00 structure describing chip
-+ * @idx: interrupt index
-+ * @edges: interrupt edges to enable
-+ *
-+ * Enable the specified interrupt to trigger on %UCB_RISING,
-+ * %UCB_FALLING or both edges. The interrupt should have been
-+ * hooked by ucb1x00_hook_irq.
-+ */
-+void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
-+{
-+ unsigned long flags;
-+
-+ if (idx < 16) {
-+ spin_lock_irqsave(&ucb->lock, flags);
-+
-+ ucb1x00_enable(ucb);
-+
-+ /* This prevents spurious interrupts on the UCB1400 */
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
-+
-+ if (edges & UCB_RISING) {
-+ ucb->irq_ris_enbl |= 1 << idx;
-+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-+ }
-+ if (edges & UCB_FALLING) {
-+ ucb->irq_fal_enbl |= 1 << idx;
-+ ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-+ }
-+ ucb1x00_disable(ucb);
-+ spin_unlock_irqrestore(&ucb->lock, flags);
-+ }
-+}
-+
-+/**
-+ * ucb1x00_disable_irq - disable an UCB1x00 interrupt source
-+ * @ucb: UCB1x00 structure describing chip
-+ * @edges: interrupt edges to disable
-+ *
-+ * Disable the specified interrupt triggering on the specified
-+ * (%UCB_RISING, %UCB_FALLING or both) edges.
-+ */
-+void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
-+{
-+ unsigned long flags;
-+
-+ if (idx < 16) {
-+ spin_lock_irqsave(&ucb->lock, flags);
-+
-+ ucb1x00_enable(ucb);
-+ if (edges & UCB_RISING) {
-+ ucb->irq_ris_enbl &= ~(1 << idx);
-+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-+ }
-+ if (edges & UCB_FALLING) {
-+ ucb->irq_fal_enbl &= ~(1 << idx);
-+ ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-+ }
-+ ucb1x00_disable(ucb);
-+ spin_unlock_irqrestore(&ucb->lock, flags);
-+ }
-+}
-+
-+/**
-+ * ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
-+ * @ucb: UCB1x00 structure describing chip
-+ * @idx: interrupt index
-+ * @devid: device id.
-+ *
-+ * Disable the interrupt source and remove the handler. devid must
-+ * match the devid passed when hooking the interrupt.
-+ *
-+ * Returns zero on success, or one of the following errors:
-+ * -EINVAL if the interrupt index is invalid
-+ * -ENOENT if devid does not match
-+ */
-+int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
-+{
-+ struct ucb1x00_irq *irq;
-+ int ret;
-+
-+ if (idx >= 16)
-+ goto bad;
-+
-+ irq = ucb->irq_handler + idx;
-+ ret = -ENOENT;
-+
-+ spin_lock_irq(&ucb->lock);
-+ if (irq->devid == devid) {
-+ ucb->irq_ris_enbl &= ~(1 << idx);
-+ ucb->irq_fal_enbl &= ~(1 << idx);
-+
-+ ucb1x00_enable(ucb);
-+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-+ ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-+ ucb1x00_disable(ucb);
-+
-+ irq->fn = NULL;
-+ irq->devid = NULL;
-+ ret = 0;
-+ }
-+ spin_unlock_irq(&ucb->lock);
-+ return ret;
-+
-+bad:
-+ printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
-+ return -EINVAL;
-+}
-+
-+/*
-+ * Try to probe our interrupt, rather than relying on lots of
-+ * hard-coded machine dependencies. For reference, the expected
-+ * IRQ mappings are:
-+ *
-+ * Machine Default IRQ
-+ * adsbitsy IRQ_GPCIN4
-+ * cerf IRQ_GPIO_UCB1200_IRQ
-+ * flexanet IRQ_GPIO_GUI
-+ * freebird IRQ_GPIO_FREEBIRD_UCB1300_IRQ
-+ * graphicsclient ADS_EXT_IRQ(8)
-+ * graphicsmaster ADS_EXT_IRQ(8)
-+ * lart LART_IRQ_UCB1200
-+ * omnimeter IRQ_GPIO23
-+ * pfs168 IRQ_GPIO_UCB1300_IRQ
-+ * simpad IRQ_GPIO_UCB1300_IRQ
-+ * shannon SHANNON_IRQ_GPIO_IRQ_CODEC
-+ * yopy IRQ_GPIO_UCB1200_IRQ
-+ */
-+static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
-+{
-+ unsigned long mask;
-+
-+ mask = probe_irq_on();
-+ if (!mask)
-+ return NO_IRQ;
-+
-+ /*
-+ * Enable the ADC interrupt.
-+ */
-+ ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
-+ ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
-+
-+ /*
-+ * Cause an ADC interrupt.
-+ */
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
-+
-+ /*
-+ * Wait for the conversion to complete.
-+ */
-+ while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0);
-+ ucb1x00_reg_write(ucb, UCB_ADC_CR, 0);
-+
-+ /*
-+ * Disable and clear interrupt.
-+ */
-+ ucb1x00_reg_write(ucb, UCB_IE_RIS, 0);
-+ ucb1x00_reg_write(ucb, UCB_IE_FAL, 0);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
-+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
-+
-+ /*
-+ * Read triggered interrupt.
-+ */
-+ return probe_irq_off(mask);
-+}
-+
-+static int ucb1x00_probe(struct mcp *mcp)
-+{
-+ struct ucb1x00 *ucb;
-+ unsigned int id;
-+ int ret = -ENODEV;
-+
-+ mcp_enable(mcp);
-+ id = mcp_reg_read(mcp, UCB_ID);
-+
-+ if (id != UCB_ID_1200 && id != UCB_ID_1300) {
-+ printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
-+ goto err_disable;
-+ }
-+
-+ ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
-+ ret = -ENOMEM;
-+ if (!ucb)
-+ goto err_disable;
-+
-+ memset(ucb, 0, sizeof(struct ucb1x00));
-+
-+ ucb->cdev.class = &ucb1x00_class;
-+ ucb->cdev.dev = &mcp->attached_device;
-+ strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
-+
-+ spin_lock_init(&ucb->lock);
-+ spin_lock_init(&ucb->io_lock);
-+ sema_init(&ucb->adc_sem, 1);
-+
-+ ucb->id = id;
-+ ucb->mcp = mcp;
-+ ucb->irq = ucb1x00_detect_irq(ucb);
-+ if (ucb->irq == NO_IRQ) {
-+ printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
-+ ret = -ENODEV;
-+ goto err_free;
-+ }
-+
-+ ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb);
-+ if (ret) {
-+ printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-+ ucb->irq, ret);
-+ goto err_free;
-+ }
-+
-+ set_irq_type(ucb->irq, IRQT_RISING);
-+ mcp_set_drvdata(mcp, ucb);
-+
-+ ret = class_device_register(&ucb->cdev);
-+ if (ret) {
-+ free_irq(ucb->irq, ucb);
-+ err_free:
-+ kfree(ucb);
-+ }
-+ err_disable:
-+ mcp_disable(mcp);
-+ return ret;
-+}
-+
-+static void ucb1x00_remove(struct mcp *mcp)
-+{
-+ struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-+
-+ class_device_unregister(&ucb->cdev);
-+ free_irq(ucb->irq, ucb);
-+}
-+
-+static void ucb1x00_release(struct class_device *dev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+ kfree(ucb);
-+}
-+
-+static struct class ucb1x00_class = {
-+ .name = "ucb1x00",
-+ .release = ucb1x00_release,
-+};
-+
-+int ucb1x00_register_interface(struct class_interface *intf)
-+{
-+ intf->class = &ucb1x00_class;
-+ return class_interface_register(intf);
-+}
-+
-+void ucb1x00_unregister_interface(struct class_interface *intf)
-+{
-+ class_interface_unregister(intf);
-+}
-+
-+static struct mcp_driver ucb1x00_driver = {
-+ .drv = {
-+ .name = "ucb1x00",
-+ },
-+ .probe = ucb1x00_probe,
-+ .remove = ucb1x00_remove,
-+};
-+
-+static int __init ucb1x00_init(void)
-+{
-+ int ret = class_register(&ucb1x00_class);
-+ if (ret == 0) {
-+ ret = mcp_driver_register(&ucb1x00_driver);
-+ if (ret)
-+ class_unregister(&ucb1x00_class);
-+ }
-+ return ret;
-+}
-+
-+static void __exit ucb1x00_exit(void)
-+{
-+ mcp_driver_unregister(&ucb1x00_driver);
-+ class_unregister(&ucb1x00_class);
-+}
-+
-+module_init(ucb1x00_init);
-+module_exit(ucb1x00_exit);
-+
-+EXPORT_SYMBOL(ucb1x00_class);
-+
-+EXPORT_SYMBOL(ucb1x00_io_set_dir);
-+EXPORT_SYMBOL(ucb1x00_io_write);
-+EXPORT_SYMBOL(ucb1x00_io_read);
-+
-+EXPORT_SYMBOL(ucb1x00_adc_enable);
-+EXPORT_SYMBOL(ucb1x00_adc_read);
-+EXPORT_SYMBOL(ucb1x00_adc_disable);
-+
-+EXPORT_SYMBOL(ucb1x00_hook_irq);
-+EXPORT_SYMBOL(ucb1x00_free_irq);
-+EXPORT_SYMBOL(ucb1x00_enable_irq);
-+EXPORT_SYMBOL(ucb1x00_disable_irq);
-+
-+EXPORT_SYMBOL(ucb1x00_register_interface);
-+EXPORT_SYMBOL(ucb1x00_unregister_interface);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("UCB1x00 core driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/switches-ucb1x00.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,214 @@
-+/*
-+ * linux/drivers/misc/switches-ucb1x00.c
-+ *
-+ * Copyright (C) 2001 John Dorsey
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 19 December 2001 - created from sa1100_switches.c.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/device.h>
-+
-+#include <asm/dma.h>
-+#include <asm/hardware.h>
-+#include <asm/irq.h>
-+#include <asm/mach-types.h>
-+
-+#ifdef CONFIG_SA1100_ASSABET
-+#include <asm/arch/assabet.h>
-+#endif
-+
-+#include "switches.h"
-+#include "ucb1x00.h"
-+
-+
-+static void switches_ucb1x00_handler(int irq, void *devid);
-+
-+
-+#ifdef CONFIG_SA1100_ASSABET
-+
-+/* Assabet
-+ * ^^^^^^^
-+ * Six switches are routed to GPIO pins on the UCB1300: S3 -- S8.
-+ * This code sets bits in the range [3, 8] in the mask that we
-+ * return to userland. Note that we transpose signals SW7 and SW8;
-+ * see assabet_switches_ucb1x00_handler().
-+ */
-+
-+static int assabet_switches_ucb1x00_init(struct ucb1x00 *ucb)
-+{
-+ int i;
-+
-+ ucb1x00_enable(ucb);
-+
-+ ucb1x00_io_set_dir(ucb,
-+ UCB_IO_0 | UCB_IO_1 | UCB_IO_2 |
-+ UCB_IO_3 | UCB_IO_4 | UCB_IO_5, 0);
-+
-+ for (i = 0; i < 6; ++i) {
-+ ucb1x00_enable_irq(ucb, i, UCB_RISING | UCB_FALLING);
-+
-+ if (ucb1x00_hook_irq(ucb, i,
-+ switches_ucb1x00_handler, ucb) < 0) {
-+ printk(KERN_ERR "%s: unable to hook IRQ for "
-+ "UCB1300 IO_%d\n", SWITCHES_NAME, i);
-+
-+ /* FIXME: BUGGY ERROR HANDLING */
-+ return -EBUSY;
-+ }
-+
-+ }
-+
-+ ucb1x00_disable(ucb);
-+
-+ return 0;
-+
-+}
-+
-+static void assabet_switches_ucb1x00_shutdown(struct ucb1x00 *ucb)
-+{
-+ int i;
-+
-+ ucb1x00_enable(ucb);
-+
-+ for (i = 5; i >= 0; --i) {
-+ ucb1x00_disable_irq(ucb, i, UCB_RISING | UCB_FALLING);
-+
-+ /* Only error conditions are ENOENT and EINVAL; silently
-+ * ignore:
-+ */
-+ ucb1x00_free_irq(ucb, i, ucb);
-+ }
-+
-+ ucb1x00_disable(ucb);
-+}
-+
-+static void assabet_switches_ucb1x00_handler(struct ucb1x00 *ucb, int irq, switches_mask_t *mask)
-+{
-+ unsigned int last, this;
-+ static unsigned int states = 0;
-+
-+ last = ((states & (1 << irq)) != 0);
-+ this = ((ucb1x00_io_read(ucb) & (1 << irq)) != 0);
-+
-+ if (last == this) /* debounce */
-+ return;
-+
-+ /* Intel StrongARM SA-1110 Development Board
-+ * Schematics Figure 5, Sheet 5 of 12
-+ *
-+ * See switches S8 and S7. Notice their
-+ * relationship to signals SW7 and SW8. Hmmm.
-+ */
-+
-+ switch (irq) {
-+
-+ case 4:
-+
-+ SWITCHES_SET(mask, 8, this);
-+ break;
-+
-+ case 5:
-+
-+ SWITCHES_SET(mask, 7, this);
-+ break;
-+
-+ default:
-+
-+ SWITCHES_SET(mask, irq + 3, this);
-+
-+ }
-+
-+ states = this ? (states | (1 << irq)) : (states & ~(1 << irq));
-+
-+}
-+#endif /* CONFIG_SA1100_ASSABET */
-+
-+
-+/* switches_ucb1x00_handler()
-+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
-+ * This routine is a generalized handler for UCB1x00 GPIO switches
-+ * which calls a board-specific service routine and passes an event
-+ * mask to the core event handler. This routine is appropriate for
-+ * systems which use the ucb1x00 framework, and can be registered
-+ * using ucb1x00_hook_irq().
-+ */
-+static void switches_ucb1x00_handler(int irq, void *devid)
-+{
-+ struct ucb1x00 *ucb = devid;
-+ switches_mask_t mask;
-+
-+ SWITCHES_ZERO(&mask);
-+
-+ /* Porting note: call a board-specific UCB1x00 switch handler here.
-+ * The handler can assume that sufficient storage for `mask' has
-+ * been allocated, and that the corresponding switches_mask_t
-+ * structure has been zeroed.
-+ */
-+
-+#ifdef CONFIG_SA1100_ASSABET
-+ if (machine_is_assabet()) {
-+ assabet_switches_ucb1x00_handler(ucb, irq, &mask);
-+ }
-+#endif
-+
-+ switches_event(&mask);
-+}
-+
-+static int switches_add(struct class_device *dev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+ int ret = -ENODEV;
-+
-+#ifdef CONFIG_SA1100_ASSABET
-+ if (machine_is_assabet()) {
-+ ret = assabet_switches_ucb1x00_init(ucb);
-+ }
-+#endif
-+ /* Porting note: call a board-specific init routine here. */
-+
-+ return ret;
-+}
-+
-+static void switches_remove(struct class_device *dev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
-+
-+ /* Porting note: call a board-specific shutdown routine here. */
-+
-+#ifdef CONFIG_SA1100_ASSABET
-+ if (machine_is_assabet()) {
-+ assabet_switches_ucb1x00_shutdown(ucb);
-+ }
-+#endif
-+}
-+
-+static struct class_interface ucb1x00_switches_interface = {
-+ .add = switches_add,
-+ .remove = switches_remove,
-+};
-+
-+static int __init switches_ucb1x00_init(void)
-+{
-+ return ucb1x00_register_interface(&ucb1x00_switches_interface);
-+}
-+
-+static void __exit switches_ucb1x00_exit(void)
-+{
-+ ucb1x00_unregister_interface(&ucb1x00_switches_interface);
-+}
-+
-+module_init(switches_ucb1x00_init);
-+module_exit(switches_ucb1x00_exit);
-+
-+MODULE_DESCRIPTION("ucb1x00 switches driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/switches-core.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,200 @@
-+/*
-+ * linux/drivers/misc/switches-core.c
-+ *
-+ * Copyright (C) 2000-2001 John Dorsey
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 5 October 2000 - created.
-+ *
-+ * 25 October 2000 - userland file interface added.
-+ *
-+ * 13 January 2001 - added support for Spot.
-+ *
-+ * 11 September 2001 - UCB1200 driver framework support added.
-+ *
-+ * 19 December 2001 - separated out SA-1100 and UCB1x00 code.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/kernel.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/poll.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/wait.h>
-+
-+#include <asm/uaccess.h>
-+
-+#include "switches.h"
-+
-+
-+MODULE_AUTHOR("John Dorsey");
-+MODULE_DESCRIPTION("Console switch support");
-+MODULE_LICENSE("GPL");
-+
-+
-+struct switches_action {
-+ struct list_head list;
-+ switches_mask_t mask;
-+};
-+
-+
-+static int switches_users = 0;
-+
-+static spinlock_t switches_lock = SPIN_LOCK_UNLOCKED;
-+
-+DECLARE_WAIT_QUEUE_HEAD(switches_wait);
-+LIST_HEAD(switches_event_queue);
-+
-+
-+static ssize_t switches_read(struct file *file, char *buffer,
-+ size_t count, loff_t *pos)
-+{
-+ unsigned long flags;
-+ struct list_head *event;
-+ struct switches_action *action;
-+
-+ if (count < sizeof(struct switches_mask_t))
-+ return -EINVAL;
-+
-+ while (list_empty(&switches_event_queue)) {
-+
-+ if (file->f_flags & O_NDELAY)
-+ return -EAGAIN;
-+
-+ interruptible_sleep_on(&switches_wait);
-+
-+ if (signal_pending(current))
-+ return -ERESTARTSYS;
-+
-+ }
-+
-+ if (verify_area(VERIFY_WRITE, buffer, sizeof(struct switches_mask_t)))
-+ return -EFAULT;
-+
-+ spin_lock_irqsave(&switches_lock, flags);
-+
-+ event = switches_event_queue.next;
-+ action = list_entry(event, struct switches_action, list);
-+ copy_to_user(buffer, &(action->mask), sizeof(struct switches_mask_t));
-+ list_del(event);
-+ kfree(action);
-+
-+ spin_unlock_irqrestore(&switches_lock, flags);
-+
-+ return 0;
-+
-+}
-+
-+static ssize_t switches_write(struct file *file, const char *buffer,
-+ size_t count, loff_t *ppos)
-+{
-+ return -EINVAL;
-+}
-+
-+static unsigned int switches_poll(struct file *file, poll_table *wait)
-+{
-+
-+ poll_wait(file, &switches_wait, wait);
-+
-+ if (!list_empty(&switches_event_queue))
-+ return POLLIN | POLLRDNORM;
-+
-+ return 0;
-+
-+}
-+
-+static int switches_open(struct inode *inode, struct file *file)
-+{
-+
-+ if (switches_users > 0)
-+ return -EBUSY;
-+
-+ ++switches_users;
-+ return 0;
-+
-+}
-+
-+static int switches_release(struct inode *inode, struct file *file)
-+{
-+
-+ --switches_users;
-+ return 0;
-+
-+}
-+
-+static struct file_operations switches_ops = {
-+ .owner = THIS_MODULE,
-+ .read = switches_read,
-+ .write = switches_write,
-+ .poll = switches_poll,
-+ .open = switches_open,
-+ .release = switches_release,
-+};
-+
-+static struct miscdevice switches_misc = {
-+ .minor = MISC_DYNAMIC_MINOR,
-+ .name = SWITCHES_NAME,
-+ .fops = &switches_ops,
-+};
-+
-+int switches_event(switches_mask_t *mask)
-+{
-+ struct switches_action *action;
-+
-+ if ((switches_users > 0) && (SWITCHES_COUNT(mask) > 0)) {
-+
-+ if ((action = (struct switches_action *)
-+ kmalloc(sizeof(struct switches_action),
-+ GFP_KERNEL)) == NULL) {
-+ printk(KERN_ERR "%s: unable to allocate action "
-+ "descriptor\n", SWITCHES_NAME);
-+ return -1;
-+ }
-+
-+ action->mask = *mask;
-+
-+ spin_lock(&switches_lock);
-+ list_add_tail(&action->list, &switches_event_queue);
-+ spin_unlock(&switches_lock);
-+
-+ wake_up_interruptible(&switches_wait);
-+
-+ }
-+
-+ return 0;
-+
-+}
-+
-+EXPORT_SYMBOL(switches_event);
-+
-+
-+static int __init switches_init(void)
-+{
-+ if (misc_register(&switches_misc) < 0) {
-+ printk(KERN_ERR "%s: unable to register misc device\n",
-+ SWITCHES_NAME);
-+ return -EIO;
-+ }
-+
-+ printk(KERN_INFO "Console switches initialized\n");
-+
-+ return 0;
-+}
-+
-+static void __exit switches_exit(void)
-+{
-+ if (misc_deregister(&switches_misc) < 0)
-+ printk(KERN_ERR "%s: unable to deregister misc device\n",
-+ SWITCHES_NAME);
-+}
-+
-+module_init(switches_init);
-+module_exit(switches_exit);
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/ucb1x00-audio.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,439 @@
-+/*
-+ * linux/drivers/misc/ucb1x00-audio.c
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/sound.h>
-+#include <linux/soundcard.h>
-+#include <linux/list.h>
-+#include <linux/device.h>
-+
-+#include <asm/dma.h>
-+#include <asm/hardware.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+
-+#include "ucb1x00.h"
-+
-+#include "../sound/oss/sa1100-audio.h"
-+
-+#define MAGIC 0x41544154
-+
-+struct ucb1x00_audio {
-+ struct file_operations fops;
-+ struct file_operations mops;
-+ struct ucb1x00 *ucb;
-+ audio_stream_t output_stream;
-+ audio_stream_t input_stream;
-+ audio_state_t state;
-+ unsigned int rate;
-+ int dev_id;
-+ int mix_id;
-+ unsigned int daa_oh_bit;
-+ unsigned int telecom;
-+ unsigned int magic;
-+ unsigned int ctrl_a;
-+ unsigned int ctrl_b;
-+
-+ /* mixer info */
-+ unsigned int mod_cnt;
-+ unsigned short output_level;
-+ unsigned short input_level;
-+};
-+
-+#define REC_MASK (SOUND_MASK_VOLUME | SOUND_MASK_MIC)
-+#define DEV_MASK REC_MASK
-+
-+static int
-+ucb1x00_mixer_ioctl(struct inode *ino, struct file *filp, uint cmd, ulong arg)
-+{
-+ struct ucb1x00_audio *ucba;
-+ unsigned int val, gain;
-+ int ret = 0;
-+
-+ ucba = list_entry(filp->f_op, struct ucb1x00_audio, mops);
-+
-+ if (_IOC_TYPE(cmd) != 'M')
-+ return -EINVAL;
-+
-+ if (cmd == SOUND_MIXER_INFO) {
-+ struct mixer_info mi;
-+
-+ strncpy(mi.id, "UCB1x00", sizeof(mi.id));
-+ strncpy(mi.name, "Philips UCB1x00", sizeof(mi.name));
-+ mi.modify_counter = ucba->mod_cnt;
-+ return copy_to_user((void *)arg, &mi, sizeof(mi)) ? -EFAULT : 0;
-+ }
-+
-+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
-+ unsigned int left, right;
-+
-+ ret = get_user(val, (unsigned int *)arg);
-+ if (ret)
-+ goto out;
-+
-+ left = val & 255;
-+ right = val >> 8;
-+
-+ if (left > 100)
-+ left = 100;
-+ if (right > 100)
-+ right = 100;
-+
-+ gain = (left + right) / 2;
-+
-+ ret = -EINVAL;
-+ if (!ucba->telecom) {
-+ switch(_IOC_NR(cmd)) {
-+ case SOUND_MIXER_VOLUME:
-+ ucba->output_level = gain | gain << 8;
-+ ucba->mod_cnt++;
-+ ucba->ctrl_b = (ucba->ctrl_b & 0xff00) |
-+ ((gain * 31) / 100);
-+ ucb1x00_reg_write(ucba->ucb, UCB_AC_B,
-+ ucba->ctrl_b);
-+ ret = 0;
-+ break;
-+
-+ case SOUND_MIXER_MIC:
-+ ucba->input_level = gain | gain << 8;
-+ ucba->mod_cnt++;
-+ ucba->ctrl_a = (ucba->ctrl_a & 0x7f) |
-+ (((gain * 31) / 100) << 7);
-+ ucb1x00_reg_write(ucba->ucb, UCB_AC_A,
-+ ucba->ctrl_a);
-+ ret = 0;
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
-+ switch (_IOC_NR(cmd)) {
-+ case SOUND_MIXER_VOLUME:
-+ val = ucba->output_level;
-+ break;
-+
-+ case SOUND_MIXER_MIC:
-+ val = ucba->input_level;
-+ break;
-+
-+ case SOUND_MIXER_RECSRC:
-+ case SOUND_MIXER_RECMASK:
-+ val = ucba->telecom ? 0 : REC_MASK;
-+ break;
-+
-+ case SOUND_MIXER_DEVMASK:
-+ val = ucba->telecom ? 0 : DEV_MASK;
-+ break;
-+
-+ case SOUND_MIXER_CAPS:
-+ case SOUND_MIXER_STEREODEVS:
-+ val = 0;
-+ break;
-+
-+ default:
-+ val = 0;
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ if (ret == 0)
-+ ret = put_user(val, (int *)arg);
-+ }
-+ out:
-+ return ret;
-+}
-+
-+static int ucb1x00_audio_setrate(struct ucb1x00_audio *ucba, int rate)
-+{
-+ unsigned int div_rate = ucb1x00_clkrate(ucba->ucb) / 32;
-+ unsigned int div;
-+
-+ div = (div_rate + (rate / 2)) / rate;
-+ if (div < 6)
-+ div = 6;
-+ if (div > 127)
-+ div = 127;
-+
-+ ucba->ctrl_a = (ucba->ctrl_a & ~0x7f) | div;
-+
-+ if (ucba->telecom) {
-+ ucb1x00_reg_write(ucba->ucb, UCB_TC_B, 0);
-+ ucb1x00_set_telecom_divisor(ucba->ucb, div * 32);
-+ ucb1x00_reg_write(ucba->ucb, UCB_TC_A, ucba->ctrl_a);
-+ ucb1x00_reg_write(ucba->ucb, UCB_TC_B, ucba->ctrl_b);
-+ } else {
-+ ucb1x00_reg_write(ucba->ucb, UCB_AC_B, 0);
-+ ucb1x00_set_audio_divisor(ucba->ucb, div * 32);
-+ ucb1x00_reg_write(ucba->ucb, UCB_AC_A, ucba->ctrl_a);
-+ ucb1x00_reg_write(ucba->ucb, UCB_AC_B, ucba->ctrl_b);
-+ }
-+
-+ ucba->rate = div_rate / div;
-+
-+ return ucba->rate;
-+}
-+
-+static int ucb1x00_audio_getrate(struct ucb1x00_audio *ucba)
-+{
-+ return ucba->rate;
-+}
-+
-+static void ucb1x00_audio_startup(void *data)
-+{
-+ struct ucb1x00_audio *ucba = data;
-+
-+ ucb1x00_enable(ucba->ucb);
-+ ucb1x00_audio_setrate(ucba, ucba->rate);
-+
-+ ucb1x00_reg_write(ucba->ucb, UCB_MODE, UCB_MODE_DYN_VFLAG_ENA);
-+
-+ /*
-+ * Take off-hook
-+ */
-+ if (ucba->daa_oh_bit)
-+ ucb1x00_io_write(ucba->ucb, 0, ucba->daa_oh_bit);
-+}
-+
-+static void ucb1x00_audio_shutdown(void *data)
-+{
-+ struct ucb1x00_audio *ucba = data;
-+
-+ /*
-+ * Place on-hook
-+ */
-+ if (ucba->daa_oh_bit)
-+ ucb1x00_io_write(ucba->ucb, ucba->daa_oh_bit, 0);
-+
-+ ucb1x00_reg_write(ucba->ucb, ucba->telecom ? UCB_TC_B : UCB_AC_B, 0);
-+ ucb1x00_disable(ucba->ucb);
-+}
-+
-+static int
-+ucb1x00_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-+{
-+ struct ucb1x00_audio *ucba;
-+ int val, ret = 0;
-+
-+ ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
-+
-+ /*
-+ * Make sure we have our magic number
-+ */
-+ if (ucba->magic != MAGIC)
-+ return -ENODEV;
-+
-+ switch (cmd) {
-+ case SNDCTL_DSP_STEREO:
-+ ret = get_user(val, (int *)arg);
-+ if (ret)
-+ return ret;
-+ if (val != 0)
-+ return -EINVAL;
-+ val = 0;
-+ break;
-+
-+ case SNDCTL_DSP_CHANNELS:
-+ case SOUND_PCM_READ_CHANNELS:
-+ val = 1;
-+ break;
-+
-+ case SNDCTL_DSP_SPEED:
-+ ret = get_user(val, (int *)arg);
-+ if (ret)
-+ return ret;
-+ val = ucb1x00_audio_setrate(ucba, val);
-+ break;
-+
-+ case SOUND_PCM_READ_RATE:
-+ val = ucb1x00_audio_getrate(ucba);
-+ break;
-+
-+ case SNDCTL_DSP_SETFMT:
-+ case SNDCTL_DSP_GETFMTS:
-+ val = AFMT_S16_LE;
-+ break;
-+
-+ default:
-+ return ucb1x00_mixer_ioctl(inode, file, cmd, arg);
-+ }
-+
-+ return put_user(val, (int *)arg);
-+}
-+
-+static int ucb1x00_audio_open(struct inode *inode, struct file *file)
-+{
-+ struct ucb1x00_audio *ucba;
-+
-+ ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
-+
-+ return sa1100_audio_attach(inode, file, &ucba->state);
-+}
-+
-+static struct ucb1x00_audio *ucb1x00_audio_alloc(struct ucb1x00 *ucb)
-+{
-+ struct ucb1x00_audio *ucba;
-+
-+ ucba = kmalloc(sizeof(*ucba), GFP_KERNEL);
-+ if (ucba) {
-+ memset(ucba, 0, sizeof(*ucba));
-+
-+ ucba->magic = MAGIC;
-+ ucba->ucb = ucb;
-+ ucba->fops.owner = THIS_MODULE;
-+ ucba->fops.open = ucb1x00_audio_open;
-+ ucba->mops.owner = THIS_MODULE;
-+ ucba->mops.ioctl = ucb1x00_mixer_ioctl;
-+ ucba->state.output_stream = &ucba->output_stream;
-+ ucba->state.input_stream = &ucba->input_stream;
-+ ucba->state.data = ucba;
-+ ucba->state.hw_init = ucb1x00_audio_startup;
-+ ucba->state.hw_shutdown = ucb1x00_audio_shutdown;
-+ ucba->state.client_ioctl = ucb1x00_audio_ioctl;
-+
-+ /* There is a bug in the StrongARM causes corrupt MCP data to be sent to
-+ * the codec when the FIFOs are empty and writes are made to the OS timer
-+ * match register 0. To avoid this we must make sure that data is always
-+ * sent to the codec.
-+ */
-+ ucba->state.need_tx_for_rx = 1;
-+
-+ init_MUTEX(&ucba->state.sem);
-+ ucba->rate = 8000;
-+ }
-+ return ucba;
-+}
-+
-+static struct ucb1x00_audio *ucb1x00_audio_add_one(struct ucb1x00 *ucb, int telecom)
-+{
-+ struct ucb1x00_audio *a;
-+
-+ a = ucb1x00_audio_alloc(ucb);
-+ if (a) {
-+ a->telecom = telecom;
-+
-+ a->input_stream.dev = ucb->cdev.dev;
-+ a->output_stream.dev = ucb->cdev.dev;
-+ a->ctrl_a = 0;
-+
-+ if (a->telecom) {
-+ a->input_stream.dma_dev = ucb->mcp->dma_telco_rd;
-+ a->input_stream.id = "UCB1x00 telco in";
-+ a->output_stream.dma_dev = ucb->mcp->dma_telco_wr;
-+ a->output_stream.id = "UCB1x00 telco out";
-+ a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA;
-+#if 0
-+ a->daa_oh_bit = UCB_IO_8;
-+
-+ ucb1x00_enable(ucb);
-+ ucb1x00_io_write(ucb, a->daa_oh_bit, 0);
-+ ucb1x00_io_set_dir(ucb, UCB_IO_7 | UCB_IO_6, a->daa_oh_bit);
-+ ucb1x00_disable(ucb);
-+#endif
-+ } else {
-+ a->input_stream.dma_dev = ucb->mcp->dma_audio_rd;
-+ a->input_stream.id = "UCB1x00 audio in";
-+ a->output_stream.dma_dev = ucb->mcp->dma_audio_wr;
-+ a->output_stream.id = "UCB1x00 audio out";
-+ a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA;
-+ }
-+
-+ a->dev_id = register_sound_dsp(&a->fops, -1);
-+ a->mix_id = register_sound_mixer(&a->mops, -1);
-+
-+ printk("Sound: UCB1x00 %s: dsp id %d mixer id %d\n",
-+ a->telecom ? "telecom" : "audio",
-+ a->dev_id, a->mix_id);
-+ }
-+
-+ return a;
-+}
-+
-+static void ucb1x00_audio_remove_one(struct ucb1x00_audio *a)
-+{
-+ unregister_sound_dsp(a->dev_id);
-+ unregister_sound_mixer(a->mix_id);
-+ kfree(a);
-+}
-+
-+static int ucb1x00_audio_add(struct class_device *cdev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(cdev);
-+
-+ if (ucb->cdev.dev == NULL || ucb->cdev.dev->dma_mask == NULL)
-+ return -ENXIO;
-+
-+ ucb->audio_data = ucb1x00_audio_add_one(ucb, 0);
-+ ucb->telecom_data = ucb1x00_audio_add_one(ucb, 1);
-+
-+ return 0;
-+}
-+
-+static void ucb1x00_audio_remove(struct class_device *cdev)
-+{
-+ struct ucb1x00 *ucb = classdev_to_ucb1x00(cdev);
-+
-+ ucb1x00_audio_remove_one(ucb->audio_data);
-+ ucb1x00_audio_remove_one(ucb->telecom_data);
-+}
-+
-+#if 0 //def CONFIG_PM
-+static int ucb1x00_audio_suspend(struct ucb1x00 *ucb, u32 state)
-+{
-+ struct ucb1x00_audio *a;
-+
-+ a = ucb->audio_data;
-+ sa1100_audio_suspend(&a->state, state);
-+ a = ucb->telecom_data;
-+ sa1100_audio_suspend(&a->state, state);
-+
-+ return 0;
-+}
-+
-+static int ucb1x00_audio_resume(struct ucb1x00 *ucb)
-+{
-+ struct ucb1x00_audio *a;
-+
-+ a = ucb->audio_data;
-+ sa1100_audio_resume(&a->state);
-+ a = ucb->telecom_data;
-+ sa1100_audio_resume(&a->state);
-+
-+ return 0;
-+}
-+#else
-+#define ucb1x00_audio_suspend NULL
-+#define ucb1x00_audio_resume NULL
-+#endif
-+
-+static struct class_interface ucb1x00_audio_interface = {
-+ .add = ucb1x00_audio_add,
-+ .remove = ucb1x00_audio_remove,
-+};
-+
-+static int __init ucb1x00_audio_init(void)
-+{
-+ return ucb1x00_register_interface(&ucb1x00_audio_interface);
-+}
-+
-+static void __exit ucb1x00_audio_exit(void)
-+{
-+ ucb1x00_unregister_interface(&ucb1x00_audio_interface);
-+}
-+
-+module_init(ucb1x00_audio_init);
-+module_exit(ucb1x00_audio_exit);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("UCB1x00 telecom/audio driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/mcp-sa1100.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,275 @@
-+/*
-+ * linux/drivers/misc/mcp-sa1100.c
-+ *
-+ * Copyright (C) 2001 Russell King
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ *
-+ * SA1100 MCP (Multimedia Communications Port) driver.
-+ *
-+ * MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+#include <linux/device.h>
-+
-+#include <asm/dma.h>
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/system.h>
-+
-+#include <asm/arch/assabet.h>
-+
-+#include "mcp.h"
-+
-+static void
-+mcp_sa1100_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
-+{
-+ unsigned int mccr0;
-+
-+ divisor /= 32;
-+
-+ mccr0 = Ser4MCCR0 & ~0x00007f00;
-+ mccr0 |= divisor << 8;
-+ Ser4MCCR0 = mccr0;
-+}
-+
-+static void
-+mcp_sa1100_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
-+{
-+ unsigned int mccr0;
-+
-+ divisor /= 32;
-+
-+ mccr0 = Ser4MCCR0 & ~0x0000007f;
-+ mccr0 |= divisor;
-+ Ser4MCCR0 = mccr0;
-+}
-+
-+/*
-+ * Write data to the device. The bit should be set after 3 subframe
-+ * times (each frame is 64 clocks). We wait a maximum of 6 subframes.
-+ * We really should try doing something more productive while we
-+ * wait.
-+ */
-+static void
-+mcp_sa1100_write(struct mcp *mcp, unsigned int reg, unsigned int val)
-+{
-+ int ret = -ETIME;
-+ int i;
-+
-+ Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
-+
-+ for (i = 0; i < 2; i++) {
-+ udelay(mcp->rw_timeout);
-+ if (Ser4MCSR & MCSR_CWC) {
-+ ret = 0;
-+ break;
-+ }
-+ }
-+
-+ if (ret < 0)
-+ printk(KERN_WARNING "mcp: write timed out\n");
-+}
-+
-+/*
-+ * Read data from the device. The bit should be set after 3 subframe
-+ * times (each frame is 64 clocks). We wait a maximum of 6 subframes.
-+ * We really should try doing something more productive while we
-+ * wait.
-+ */
-+static unsigned int
-+mcp_sa1100_read(struct mcp *mcp, unsigned int reg)
-+{
-+ int ret = -ETIME;
-+ int i;
-+
-+ Ser4MCDR2 = reg << 17 | MCDR2_Rd;
-+
-+ for (i = 0; i < 2; i++) {
-+ udelay(mcp->rw_timeout);
-+ if (Ser4MCSR & MCSR_CRC) {
-+ ret = Ser4MCDR2 & 0xffff;
-+ break;
-+ }
-+ }
-+
-+ if (ret < 0)
-+ printk(KERN_WARNING "mcp: read timed out\n");
-+
-+ return ret;
-+}
-+
-+static void mcp_sa1100_enable(struct mcp *mcp)
-+{
-+ Ser4MCSR = -1;
-+ Ser4MCCR0 |= MCCR0_MCE;
-+}
-+
-+static void mcp_sa1100_disable(struct mcp *mcp)
-+{
-+ Ser4MCCR0 &= ~MCCR0_MCE;
-+}
-+
-+/*
-+ * Our methods.
-+ */
-+static struct mcp mcp_sa1100 = {
-+ .owner = THIS_MODULE,
-+ .lock = SPIN_LOCK_UNLOCKED,
-+ .sclk_rate = 11981000,
-+ .dma_audio_rd = DMA_Ser4MCP0Rd,
-+ .dma_audio_wr = DMA_Ser4MCP0Wr,
-+ .dma_telco_rd = DMA_Ser4MCP1Rd,
-+ .dma_telco_wr = DMA_Ser4MCP1Wr,
-+ .set_telecom_divisor = mcp_sa1100_set_telecom_divisor,
-+ .set_audio_divisor = mcp_sa1100_set_audio_divisor,
-+ .reg_write = mcp_sa1100_write,
-+ .reg_read = mcp_sa1100_read,
-+ .enable = mcp_sa1100_enable,
-+ .disable = mcp_sa1100_disable,
-+};
-+
-+static int mcp_sa1100_probe(struct device *dev)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct mcp *mcp = &mcp_sa1100;
-+ int ret;
-+
-+ if (!machine_is_adsbitsy() && !machine_is_assabet() &&
-+ !machine_is_cerf() && !machine_is_flexanet() &&
-+ !machine_is_freebird() && !machine_is_graphicsclient() &&
-+ !machine_is_graphicsmaster() && !machine_is_lart() &&
-+ !machine_is_omnimeter() && !machine_is_pfs168() &&
-+ !machine_is_shannon() && !machine_is_simpad() &&
-+ !machine_is_yopy())
-+ return -ENODEV;
-+
-+ if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
-+ return -EBUSY;
-+
-+ mcp->me = dev;
-+ dev_set_drvdata(dev, mcp);
-+
-+ if (machine_is_assabet()) {
-+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
-+ }
-+
-+ /*
-+ * Setup the PPC unit correctly.
-+ */
-+ PPDR &= ~PPC_RXD4;
-+ PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-+ PSDR |= PPC_RXD4;
-+ PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-+ PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-+
-+ Ser4MCSR = -1;
-+ Ser4MCCR1 = 0;
-+ Ser4MCCR0 = 0x00007f7f | MCCR0_ADM;
-+
-+ /*
-+ * Calculate the read/write timeout (us) from the bit clock
-+ * rate. This is the period for 3 64-bit frames. Always
-+ * round this time up.
-+ */
-+ mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
-+ mcp->sclk_rate;
-+
-+ ret = mcp_host_register(mcp, &pdev->dev);
-+ if (ret != 0) {
-+ release_mem_region(0x80060000, 0x60);
-+ dev_set_drvdata(dev, NULL);
-+ }
-+
-+ return ret;
-+}
-+
-+static int mcp_sa1100_remove(struct device *dev)
-+{
-+ struct mcp *mcp = dev_get_drvdata(dev);
-+
-+ dev_set_drvdata(dev, NULL);
-+
-+ mcp_host_unregister(mcp);
-+ release_mem_region(0x80060000, 0x60);
-+
-+ return 0;
-+}
-+
-+struct mcp_sa1100_state {
-+ u32 mccr0;
-+ u32 mccr1;
-+};
-+
-+static int mcp_sa1100_suspend(struct device *dev, u32 state, u32 level)
-+{
-+ struct mcp_sa1100_state *s = (struct mcp_sa1100_state *)dev->saved_state;
-+
-+ if (!s) {
-+ s = kmalloc(sizeof(struct mcp_sa1100_state), GFP_KERNEL);
-+ dev->saved_state = (unsigned char *)s;
-+ }
-+
-+ if (s) {
-+ s->mccr0 = Ser4MCCR0;
-+ s->mccr1 = Ser4MCCR1;
-+ }
-+
-+ if (level == SUSPEND_DISABLE)
-+ Ser4MCCR0 &= ~MCCR0_MCE;
-+ return 0;
-+}
-+
-+static int mcp_sa1100_resume(struct device *dev, u32 level)
-+{
-+ struct mcp_sa1100_state *s = (struct mcp_sa1100_state *)dev->saved_state;
-+
-+ if (s && level == RESUME_RESTORE_STATE) {
-+ Ser4MCCR1 = s->mccr1;
-+ Ser4MCCR0 = s->mccr0;
-+
-+ dev->saved_state = NULL;
-+ kfree(s);
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * The driver for the SA11x0 MCP port.
-+ */
-+static struct device_driver mcp_sa1100_driver = {
-+ .name = "sa11x0-mcp",
-+ .bus = &platform_bus_type,
-+ .probe = mcp_sa1100_probe,
-+ .remove = mcp_sa1100_remove,
-+ .suspend = mcp_sa1100_suspend,
-+ .resume = mcp_sa1100_resume,
-+};
-+
-+/*
-+ * This needs re-working
-+ */
-+static int __init mcp_sa1100_init(void)
-+{
-+ return driver_register(&mcp_sa1100_driver);
-+}
-+
-+static void __exit mcp_sa1100_exit(void)
-+{
-+ driver_unregister(&mcp_sa1100_driver);
-+}
-+
-+module_init(mcp_sa1100_init);
-+module_exit(mcp_sa1100_exit);
-+
-+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-+MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/mcp.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,58 @@
-+/*
-+ * linux/drivers/misc/mcp.h
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ */
-+#ifndef MCP_H
-+#define MCP_H
-+
-+struct mcp {
-+ struct module *owner;
-+ struct device *me;
-+ spinlock_t lock;
-+ int use_count;
-+ unsigned int sclk_rate;
-+ unsigned int rw_timeout;
-+ dma_device_t dma_audio_rd;
-+ dma_device_t dma_audio_wr;
-+ dma_device_t dma_telco_rd;
-+ dma_device_t dma_telco_wr;
-+ void (*set_telecom_divisor)(struct mcp *, unsigned int);
-+ void (*set_audio_divisor)(struct mcp *, unsigned int);
-+ void (*reg_write)(struct mcp *, unsigned int, unsigned int);
-+ unsigned int (*reg_read)(struct mcp *, unsigned int);
-+ void (*enable)(struct mcp *);
-+ void (*disable)(struct mcp *);
-+ struct device attached_device;
-+};
-+
-+void mcp_set_telecom_divisor(struct mcp *, unsigned int);
-+void mcp_set_audio_divisor(struct mcp *, unsigned int);
-+void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
-+unsigned int mcp_reg_read(struct mcp *, unsigned int);
-+void mcp_enable(struct mcp *);
-+void mcp_disable(struct mcp *);
-+#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
-+
-+int mcp_host_register(struct mcp *, struct device *);
-+void mcp_host_unregister(struct mcp *);
-+
-+struct mcp_driver {
-+ struct device_driver drv;
-+ int (*probe)(struct mcp *);
-+ void (*remove)(struct mcp *);
-+ int (*suspend)(struct mcp *, u32);
-+ int (*resume)(struct mcp *);
-+};
-+
-+int mcp_driver_register(struct mcp_driver *);
-+void mcp_driver_unregister(struct mcp_driver *);
-+
-+#define mcp_get_drvdata(mcp) dev_get_drvdata(&(mcp)->attached_device)
-+#define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d)
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/ucb1x00-input.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,233 @@
-+/*
-+ * linux/drivers/misc/ucb1x00.h
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ */
-+#ifndef UCB1200_H
-+#define UCB1200_H
-+
-+#define UCB_IO_DATA 0x00
-+#define UCB_IO_DIR 0x01
-+
-+#define UCB_IO_0 (1 << 0)
-+#define UCB_IO_1 (1 << 1)
-+#define UCB_IO_2 (1 << 2)
-+#define UCB_IO_3 (1 << 3)
-+#define UCB_IO_4 (1 << 4)
-+#define UCB_IO_5 (1 << 5)
-+#define UCB_IO_6 (1 << 6)
-+#define UCB_IO_7 (1 << 7)
-+#define UCB_IO_8 (1 << 8)
-+#define UCB_IO_9 (1 << 9)
-+
-+#define UCB_IE_RIS 0x02
-+#define UCB_IE_FAL 0x03
-+#define UCB_IE_STATUS 0x04
-+#define UCB_IE_CLEAR 0x04
-+#define UCB_IE_ADC (1 << 11)
-+#define UCB_IE_TSPX (1 << 12)
-+#define UCB_IE_TSMX (1 << 13)
-+#define UCB_IE_TCLIP (1 << 14)
-+#define UCB_IE_ACLIP (1 << 15)
-+
-+#define UCB_IRQ_TSPX 12
-+
-+#define UCB_TC_A 0x05
-+#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */
-+#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */
-+
-+#define UCB_TC_B 0x06
-+#define UCB_TC_B_VOICE_ENA (1 << 3)
-+#define UCB_TC_B_CLIP (1 << 4)
-+#define UCB_TC_B_ATT (1 << 6)
-+#define UCB_TC_B_SIDE_ENA (1 << 11)
-+#define UCB_TC_B_MUTE (1 << 13)
-+#define UCB_TC_B_IN_ENA (1 << 14)
-+#define UCB_TC_B_OUT_ENA (1 << 15)
-+
-+#define UCB_AC_A 0x07
-+#define UCB_AC_B 0x08
-+#define UCB_AC_B_LOOP (1 << 8)
-+#define UCB_AC_B_MUTE (1 << 13)
-+#define UCB_AC_B_IN_ENA (1 << 14)
-+#define UCB_AC_B_OUT_ENA (1 << 15)
-+
-+#define UCB_TS_CR 0x09
-+#define UCB_TS_CR_TSMX_POW (1 << 0)
-+#define UCB_TS_CR_TSPX_POW (1 << 1)
-+#define UCB_TS_CR_TSMY_POW (1 << 2)
-+#define UCB_TS_CR_TSPY_POW (1 << 3)
-+#define UCB_TS_CR_TSMX_GND (1 << 4)
-+#define UCB_TS_CR_TSPX_GND (1 << 5)
-+#define UCB_TS_CR_TSMY_GND (1 << 6)
-+#define UCB_TS_CR_TSPY_GND (1 << 7)
-+#define UCB_TS_CR_MODE_INT (0 << 8)
-+#define UCB_TS_CR_MODE_PRES (1 << 8)
-+#define UCB_TS_CR_MODE_POS (2 << 8)
-+#define UCB_TS_CR_BIAS_ENA (1 << 11)
-+#define UCB_TS_CR_TSPX_LOW (1 << 12)
-+#define UCB_TS_CR_TSMX_LOW (1 << 13)
-+
-+#define UCB_ADC_CR 0x0a
-+#define UCB_ADC_SYNC_ENA (1 << 0)
-+#define UCB_ADC_VREFBYP_CON (1 << 1)
-+#define UCB_ADC_INP_TSPX (0 << 2)
-+#define UCB_ADC_INP_TSMX (1 << 2)
-+#define UCB_ADC_INP_TSPY (2 << 2)
-+#define UCB_ADC_INP_TSMY (3 << 2)
-+#define UCB_ADC_INP_AD0 (4 << 2)
-+#define UCB_ADC_INP_AD1 (5 << 2)
-+#define UCB_ADC_INP_AD2 (6 << 2)
-+#define UCB_ADC_INP_AD3 (7 << 2)
-+#define UCB_ADC_EXT_REF (1 << 5)
-+#define UCB_ADC_START (1 << 7)
-+#define UCB_ADC_ENA (1 << 15)
-+
-+#define UCB_ADC_DATA 0x0b
-+#define UCB_ADC_DAT_VAL (1 << 15)
-+#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5)
-+
-+#define UCB_ID 0x0c
-+#define UCB_ID_1200 0x1004
-+#define UCB_ID_1300 0x1005
-+#define UCB_ID_1400 0x4304
-+#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */
-+
-+#define UCB_MODE 0x0d
-+#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
-+#define UCB_MODE_AUD_OFF_CAN (1 << 13)
-+
-+#include "mcp.h"
-+
-+struct ucb1x00;
-+
-+struct ucb1x00_irq {
-+ void *devid;
-+ void (*fn)(int, void *);
-+};
-+
-+struct ucb1x00 {
-+ spinlock_t lock;
-+ struct mcp *mcp;
-+ unsigned int irq;
-+ struct semaphore adc_sem;
-+ spinlock_t io_lock;
-+ u16 id;
-+ u16 io_dir;
-+ u16 io_out;
-+ u16 adc_cr;
-+ u16 irq_fal_enbl;
-+ u16 irq_ris_enbl;
-+ struct ucb1x00_irq irq_handler[16];
-+};
-+
-+/**
-+ * ucb1x00_clkrate - return the UCB1x00 SIB clock rate
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Return the SIB clock rate in Hz.
-+ */
-+static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
-+{
-+ return mcp_get_sclk_rate(ucb->mcp);
-+}
-+
-+/**
-+ * ucb1x00_enable - enable the UCB1x00 SIB clock
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Enable the SIB clock. This can be called multiple times.
-+ */
-+static inline void ucb1x00_enable(struct ucb1x00 *ucb)
-+{
-+ mcp_enable(ucb->mcp);
-+}
-+
-+/**
-+ * ucb1x00_disable - disable the UCB1x00 SIB clock
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Disable the SIB clock. The SIB clock will only be disabled
-+ * when the number of ucb1x00_enable calls match the number of
-+ * ucb1x00_disable calls.
-+ */
-+static inline void ucb1x00_disable(struct ucb1x00 *ucb)
-+{
-+ mcp_disable(ucb->mcp);
-+}
-+
-+/**
-+ * ucb1x00_reg_write - write a UCB1x00 register
-+ * @ucb: UCB1x00 structure describing chip
-+ * @reg: UCB1x00 4-bit register index to write
-+ * @val: UCB1x00 16-bit value to write
-+ *
-+ * Write the UCB1x00 register @reg with value @val. The SIB
-+ * clock must be running for this function to return.
-+ */
-+static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
-+{
-+ mcp_reg_write(ucb->mcp, reg, val);
-+}
-+
-+/**
-+ * ucb1x00_reg_read - read a UCB1x00 register
-+ * @ucb: UCB1x00 structure describing chip
-+ * @reg: UCB1x00 4-bit register index to write
-+ *
-+ * Read the UCB1x00 register @reg and return its value. The SIB
-+ * clock must be running for this function to return.
-+ */
-+static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
-+{
-+ return mcp_reg_read(ucb->mcp, reg);
-+}
-+/**
-+ * ucb1x00_set_audio_divisor -
-+ * @ucb: UCB1x00 structure describing chip
-+ * @div: SIB clock divisor
-+ */
-+static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
-+{
-+ mcp_set_audio_divisor(ucb->mcp, div);
-+}
-+
-+/**
-+ * ucb1x00_set_telecom_divisor -
-+ * @ucb: UCB1x00 structure describing chip
-+ * @div: SIB clock divisor
-+ */
-+static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
-+{
-+ mcp_set_telecom_divisor(ucb->mcp, div);
-+}
-+
-+struct ucb1x00 *ucb1x00_get(void);
-+
-+void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
-+void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
-+unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
-+
-+#define UCB_NOSYNC (0)
-+#define UCB_SYNC (1)
-+
-+unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
-+void ucb1x00_adc_enable(struct ucb1x00 *ucb);
-+void ucb1x00_adc_disable(struct ucb1x00 *ucb);
-+
-+/*
-+ * Which edges of the IRQ do you want to control today?
-+ */
-+#define UCB_RISING (1 << 0)
-+#define UCB_FALLING (1 << 1)
-+
-+int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
-+void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-+void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-+int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/ucb1x00.h 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,271 @@
-+/*
-+ * linux/drivers/misc/ucb1x00.h
-+ *
-+ * Copyright (C) 2001 Russell King, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License.
-+ */
-+#ifndef UCB1200_H
-+#define UCB1200_H
-+
-+#ifdef CONFIG_ARCH_PXA
-+
-+/* ucb1400 aclink register mappings: */
-+
-+#define UCB_IO_DATA 0x5a
-+#define UCB_IO_DIR 0x5c
-+#define UCB_IE_RIS 0x5e
-+#define UCB_IE_FAL 0x60
-+#define UCB_IE_STATUS 0x62
-+#define UCB_IE_CLEAR 0x62
-+#define UCB_TS_CR 0x64
-+#define UCB_ADC_CR 0x66
-+#define UCB_ADC_DATA 0x68
-+#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */
-+
-+#define UCB_ADC_DAT(x) ((x) & 0x3ff)
-+
-+#else
-+
-+/* ucb1x00 SIB register mappings: */
-+
-+#define UCB_IO_DATA 0x00
-+#define UCB_IO_DIR 0x01
-+#define UCB_IE_RIS 0x02
-+#define UCB_IE_FAL 0x03
-+#define UCB_IE_STATUS 0x04
-+#define UCB_IE_CLEAR 0x04
-+#define UCB_TC_A 0x05
-+#define UCB_TC_B 0x06
-+#define UCB_AC_A 0x07
-+#define UCB_AC_B 0x08
-+#define UCB_TS_CR 0x09
-+#define UCB_ADC_CR 0x0a
-+#define UCB_ADC_DATA 0x0b
-+#define UCB_ID 0x0c
-+#define UCB_MODE 0x0d
-+
-+#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5)
-+
-+#endif
-+
-+
-+#define UCB_IO_0 (1 << 0)
-+#define UCB_IO_1 (1 << 1)
-+#define UCB_IO_2 (1 << 2)
-+#define UCB_IO_3 (1 << 3)
-+#define UCB_IO_4 (1 << 4)
-+#define UCB_IO_5 (1 << 5)
-+#define UCB_IO_6 (1 << 6)
-+#define UCB_IO_7 (1 << 7)
-+#define UCB_IO_8 (1 << 8)
-+#define UCB_IO_9 (1 << 9)
-+
-+#define UCB_IE_ADC (1 << 11)
-+#define UCB_IE_TSPX (1 << 12)
-+#define UCB_IE_TSMX (1 << 13)
-+#define UCB_IE_TCLIP (1 << 14)
-+#define UCB_IE_ACLIP (1 << 15)
-+
-+#define UCB_IRQ_TSPX 12
-+
-+#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */
-+#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */
-+
-+#define UCB_TC_B_VOICE_ENA (1 << 3)
-+#define UCB_TC_B_CLIP (1 << 4)
-+#define UCB_TC_B_ATT (1 << 6)
-+#define UCB_TC_B_SIDE_ENA (1 << 11)
-+#define UCB_TC_B_MUTE (1 << 13)
-+#define UCB_TC_B_IN_ENA (1 << 14)
-+#define UCB_TC_B_OUT_ENA (1 << 15)
-+
-+#define UCB_AC_B_LOOP (1 << 8)
-+#define UCB_AC_B_MUTE (1 << 13)
-+#define UCB_AC_B_IN_ENA (1 << 14)
-+#define UCB_AC_B_OUT_ENA (1 << 15)
-+
-+#define UCB_TS_CR_TSMX_POW (1 << 0)
-+#define UCB_TS_CR_TSPX_POW (1 << 1)
-+#define UCB_TS_CR_TSMY_POW (1 << 2)
-+#define UCB_TS_CR_TSPY_POW (1 << 3)
-+#define UCB_TS_CR_TSMX_GND (1 << 4)
-+#define UCB_TS_CR_TSPX_GND (1 << 5)
-+#define UCB_TS_CR_TSMY_GND (1 << 6)
-+#define UCB_TS_CR_TSPY_GND (1 << 7)
-+#define UCB_TS_CR_MODE_INT (0 << 8)
-+#define UCB_TS_CR_MODE_PRES (1 << 8)
-+#define UCB_TS_CR_MODE_POS (2 << 8)
-+#define UCB_TS_CR_BIAS_ENA (1 << 11)
-+#define UCB_TS_CR_TSPX_LOW (1 << 12)
-+#define UCB_TS_CR_TSMX_LOW (1 << 13)
-+
-+#define UCB_ADC_SYNC_ENA (1 << 0)
-+#define UCB_ADC_VREFBYP_CON (1 << 1)
-+#define UCB_ADC_INP_TSPX (0 << 2)
-+#define UCB_ADC_INP_TSMX (1 << 2)
-+#define UCB_ADC_INP_TSPY (2 << 2)
-+#define UCB_ADC_INP_TSMY (3 << 2)
-+#define UCB_ADC_INP_AD0 (4 << 2)
-+#define UCB_ADC_INP_AD1 (5 << 2)
-+#define UCB_ADC_INP_AD2 (6 << 2)
-+#define UCB_ADC_INP_AD3 (7 << 2)
-+#define UCB_ADC_EXT_REF (1 << 5)
-+#define UCB_ADC_START (1 << 7)
-+#define UCB_ADC_ENA (1 << 15)
-+
-+#define UCB_ADC_DAT_VAL (1 << 15)
-+
-+#define UCB_ID_1200 0x1004
-+#define UCB_ID_1300 0x1005
-+#define UCB_ID_1400 0x4304
-+#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */
-+
-+#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
-+#define UCB_MODE_AUD_OFF_CAN (1 << 13)
-+
-+#include <linux/completion.h>
-+#include "mcp.h"
-+
-+struct ucb1x00_irq {
-+ void *devid;
-+ void (*fn)(int, void *);
-+};
-+
-+extern struct class ucb1x00_class;
-+
-+struct ucb1x00 {
-+ spinlock_t lock;
-+ struct mcp *mcp;
-+ unsigned int irq;
-+ struct semaphore adc_sem;
-+ spinlock_t io_lock;
-+ wait_queue_head_t irq_wait;
-+ struct completion complete;
-+ struct task_struct *rtask;
-+ u16 id;
-+ u16 io_dir;
-+ u16 io_out;
-+ u16 adc_cr;
-+ u16 irq_fal_enbl;
-+ u16 irq_ris_enbl;
-+ struct ucb1x00_irq irq_handler[16];
-+ struct class_device cdev;
-+ void *audio_data;
-+ void *telecom_data;
-+ void *ts_data;
-+};
-+
-+#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, cdev)
-+
-+int ucb1x00_register_interface(struct class_interface *intf);
-+void ucb1x00_unregister_interface(struct class_interface *intf);
-+
-+/**
-+ * ucb1x00_clkrate - return the UCB1x00 SIB clock rate
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Return the SIB clock rate in Hz.
-+ */
-+static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
-+{
-+ return mcp_get_sclk_rate(ucb->mcp);
-+}
-+
-+/**
-+ * ucb1x00_enable - enable the UCB1x00 SIB clock
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Enable the SIB clock. This can be called multiple times.
-+ */
-+static inline void ucb1x00_enable(struct ucb1x00 *ucb)
-+{
-+ mcp_enable(ucb->mcp);
-+}
-+
-+/**
-+ * ucb1x00_disable - disable the UCB1x00 SIB clock
-+ * @ucb: UCB1x00 structure describing chip
-+ *
-+ * Disable the SIB clock. The SIB clock will only be disabled
-+ * when the number of ucb1x00_enable calls match the number of
-+ * ucb1x00_disable calls.
-+ */
-+static inline void ucb1x00_disable(struct ucb1x00 *ucb)
-+{
-+ mcp_disable(ucb->mcp);
-+}
-+
-+/**
-+ * ucb1x00_reg_write - write a UCB1x00 register
-+ * @ucb: UCB1x00 structure describing chip
-+ * @reg: UCB1x00 4-bit register index to write
-+ * @val: UCB1x00 16-bit value to write
-+ *
-+ * Write the UCB1x00 register @reg with value @val. The SIB
-+ * clock must be running for this function to return.
-+ */
-+static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
-+{
-+ mcp_reg_write(ucb->mcp, reg, val);
-+}
-+
-+/**
-+ * ucb1x00_reg_read - read a UCB1x00 register
-+ * @ucb: UCB1x00 structure describing chip
-+ * @reg: UCB1x00 4-bit register index to write
-+ *
-+ * Read the UCB1x00 register @reg and return its value. The SIB
-+ * clock must be running for this function to return.
-+ */
-+static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
-+{
-+ return mcp_reg_read(ucb->mcp, reg);
-+}
-+/**
-+ * ucb1x00_set_audio_divisor -
-+ * @ucb: UCB1x00 structure describing chip
-+ * @div: SIB clock divisor
-+ */
-+static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
-+{
-+ mcp_set_audio_divisor(ucb->mcp, div);
-+}
-+
-+/**
-+ * ucb1x00_set_telecom_divisor -
-+ * @ucb: UCB1x00 structure describing chip
-+ * @div: SIB clock divisor
-+ */
-+static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
-+{
-+ mcp_set_telecom_divisor(ucb->mcp, div);
-+}
-+
-+#define ucb1x00_get() NULL
-+
-+void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
-+void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
-+unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
-+
-+#define UCB_NOSYNC (0)
-+#define UCB_SYNC (1)
-+
-+unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
-+void ucb1x00_adc_enable(struct ucb1x00 *ucb);
-+void ucb1x00_adc_disable(struct ucb1x00 *ucb);
-+
-+/*
-+ * Which edges of the IRQ do you want to control today?
-+ */
-+#define UCB_RISING (1 << 0)
-+#define UCB_FALLING (1 << 1)
-+
-+int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
-+void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-+void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-+int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
-+
-+#endif
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/misc/switches-sa1100.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,323 @@
-+/*
-+ * linux/drivers/misc/switches-sa1100.c
-+ *
-+ * Copyright (C) 2001 John Dorsey
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 19 December 2001 - created from sa1100_switches.c.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/irq.h>
-+
-+#include <asm/arch/assabet.h>
-+#include <asm/arch/neponset.h>
-+#include <asm/arch/badge4.h>
-+
-+#include "switches.h"
-+
-+
-+static irqreturn_t switches_sa1100_handler(int irq, void *dev_id,
-+ struct pt_regs *regs);
-+
-+
-+#ifdef CONFIG_SA1100_ASSABET
-+
-+/* Assabet
-+ * ^^^^^^^
-+ * We have two general-purpose switches, S1 and S2, available via GPIO
-+ * on Assabet. This code sets bits in the range [1, 2] in the mask that
-+ * we return to userland.
-+ */
-+
-+static int assabet_switches_sa1100_init(void)
-+{
-+
-+ if (machine_has_neponset())
-+ NCR_0 |= NCR_GP01_OFF;
-+
-+ if (request_irq(IRQ_GPIO0, switches_sa1100_handler, SA_INTERRUPT,
-+ SWITCHES_NAME, NULL) < 0) {
-+ printk(KERN_ERR "%s: unable to register IRQ for GPIO 0\n",
-+ SWITCHES_NAME);
-+ return -EIO;
-+ }
-+
-+ if (request_irq(IRQ_GPIO1, switches_sa1100_handler, SA_INTERRUPT,
-+ SWITCHES_NAME, NULL) < 0) {
-+ printk(KERN_ERR "%s: unable to register IRQ for GPIO 1\n",
-+ SWITCHES_NAME);
-+ free_irq(IRQ_GPIO0, NULL);
-+ return -EIO;
-+ }
-+
-+ set_irq_type(IRQ_GPIO0, IRQT_BOTHEDGE);
-+ set_irq_type(IRQ_GPIO1, IRQT_BOTHEDGE);
-+
-+ return 0;
-+
-+}
-+
-+static void assabet_switches_sa1100_shutdown(void)
-+{
-+
-+ free_irq(IRQ_GPIO1, NULL);
-+ free_irq(IRQ_GPIO0, NULL);
-+
-+}
-+
-+static irqreturn_t assabet_switches_sa1100_handler(int irq, switches_mask_t *mask)
-+{
-+ unsigned int s, last, this;
-+ static unsigned int states = 0;
-+
-+ switch (irq) {
-+
-+ case IRQ_GPIO0: s = 0; break;
-+
-+ case IRQ_GPIO1: s = 1; break;
-+
-+ default: return IRQ_NONE;
-+
-+ }
-+
-+ last = ((states & (1 << s)) != 0);
-+ this = ((GPLR & GPIO_GPIO(s)) != 0);
-+
-+ if (last == this) /* debounce */
-+ return IRQ_HANDLED;
-+
-+ SWITCHES_SET(mask, s + 1, this);
-+
-+ states = this ? (states | (1 << s)) : (states & ~(1 << s));
-+
-+ return IRQ_HANDLED;
-+}
-+#endif /* CONFIG_SA1100_ASSABET */
-+
-+#ifdef CONFIG_SA1100_BADGE4
-+
-+/* BadgePAD 4
-+ * ^^^^^^^^^^
-+ *
-+ * Here we use test point J6 (BADGE4_GPIO_TESTPT_J6 aka GPIO 23) as a
-+ * general purpose switch input. We map this to switch #0.
-+ */
-+
-+#define BADGE4_SW0_GPIO GPIO_GPIO23 /* aka BADGE4_GPIO_TESTPT_J6 */
-+#define BADGE4_SW0_IRQ IRQ_GPIO23
-+
-+static int badge4_switches_sa1100_init(void)
-+{
-+ if (request_irq(BADGE4_SW0_IRQ, switches_sa1100_handler, SA_INTERRUPT,
-+ SWITCHES_NAME, NULL) < 0) {
-+ printk(KERN_ERR "%s: unable to register IRQ for SW0\n",
-+ SWITCHES_NAME);
-+ return -EIO;
-+ }
-+
-+ set_irq_type(BADGE4_SW0_IRQ, IRQT_BOTHEDGE);
-+
-+ return 0;
-+}
-+
-+static void badge4_switches_sa1100_shutdown(void)
-+{
-+ free_irq(BADGE4_SW0_IRQ, NULL);
-+}
-+
-+static irqreturn_t badge4_switches_sa1100_handler(int irq, switches_mask_t *mask)
-+{
-+ unsigned int swno, last, this, gpio;
-+ static unsigned int states = 0;
-+
-+ switch (irq) {
-+ case BADGE4_SW0_IRQ:
-+ swno = 0;
-+ gpio = BADGE4_SW0_GPIO;
-+ break;
-+ default:
-+ return IRQ_NONE;
-+ }
-+
-+ last = ((states & gpio) != 0);
-+ this = ((GPLR & gpio) != 0);
-+
-+ if (last == this) /* debounce */
-+ return IRQ_HANDLED;
-+
-+ SWITCHES_SET(mask, swno, this);
-+
-+ states = this ? (states | gpio) : (states & ~gpio);
-+
-+ return IRQ_HANDLED;
-+}
-+#endif /* CONFIG_SA1100_BADGE4 */
-+
-+
-+#ifdef CONFIG_SA1100_SPOT
-+
-+/* Spot
-+ * ^^^^
-+ * Spot (R2, R3) has a single general-purpose switch (S1), which is
-+ * also the power-on switch. We set bit [1] in the mask we return to
-+ * userland.
-+ */
-+
-+static int spot_switches_sa1100_init(void)
-+{
-+
-+ set_GPIO_IRQ_edge(GPIO_SW1, GPIO_BOTH_EDGES);
-+
-+ if (request_irq(IRQ_GPIO_SW1, switches_sa1100_handler, SA_INTERRUPT,
-+ SWITCHES_NAME, NULL) < 0) {
-+ printk(KERN_ERR "%s: unable to register IRQ for SW1\n",
-+ SWITCHES_NAME);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+
-+}
-+
-+static void spot_switches_sa1100_shutdown(void)
-+{
-+
-+ free_irq(IRQ_GPIO_SW1, NULL);
-+
-+}
-+
-+static irqreturn_t spot_switches_sa1100_handler(int irq, switches_mask_t *mask)
-+{
-+ unsigned int s, last, this;
-+ static unsigned int states = 0;
-+
-+ switch (irq) {
-+
-+ case IRQ_GPIO_SW1: s = 0; break;
-+
-+ default: return IRQ_NONE;
-+
-+ }
-+
-+ last = ((states & (1 << s)) != 0);
-+ this = ((GPLR & GPIO_GPIO(s)) != 0);
-+
-+ if (last == this) /* debounce */
-+ return IRQ_HANDLED;
-+
-+ SWITCHES_SET(mask, s + 1, this);
-+
-+ states = this ? (states | (1 << s)) : (states & ~(1 << s));
-+
-+ return IRQ_HANDLED;
-+
-+}
-+#endif /* CONFIG_SA1100_SPOT */
-+
-+
-+/* switches_sa1100_handler()
-+ * ^^^^^^^^^^^^^^^^^^^^^^^^^
-+ * This routine is a generalized handler for SA-1100 switches
-+ * which manages action descriptors and calls a board-specific
-+ * service routine. This routine is appropriate for GPIO switches
-+ * or other primary interrupt sources, and can be registered as a
-+ * first-class IRQ handler using request_irq().
-+ */
-+static irqreturn_t switches_sa1100_handler(int irq, void *dev_id,
-+ struct pt_regs *regs)
-+{
-+ switches_mask_t mask;
-+ irqreturn_t ret = IRQ_NONE;
-+
-+ SWITCHES_ZERO(&mask);
-+
-+ /* Porting note: call a board-specific switch interrupt handler
-+ * here. The handler can assume that sufficient storage for
-+ * `mask' has been allocated, and that the corresponding
-+ * switches_mask_t structure has been zeroed.
-+ */
-+
-+ if (machine_is_assabet()) {
-+#ifdef CONFIG_SA1100_ASSABET
-+ ret = assabet_switches_sa1100_handler(irq, &mask);
-+#endif
-+ } else if (machine_is_badge4()) {
-+#ifdef CONFIG_SA1100_BADGE4
-+ ret = badge4_switches_sa1100_handler(irq, &mask);
-+#endif
-+ } else if (machine_is_spot()) {
-+#ifdef CONFIG_SA1100_SPOT
-+ ret = spot_switches_sa1100_handler(irq, &mask);
-+#endif
-+ }
-+
-+ switches_event(&mask);
-+
-+ return ret;
-+}
-+
-+int __init switches_sa1100_init(void)
-+{
-+
-+ /* Porting note: call a board-specific init routine here. */
-+
-+ if (machine_is_assabet()) {
-+#ifdef CONFIG_SA1100_ASSABET
-+ if (assabet_switches_sa1100_init() < 0)
-+ return -EIO;
-+#endif
-+ } else if (machine_is_badge4()) {
-+#ifdef CONFIG_SA1100_BADGE4
-+ if (badge4_switches_sa1100_init() < 0)
-+ return -EIO;
-+#endif
-+ } else if (machine_is_spot()) {
-+#ifdef CONFIG_SA1100_SPOT
-+ if (spot_switches_sa1100_init() < 0)
-+ return -EIO;
-+#endif
-+ }
-+
-+ return 0;
-+
-+}
-+
-+void __exit switches_sa1100_exit(void)
-+{
-+
-+ /* Porting note: call a board-specific shutdown routine here. */
-+
-+ if (machine_is_assabet()) {
-+#ifdef CONFIG_SA1100_ASSABET
-+ assabet_switches_sa1100_shutdown();
-+#endif
-+ } else if (machine_is_badge4()) {
-+#ifdef CONFIG_SA1100_BADGE4
-+ badge4_switches_sa1100_shutdown();
-+#endif
-+ } else if (machine_is_spot()) {
-+#ifdef CONFIG_SA1100_SPOT
-+ spot_switches_sa1100_shutdown();
-+#endif
-+ }
-+
-+}
-+
-+module_init(switches_sa1100_init);
-+module_exit(switches_sa1100_exit);
-+
-+MODULE_DESCRIPTION("SA-1100 switches driver");
-+MODULE_LICENSE("GPL");
---- linux-2.6.5/drivers/misc/Makefile~heh 2004-04-03 22:38:17.000000000 -0500
-+++ linux-2.6.5/drivers/misc/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -4,3 +4,21 @@
- obj- := misc.o # Dummy rule to force built-in.o to be made
-
- obj-$(CONFIG_IBM_ASM) += ibmasm/
-+
-+obj-$(CONFIG_MCP) += mcp-core.o
-+obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
-+obj-$(CONFIG_MCP_UCB1200_AUDIO) += ucb1x00-audio.o
-+obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
-+
-+ifeq ($(CONFIG_SA1100_ASSABET),y)
-+obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
-+endif
-+
-+obj-$(CONFIG_SWITCHES) += switches-core.o
-+obj-$(CONFIG_SWITCHES_SA1100) += switches-sa1100.o
-+obj-$(CONFIG_SWITCHES_UCB1X00) += switches-ucb1x00.o
-+
-+obj-$(CONFIG_MCP_SA1100) += mcp-sa1100.o
-+
-+obj-$(CONFIG_UCB1400_TS) += mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o
-+
---- linux-2.6.5/drivers/i2c/busses/Kconfig~heh 2004-04-03 22:38:10.000000000 -0500
-+++ linux-2.6.5/drivers/i2c/busses/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -70,6 +70,16 @@
- This support is also available as a module. If so, the module
- will be called i2c-hydra.
-
-+config I2C_BIT_SA1100_GPIO
-+ bool "SA1100 I2C GPIO adapter"
-+ depends on ARCH_SA1100 && I2C_ALGOBIT
-+ help
-+ This supports I2C on the SA11x0 processor GPIO pins. This
-+ shares support with the L3 driver.
-+
-+ This support is also available as a module. If so, the module
-+ will be called l3-bit-sa1100.
-+
- config I2C_I801
- tristate "Intel 801"
- depends on I2C && PCI && EXPERIMENTAL
-@@ -241,6 +251,18 @@
- This support is also available as a module. If so, the module
- will be called i2c-prosavage.
-
-+config I2C_PXA2XX
-+ tristate "PXA I2C Interface"
-+ depends on I2C && ARCH_PXA
-+ select I2C_ALGOPXA
-+ help
-+ This supports the use of the PXA I2C interface found on the Intel
-+ PXA 25x and PXA 26x systems. Say Y if you have one of these.
-+
-+ This support is also available as a module. If you want to compile
-+ it as a module, say M here and read Documentation/modules.txt.
-+ The module will be called i2c-adap-pxa.
-+
- config I2C_RPXLITE
- tristate "Embedded Planet RPX Lite/Classic support"
- depends on (RPXLITE || RPXCLASSIC) && I2C
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/i2c/busses/pxa2xx_i2c.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,388 @@
-+/*
-+ * i2c_adap_pxa.c
-+ *
-+ * I2C adapter for the PXA I2C bus access.
-+ *
-+ * Copyright (C) 2002 Intrinsyc Software Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * History:
-+ * Apr 2002: Initial version [CS]
-+ * Jun 2002: Properly seperated algo/adap [FB]
-+ * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
-+ * Jan 2003: added limited signal handling [Kai-Uwe Bloem]
-+ * Jun 2003: updated for 2.5 [Dustin McIntire]
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-id.h>
-+#include <linux/init.h>
-+#include <linux/time.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/irq.h>
-+#include <asm/arch/irqs.h> /* for IRQ_I2C */
-+
-+#include <linux/i2c-pxa.h>
-+
-+/*
-+ * Set this to zero to remove all debug statements via dead code elimination.
-+ */
-+//#define DEBUG 1
-+
-+#if DEBUG
-+static unsigned int i2c_debug = DEBUG;
-+#else
-+#define i2c_debug 0
-+#endif
-+
-+static int irq = 0;
-+static volatile int i2c_pending = 0; /* interrupt pending when 1 */
-+static volatile int bus_error = 0;
-+static volatile int tx_finished = 0;
-+static volatile int rx_finished = 0;
-+
-+static wait_queue_head_t i2c_wait;
-+static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte);
-+
-+/* place a byte in the transmit register */
-+static void i2c_pxa_write_byte(u8 value)
-+{
-+ IDBR = value;
-+}
-+
-+/* read byte in the receive register */
-+static u8 i2c_pxa_read_byte(void)
-+{
-+ return (u8) (0xff & IDBR);
-+}
-+
-+static void i2c_pxa_start(void)
-+{
-+ unsigned long icr = ICR;
-+ icr |= ICR_START;
-+ icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK);
-+ ICR = icr;
-+
-+ bus_error=0; /* clear any bus_error from previous txfers */
-+ tx_finished=0; /* clear rx and tx interrupts from previous txfers */
-+ rx_finished=0;
-+ i2c_pending = 0;
-+}
-+
-+static void i2c_pxa_repeat_start(void)
-+{
-+ unsigned long icr = ICR;
-+ icr |= ICR_START;
-+ icr &= ~(ICR_STOP | ICR_ALDIE);
-+ ICR = icr;
-+
-+ bus_error=0; /* clear any bus_error from previous txfers */
-+ tx_finished=0; /* clear rx and tx interrupts from previous txfers */
-+ rx_finished=0;
-+ i2c_pending = 0;
-+}
-+
-+static void i2c_pxa_stop(void)
-+{
-+ unsigned long icr = ICR;
-+ icr |= ICR_STOP;
-+ icr &= ~(ICR_START);
-+ ICR = icr;
-+}
-+
-+static void i2c_pxa_midbyte(void)
-+{
-+ unsigned long icr = ICR;
-+ icr &= ~(ICR_START | ICR_STOP);
-+ ICR = icr;
-+}
-+
-+static void i2c_pxa_abort(void)
-+{
-+ unsigned long timeout = jiffies + HZ/4;
-+
-+#ifdef PXA_ABORT_MA
-+ while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) {
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(1);
-+ }
-+
-+ ICR |= ICR_MA;
-+ udelay(100);
-+#else
-+ while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) {
-+ i2c_pxa_transfer( 1, I2C_RECEIVE, 1);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(1);
-+ }
-+#endif
-+ ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
-+}
-+
-+static int i2c_pxa_wait_bus_not_busy( void)
-+{
-+ int timeout = DEF_TIMEOUT;
-+
-+ while (timeout-- && (ISR & ISR_IBB)) {
-+ udelay(100); /* wait for 100 us */
-+ }
-+
-+ return (timeout<=0);
-+}
-+
-+spinlock_t i2c_pxa_irqlock = SPIN_LOCK_UNLOCKED;
-+
-+static void i2c_pxa_wait_for_ite(void){
-+ unsigned long flags;
-+ if (irq > 0) {
-+ spin_lock_irqsave(&i2c_pxa_irqlock, flags);
-+ if (i2c_pending == 0) {
-+ interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT );
-+ }
-+ i2c_pending = 0;
-+ spin_unlock_irqrestore(&i2c_pxa_irqlock, flags);
-+ } else {
-+ udelay(100);
-+ }
-+}
-+
-+static int i2c_pxa_wait_for_int( int wait_type)
-+{
-+ int timeout = DEF_TIMEOUT;
-+#ifdef DEBUG
-+ if (bus_error)
-+ printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n");
-+ if (rx_finished)
-+ printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n");
-+ if (tx_finished)
-+ printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n");
-+#endif
-+
-+ if (wait_type == I2C_RECEIVE){ /* wait on receive */
-+
-+ do {
-+ i2c_pxa_wait_for_ite();
-+ } while (!(rx_finished) && timeout-- && !signal_pending(current));
-+
-+#ifdef DEBUG
-+ if (timeout<0){
-+ if (tx_finished)
-+ printk("Error: i2c-algo-pxa.o: received a tx"
-+ " interrupt while waiting on a rx in wait_for_int");
-+ }
-+#endif
-+ } else { /* wait on transmit */
-+
-+ do {
-+ i2c_pxa_wait_for_ite();
-+ } while (!(tx_finished) && timeout-- && !signal_pending(current));
-+
-+#ifdef DEBUG
-+ if (timeout<0){
-+ if (rx_finished)
-+ printk("Error: i2c-algo-pxa.o: received a rx"
-+ " interrupt while waiting on a tx in wait_for_int");
-+ }
-+#endif
-+ }
-+
-+ udelay(ACK_DELAY); /* this is needed for the bus error */
-+
-+ tx_finished=0;
-+ rx_finished=0;
-+
-+ if (bus_error){
-+ bus_error=0;
-+ if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n");
-+ return BUS_ERROR;
-+ }
-+
-+ if (signal_pending(current)) {
-+ return (-ERESTARTSYS);
-+ } else if (timeout < 0) {
-+ if( i2c_debug > 2)printk("wait_for_int: timeout.\n");
-+ return(-EIO);
-+ } else
-+ return(0);
-+}
-+
-+static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte)
-+{
-+ if( lastbyte)
-+ {
-+ if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK;
-+ i2c_pxa_stop();
-+ }
-+ else if( midbyte)
-+ {
-+ i2c_pxa_midbyte();
-+ }
-+ ICR |= ICR_TB;
-+}
-+
-+static void i2c_pxa_reset( void)
-+{
-+#ifdef DEBUG
-+ printk("Resetting I2C Controller Unit\n");
-+#endif
-+
-+ /* abort any transfer currently under way */
-+ i2c_pxa_abort();
-+
-+ /* reset according to 9.8 */
-+ ICR = ICR_UR;
-+ ISR = I2C_ISR_INIT;
-+ ICR &= ~ICR_UR;
-+
-+ /* set the global I2C clock on */
-+ CKEN |= CKEN14_I2C;
-+
-+ /* set our slave address */
-+ ISAR = I2C_PXA_SLAVE_ADDR;
-+
-+ /* set control register values */
-+ ICR = I2C_ICR_INIT;
-+
-+ /* clear any leftover states from prior transmissions */
-+ i2c_pending = rx_finished = tx_finished = bus_error = 0;
-+
-+ /* enable unit */
-+ ICR |= ICR_IUE;
-+ udelay(100);
-+}
-+
-+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
-+{
-+ unsigned long flags;
-+ int status, wakeup = 0;
-+ status = (ISR);
-+
-+ if (status & ISR_BED){
-+ (ISR) |= ISR_BED;
-+ bus_error=ISR_BED;
-+ wakeup = 1;
-+ }
-+ if (status & ISR_ITE){
-+ (ISR) |= ISR_ITE;
-+ tx_finished=ISR_ITE;
-+ wakeup = 1;
-+ }
-+ if (status & ISR_IRF){
-+ (ISR) |= ISR_IRF;
-+ rx_finished=ISR_IRF;
-+ wakeup = 1;
-+ }
-+ if (wakeup) {
-+ spin_lock_irqsave(&i2c_pxa_irqlock, flags);
-+ i2c_pending = 1;
-+ spin_unlock_irqrestore(&i2c_pxa_irqlock, flags);
-+ wake_up_interruptible(&i2c_wait);
-+ }
-+ return IRQ_HANDLED;
-+}
-+
-+static int i2c_pxa_resource_init( void)
-+{
-+ init_waitqueue_head(&i2c_wait);
-+
-+ if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C", 0) < 0) {
-+ irq = 0;
-+ if(i2c_debug)
-+ printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C);
-+ return -ENODEV;
-+ }
-+ return 0;
-+}
-+
-+static void i2c_pxa_resource_release( void)
-+{
-+ if( irq > 0)
-+ {
-+ disable_irq(irq);
-+ free_irq(irq,0);
-+ irq=0;
-+ }
-+}
-+
-+static int i2c_pxa_client_register(struct i2c_client *client)
-+{
-+ return 0;
-+}
-+
-+static int i2c_pxa_client_unregister(struct i2c_client *client)
-+{
-+ return 0;
-+}
-+
-+static struct i2c_algo_pxa_data i2c_pxa_data = {
-+ write_byte: i2c_pxa_write_byte,
-+ read_byte: i2c_pxa_read_byte,
-+
-+ start: i2c_pxa_start,
-+ repeat_start: i2c_pxa_repeat_start,
-+ stop: i2c_pxa_stop,
-+ abort: i2c_pxa_abort,
-+
-+ wait_bus_not_busy: i2c_pxa_wait_bus_not_busy,
-+ wait_for_interrupt: i2c_pxa_wait_for_int,
-+ transfer: i2c_pxa_transfer,
-+ reset: i2c_pxa_reset,
-+
-+ udelay: 10,
-+ timeout: DEF_TIMEOUT,
-+};
-+
-+static struct i2c_adapter i2c_pxa_ops = {
-+ .owner = THIS_MODULE,
-+ .id = I2C_ALGO_PXA,
-+ .algo_data = &i2c_pxa_data,
-+ .dev = {
-+ .name = "PXA I2C Adapter",
-+ },
-+ .client_register = i2c_pxa_client_register,
-+ .client_unregister = i2c_pxa_client_unregister,
-+ .retries = 2,
-+};
-+
-+extern int i2c_pxa_add_bus(struct i2c_adapter *);
-+extern int i2c_pxa_del_bus(struct i2c_adapter *);
-+
-+static int __init i2c_adap_pxa_init(void)
-+{
-+ if( i2c_pxa_resource_init() == 0) {
-+
-+ if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) {
-+ i2c_pxa_resource_release();
-+ printk(KERN_INFO "I2C: Failed to add bus\n");
-+ return -ENODEV;
-+ }
-+ } else {
-+ return -ENODEV;
-+ }
-+
-+ printk(KERN_INFO "I2C: Successfully added bus\n");
-+
-+ return 0;
-+}
-+
-+static void i2c_adap_pxa_exit(void)
-+{
-+ i2c_pxa_del_bus( &i2c_pxa_ops);
-+ i2c_pxa_resource_release();
-+
-+ printk(KERN_INFO "I2C: Successfully removed bus\n");
-+}
-+
-+module_init(i2c_adap_pxa_init);
-+module_exit(i2c_adap_pxa_exit);
---- linux-2.6.5/drivers/i2c/busses/Makefile~heh 2004-04-03 22:36:17.000000000 -0500
-+++ linux-2.6.5/drivers/i2c/busses/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -21,6 +21,7 @@
- obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
- obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
- obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
-+obj-$(CONFIG_I2C_PXA) += pxa2xx_i2c.o
- obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
- obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
- obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
---- linux-2.6.5/drivers/i2c/algos/Kconfig~heh 2004-04-03 22:37:59.000000000 -0500
-+++ linux-2.6.5/drivers/i2c/algos/Kconfig 2004-04-30 20:57:36.000000000 -0400
-@@ -38,6 +38,18 @@
- This support is also available as a module. If so, the module
- will be called i2c-algo-ite.
-
-+config I2C_ALGOPXA
-+ tristate "PXA I2C Algorithm"
-+ depends on ARCH_PXA && I2C
-+ help
-+ This supports the use of the PXA I2C interface found on the Intel
-+ PXA 25x and PXA 26x systems. Say Y if you have one of these.
-+ You should also say Y for the PXA I2C peripheral driver support below.
-+
-+ This support is also available as a module. If you want to compile
-+ it as a module, say M here and read Documentation/modules.txt.
-+ The module will be called i2c-algo-pxa.
-+
- config I2C_ALGO8XX
- tristate "MPC8xx CPM I2C interface"
- depends on 8xx && I2C
---- /dev/null 2003-09-23 18:19:32.000000000 -0400
-+++ linux-2.6.5/drivers/i2c/algos/i2c-algo-pxa.c 2004-04-30 20:57:36.000000000 -0400
-@@ -0,0 +1,384 @@
-+/*
-+ * i2c-algo-pxa.c
-+ *
-+ * I2C algorithm for the PXA I2C bus access.
-+ * Byte driven algorithm similar to pcf.
-+ *
-+ * Copyright (C) 2002 Intrinsyc Software Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * History:
-+ * Apr 2002: Initial version [CS]
-+ * Jun 2002: Properly seperated algo/adap [FB]
-+ * Jan 2003: added limited signal handling [Kai-Uwe Bloem]
-+ * Jan 2003: allow SMBUS_QUICK as valid msg [FB]
-+ * Jun 2003: updated for 2.5 [Dustin McIntire]
-+ *
-+ */
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/errno.h>
-+#include <linux/i2c.h> /* struct i2c_msg and others */
-+#include <linux/i2c-id.h>
-+
-+#include <linux/i2c-pxa.h>
-+
-+/*
-+ * Set this to zero to remove all the debug statements via dead code elimination.
-+ */
-+//#define DEBUG 1
-+
-+#if DEBUG
-+static unsigned int i2c_debug = DEBUG;
-+#else
-+#define i2c_debug 0
-+#endif
-+
-+static int pxa_scan = 1;
-+
-+static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num)
-+{
-+ int i;
-+ if (num < 1 || num > MAX_MESSAGES){
-+ if( i2c_debug)
-+ printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n",
-+ MAX_MESSAGES, num);
-+ return -EINVAL;
-+ }
-+
-+ /* check consistency of our messages */
-+ for (i=0;i<num;i++){
-+ if (&msgs[i]==NULL){
-+ if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n");
-+ return -EINVAL;
-+ } else {
-+ if (msgs[i].buf == NULL){
-+ if( i2c_debug)printk(KERN_INFO "Length is less than zero");
-+ return -EINVAL;
-+ }
-+ }
-+ }
-+
-+ return 1;
-+}
-+
-+static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf,
-+ int count, int last)
-+{
-+
-+ int i, timeout=0;
-+ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
-+
-+ /* increment number of bytes to read by one -- read dummy byte */
-+ for (i = 0; i <= count; i++) {
-+ if (i!=0){
-+ /* set ACK to NAK for last received byte ICR[ACKNAK] = 1
-+ only if not a repeated start */
-+
-+ if ((i == count) && last) {
-+ adap->transfer( last, I2C_RECEIVE, 0);
-+ }else{
-+ adap->transfer( 0, I2C_RECEIVE, 1);
-+ }
-+
-+ timeout = adap->wait_for_interrupt(I2C_RECEIVE);
-+
-+#ifdef DEBUG
-+ if (timeout==BUS_ERROR){
-+ printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n");
-+ adap->reset();
-+ return I2C_RETRY;
-+ } else
-+#endif
-+ if (timeout == -ERESTARTSYS) {
-+ adap->abort();
-+ return timeout;
-+ } else
-+ if (timeout){
-+#ifdef DEBUG
-+ printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n");
-+#endif
-+ adap->reset();
-+ return I2C_RETRY;
-+ }
-+
-+ }
-+
-+ if (i) {
-+ buf[i - 1] = adap->read_byte();
-+ } else {
-+ adap->read_byte(); /* dummy read */
-+ }
-+ }
-+ return (i - 1);
-+}
-+
-+static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
-+ int count, int last)
-+{
-+
-+ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
-+ int wrcount, timeout;
-+
-+ for (wrcount=0; wrcount<count; ++wrcount) {
-+
-+ adap->write_byte(buf[wrcount]);
-+ if ((wrcount==(count-1)) && last) {
-+ adap->transfer( last, I2C_TRANSMIT, 0);
-+ }else{
-+ adap->transfer( 0, I2C_TRANSMIT, 1);
-+ }
-+
-+ timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
-+
-+#ifdef DEBUG
-+ if (timeout==BUS_ERROR) {
-+ printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n");
-+ adap->reset();
-+ return I2C_RETRY;
-+ } else
-+#endif
-+ if (timeout == -ERESTARTSYS) {
-+ adap->abort();
-+ return timeout;
-+ } else
-+ if (timeout) {
-+#ifdef DEBUG
-+ printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n");
-+#endif
-+ adap->reset();
-+ return I2C_RETRY;
-+ }
-+ }
-+ return (wrcount);
-+}
-+
-+
-+static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg)
-+{
-+ u16 flags = msg->flags;
-+ u8 addr;
-+ addr = (u8) ( (0x7f & msg->addr) << 1 );
-+ if (flags & I2C_M_RD )
-+ addr |= 1;
-+ if (flags & I2C_M_REV_DIR_ADDR )
-+ addr ^= 1;
-+ adap->write_byte(addr);
-+ return 0;
-+}
-+
-+static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
-+{
-+ struct i2c_algo_pxa_data * adap;
-+ struct i2c_msg *pmsg=NULL;
-+ int i;
-+ int ret=0, timeout;
-+
-+ adap = i2c_adap->algo_data;
-+
-+ timeout = adap->wait_bus_not_busy();
-+
-+ if (timeout) {
-+ return I2C_RETRY;
-+ }
-+
-+ for (i = 0;ret >= 0 && i < num; i++) {
-+ int last = i + 1 == num;
-+ pmsg = &msgs[i];
-+
-+ ret = i2c_pxa_set_ctrl_byte(adap,pmsg);
-+
-+ /* Send START */
-+ if (i == 0) {
-+ adap->start();
-+ }else{
-+ adap->repeat_start();
-+ }
-+
-+ adap->transfer(0, I2C_TRANSMIT, 0);
-+
-+ /* Wait for ITE (transmit empty) */
-+ timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
-+
-+#ifdef DEBUG
-+ /* Check for ACK (bus error) */
-+ if (timeout==BUS_ERROR){
-+ printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n");
-+ adap->reset();
-+ return I2C_RETRY;
-+ } else
-+#endif
-+ if (timeout == -ERESTARTSYS) {
-+ adap->abort();
-+ return timeout;
-+ } else
-+ if (timeout) {
-+#ifdef DEBUG
-+ printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n");
-+#endif
-+ adap->reset();
-+ return I2C_RETRY;
-+ }
-+/* FIXME: handle arbitration... */
-+#if 0
-+ /* Check for bus arbitration loss */
-+ if (adap->arbitration_loss()){
-+ printk("Arbitration loss detected \n");
-+ adap->reset();
-+ return I2C_RETRY;
-+ }
-+#endif
-+
-+ /* Read */
-+ if (pmsg->flags & I2C_M_RD) {
-+ /* read bytes into buffer*/
-+ ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last);
-+#if DEBUG > 2
-+ if (ret != pmsg->len) {
-+ printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n",
-+ ret, pmsg->len);
-+ } else {
-+ printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret);
-+ }
-+#endif
-+ } else { /* Write */
-+ ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last);
-+#if DEBUG > 2
-+ if (ret != pmsg->len) {
-+ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n",
-+ ret, pmsg->len);
-+ } else {
-+ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret);
-+ }
-+#endif
-+ }
-+ }
-+
-+ if (ret<0){
-+ return ret;
-+ }else{
-+ return i;
-+ }
-+}
-+
-+static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
-+{
-+ int retval = i2c_pxa_valid_messages( msgs, num);
-+ if( retval > 0)
-+ {
-+ int i;
-+ for (i=i2c_adap->retries; i>=0; i--){
-+ int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num);
-+ if (retval!=I2C_RETRY){
-+ return retval;
-+ }
-+ if( i2c_debug)printk(KERN_INFO"Retrying transmission \n");
-+ udelay(100);
-+ }
-+ if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries);
-+ return -EREMOTEIO;
-+
-+ }
-+ return retval;
-+}
-+
-+static u32 i2c_pxa_functionality(struct i2c_adapter * adapter)
-+{
-+ /* Emulate the SMBUS functions */
-+ return I2C_FUNC_SMBUS_EMUL;
-+}
-+
-+struct i2c_algorithm i2c_pxa_algorithm = {
-+ name: "PXA I2C Algorithm",
-+ id: I2C_ALGO_PXA,
-+ master_xfer: i2c_pxa_xfer,
-+ smbus_xfer: NULL,
-+ slave_send: NULL,
-+ slave_recv: NULL,
-+ algo_control: NULL,
-+ functionality: i2c_pxa_functionality,
-+};
-+
-+/*
-+ * registering functions to load algorithms at runtime
-+ */
-+int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap)
-+{
-+ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
-+
-+ printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->dev.name);
-+
-+ i2c_adap->algo = &i2c_pxa_algorithm;
-+
-+ MOD_INC_USE_COUNT;
-+
-+ /* register new adapter to i2c module... */
-+ i2c_add_adapter(i2c_adap);
-+
-+ adap->reset();
-+
-+ /* scan bus */
-+ if (pxa_scan) {
-+ int i;
-+ printk(KERN_INFO "I2C: Scanning bus ");
-+ for (i = 0x02; i < 0xff; i+=2) {
-+ if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue;
-+
-+ if (adap->wait_bus_not_busy()) {
-+ printk(KERN_INFO "I2C: scanning bus %s - TIMEOUT.\n",
-+ i2c_adap->dev.name);
-+ return -EIO;
-+ }
-+ adap->write_byte(i);
-+ adap->start();
-+ adap->transfer(0, I2C_TRANSMIT, 0);
-+
-+ if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) {
-+ printk("(%02x)",i>>1);
-+ adap->abort();
-+ } else {
-+// printk(".");
-+ adap->stop();
-+ }
-+ udelay(adap->udelay);
-+ }
-+ printk("\n");
-+ }
-+ return 0;
-+}
-+
-+int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap)
-+{
-+ int res;
-+ if ((res = i2c_del_adapter(i2c_adap)) < 0)
-+ return res;
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->dev.name);
-+
-+ return 0;
-+}
-+
-+static int __init i2c_algo_pxa_init (void)
-+{
-+ printk(KERN_INFO "I2C: PXA algorithm module loaded.\n");
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(i2c_pxa_add_bus);
-+EXPORT_SYMBOL(i2c_pxa_del_bus);
-+
-+MODULE_PARM(pxa_scan, "i");
-+MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus");
-+
-+MODULE_AUTHOR("Intrinsyc Software Inc.");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_algo_pxa_init);
---- linux-2.6.5/drivers/i2c/algos/Makefile~heh 2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/i2c/algos/Makefile 2004-04-30 20:57:36.000000000 -0400
-@@ -4,6 +4,7 @@
-
- obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
- obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
-+obj-$(CONFIG_I2C_ALGOPXA) += i2c-algo-pxa.o
- obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
-
- ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
---- linux-2.6.5/Makefile~heh 2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/Makefile 2004-04-30 20:57:58.000000000 -0400
-@@ -1,7 +1,7 @@
- VERSION = 2
- PATCHLEVEL = 6
- SUBLEVEL = 5
--EXTRAVERSION =
-+EXTRAVERSION = -gnalm1
- NAME=Zonked Quokka
-
- # *DOCUMENTATION*