Hi!

This is an experimental patch that enables me to use HaReT on a E-TEN glofiish
DX900 which is based on the Samsung S3C6400 SoC

The patch is not fully cleaned-up yet, but it does the trick for me right
now.  I'll probably send a cleaned-up version at some latre point, but don't
expect it too soon.

I'm not a member of this list, so please Cc me in case of any feedback.

Regards,
-- 
- Harald Welte <[email protected]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)
diff --git a/Makefile b/Makefile
index 8fb3852..cb19987 100644
--- a/Makefile
+++ b/Makefile
@@ -85,7 +85,7 @@ $(OUT)%.exe: $(OUT)%-debug
 MACHOBJS := machines.o \
   mach-autogen.o \
   arch-pxa27x.o arch-pxa.o arch-sa.o arch-omap.o arch-s3.o arch-msm.o \
-  arch-imx.o arch-centrality.o arch-arm.o
+  arch-imx.o arch-centrality.o arch-arm.o arch-s3c64xx.o
 
 $(OUT)mach-autogen.o: src/mach/machlist.txt
 	@echo "  Building machine list"
diff --git a/haretconsole/regs_s3c.py b/haretconsole/regs_s3c.py
index eef93e8..dd54dd6 100644
--- a/haretconsole/regs_s3c.py
+++ b/haretconsole/regs_s3c.py
@@ -1,6 +1,7 @@
 # Register definitions for Samsung processors
 #
 # (C) Copyright 2007 Kevin O'Connor <[email protected]>
+# (C) Copyright 2009 Harald Welte <[email protected]>
 #
 # This file may be distributed under the terms of the GNU GPL license.
 
@@ -70,3 +71,101 @@ Regs_s3c2442 = {
                              (4, "CAMCLK_SEL"), ("0-3", "CAMCLK_DIV"))),
     }
 memalias.RegsList['ARCH:s3c2442'] = Regs_s3c2442
+
+######################################################################
+# s3c64xx
+######################################################################
+
+vic1 = (
+    (31, "INT_ADC"), (30, "INT_PENDN"), (29, "INT_SEC"), (28, "INT_RTC_ALARM"),
+    (27, "INT_IRDA"), (26, "INT_OTG"), (25, "INT_HSMMC1"), (24, "INT_HSMMC0"),
+    (23, "INT_HOSTIF"), (22, "INT_MSM"), (21, "INT_EINT4"), (20, "INT_HSIrx"),
+    (19, "INT_HSItx"), (18, "INT_I2C"), (17, "INT_SPI1_HSMMC2"), (16, "INT_SPI0"),
+    (15, "INT_UHOST"), (14, "INT_CFC"), (13, "INT_NFC"), (12, "INT_ONENAND1"),
+    (11, "INT_ONENAND0"), (10, "INT_DMA1"), (9, "INT_DMA0"), (8, "INT_UART3"),
+    (7, "INT_UART2"), (6, "INT_UART1"), (5, "INT_UART0"), (4, "INT_AC97"),
+    (3, "INT_PCM1"), (2, "INT_PCM0"), (1, "INT_EINT3"), (0, "INT_EINT2"))
+
+vic0 = (
+    (31, "INT_LCD2"), (30, "INT_LCD1"), (29, "INT_LCD0"), (28, "INT_TIMER4"),
+    (27, "INT_TIMER3"), (26, "INT_WDT"), (25, "INT_TIMER2"), (24, "INT_TIMER1"),
+    (23, "INT_TIMER0"), (22, "INT_KEYPAD"), (21, "INT_ARM_DMAS"),
+    (20, "INT_ARM_DMA"), (19, "INT_ARM_DMA_ERR"), (18, "INT_SDMA1"),
+    (17, "INT_SDMA0"), (16, "INT_MFC"), (15, "INT_JPEG"), (14, "INT_BATF"),
+    (13, "INT_SCALAR"), (12, "INT_TVENC"), (11, "INT_2D"), (10, "INT_ROTATOR"),
+    (9, "INT_POST0"), (8, "INT_3D"), (6, "INT_I2S"),
+    (5, "INT_I2C1"), (4, "INT_CAMIF_P"), (3, "INT_CAMIF_C"), (2, "INT_RTC_TIC"),
+    (1, "INT_EINT1"), (0, "INT_EINT0"))
+
+
+hclkgate = (
+    (29, "UHOST"), (28, "SECUR"), (27, "SDMA1"), (26, "SDMA0"), (25, "IROM"),
+    (24, "DDR1"), (23, "DDR0"), (22, "MEM1"), (21, "MEM0"), (20, "USB"),
+    (19, "HSMMC2"), (18, "HSMMC1"), (17, "HSMMC0"), (16, "MDP"), (15, "DHOST"),
+    (14, "IHOST"), (13, "DMA1"), (12, "DMA0"), (11, "JPEG"), (10, "CAMIF"),
+    (9, "SCALER"), (8, "2D"), (7, "TV"), (5, "POST0"),
+    (4, "ROT"), (3, "LCD"), (2, "TZIC"), (1, "INTC"), (0, "MFC"))
+
+pclkgate = (
+    (27, "IIC1"), (26, "IIS2"), (25, "RESERVED"), (24, "SKEY"), (23, "CHIPID"),
+    (22, "SPI1"), (21, "SPI0"), (20, "HSIRX"), (19, "HSITX"), (18, "GPIO"),
+    (17, "IIC0"), (16, "IIS1"), (15, "IIS0"), (14, "AC97"), (13, "TZPC"),
+    (12, "TSADC"), (11, "KEYPAD"), (10, "IRDA"), (9, "PCM1"), (8, "PCM0"),
+    (7, "PWM"), (6, "RTC"), (5, "WDT"), (4, "UART3"), (3, "UART2"), (2, "UART1"),
+    (1, "UART0"), (0, "MFC"))
+
+sclkgate = (
+    (30, "UHOST"), (29, "MMC2_48"), (28, "MMC1_48"), (27, "MMC0_48"), (26, "MMC2"),
+    (25, "MMC1"), (24, "MMC0"), (23, "SPI1_48"), (22, "SPI0_48"), (21, "SPI1"),
+    (20, "SPI0"), (19, "DAC27"), (18, "TV27"), (17, "SCALER27"), (16, "SCALER"),
+    (15, "LCD27"), (14, "LCD"), (13, "FIMC"), (12, "POST0_27"), (11, "AUDIO2"),
+    (10, "POST0"), (9, "AUDIO1"), (8, "AUDIO0"), (7, "SECUR"), (6, "IRDA"),
+    (5, "UART"), (3, "MFC"), (2, "CAM"), (1, "JPEG"))
+
+Regs_s3c64xx = {
+    0x71200000: ("VICIRQSTATUS0", vic0),
+    0x71300000: ("VICIRQSTATUS1", vic1),
+
+    0x7e00f030: ("HCKL_GATE", hclkgate),
+    0x7e00f034: ("PCLK_GATE", pclkgate),
+    0x7e00f038: ("SCLK_GATE", hclkgate),
+
+    0x7f008004: ("GPADAT", regOneBits("GPA")),
+    0x7f008024: ("GPBDAT", regOneBits("GPB")),
+    0x7f008044: ("GPCDAT", regOneBits("GPC")),
+    0x7f008064: ("GPDDAT", regOneBits("GPD")),
+    0x7f008084: ("GPEDAT", regOneBits("GPE")),
+    0x7f0080a4: ("GPFDAT", regOneBits("GPF")),
+    0x7f0080c4: ("GPGDAT", regOneBits("GPG")),
+    0x7f0080e4: ("GPHDAT", regOneBits("GPH")),
+    0x7f008104: ("GPIDAT", regOneBits("GPI")),
+    0x7f008124: ("GPJDAT", regOneBits("GPJ")),
+    0x7f008808: ("GPKDAT", regOneBits("GPK")),
+    0x7f008818: ("GPLDAT", regOneBits("GPL")),
+    0x7f008824: ("GPMDAT", regOneBits("GPM")),
+    0x7f008834: ("GPNDAT", regOneBits("GPN")),
+    0x7f008144: ("GPODAT", regOneBits("GPO")),
+    0x7f008164: ("GPPDAT", regOneBits("GPP")),
+    0x7f008184: ("GPQDAT", regOneBits("GPQ")),
+
+    0x7f008000: ("GPACON", regTwoBits("GDA")),
+    0x7f008020: ("GPBCON", regTwoBits("GDB")),
+    0x7f008040: ("GPCCON", regTwoBits("GDC")),
+    0x7f008060: ("GPDCON", regTwoBits("GDD")),
+    0x7f008080: ("GPECON", regTwoBits("GDE")),
+    0x7f0080a0: ("GPFCON", regTwoBits("GDF")),
+    0x7f0080c0: ("GPGCON", regTwoBits("GDG")),
+    0x7f0080e0: ("GPHCON", regTwoBits("GDH")),
+    0x7f008100: ("GPICON", regTwoBits("GDI")),
+    0x7f008120: ("GPJCON", regTwoBits("GDJ")),
+    0x7f008800: ("GPKCON0", regTwoBits("GDK0")),
+    0x7f008804: ("GPKCON1", regTwoBits("GDK1")),
+    0x7f008810: ("GPLCON0", regTwoBits("GDL0")),
+    0x7f008814: ("GPLCON1", regTwoBits("GDL1")),
+    0x7f008820: ("GPMCON", regTwoBits("GDM")),
+    0x7f008830: ("GPNCON", regTwoBits("GDN")),
+    0x7f008140: ("GPOCON", regTwoBits("GDO")),
+    0x7f008160: ("GPPCON", regTwoBits("GDP")),
+    0x7f008180: ("GPQCON", regTwoBits("GDQ")),
+    }
+memalias.RegsList['ARCH:s3c64xx'] = Regs_s3c64xx
diff --git a/include/arch-s3.h b/include/arch-s3.h
index fb59220..67cf569 100644
--- a/include/arch-s3.h
+++ b/include/arch-s3.h
@@ -16,3 +16,18 @@ class MachineS3c2440 : public MachineS3c2442 {
 };
 class MachineS3c2410 : public MachineS3c2442 {
 };
+
+// Definitions for Samsung s3c64xx chips.
+class MachineS3c6400 : public Machine {
+public:
+    MachineS3c6400();
+    void init();
+    int preHardwareShutdown();
+    void hardwareShutdown(struct fbinfo *fbi);
+
+    uint32 *dma_base[4];
+};
+
+// XXX - assume they are the same for now.
+class MachineS3c6410 : public MachineS3c6400 {
+};
diff --git a/include/mach-types.h b/include/mach-types.h
index 83d5484..35432b3 100644
--- a/include/mach-types.h
+++ b/include/mach-types.h
@@ -1896,6 +1896,7 @@ extern unsigned int __machine_arch_type;
 #define MACH_TYPE_HTCRAPHAEL           1910
 #define MACH_TYPE_SYGDG1               1911
 #define MACH_TYPE_SYGDG2               1912
+#define MACH_TYPE_DX900                2061
 
 #ifdef CONFIG_ARCH_EBSA110
 # ifdef machine_arch_type
@@ -24505,6 +24506,18 @@ extern unsigned int __machine_arch_type;
 # define machine_is_sygdg2()	(0)
 #endif
 
+#ifdef CONFIG_MACH_DX900
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_DX900
+# endif
+# define machine_is_dx900()	(machine_arch_type == MACH_TYPE_DX900)
+#else
+# define machine_is_dx900()	(0)
+#endif
+
 /*
  * These have not yet been registered
  */
diff --git a/src/mach/arch-s3c64xx.cpp b/src/mach/arch-s3c64xx.cpp
new file mode 100644
index 0000000..f11c5f8
--- /dev/null
+++ b/src/mach/arch-s3c64xx.cpp
@@ -0,0 +1,147 @@
+#include "arch-s3.h"
+#include "arch-arm.h" // cpuFlushCache_arm6
+#include "memory.h" // memPhysMap
+#include "script.h" // runMemScript
+
+MachineS3c6400::MachineS3c6400()
+{
+    name = "Generic Samsung s3c64xx";
+    flushCache = cpuFlushCache_arm6;
+    archname = "s3c64xx";
+    CPUInfo[0] = L"SC364xx";
+}
+
+void
+MachineS3c6400::init()
+{
+    runMemScript(
+        "set ramaddr 0x30000000\n"
+        // IRQs
+        "addlist IRQS p2v(0x71200000) 0x4030 32 0\n"
+        "addlist IRQS p2v(0x71300000) 0x4030 32 0\n"
+        //"addlist IRQS p2v(0x4A000010) 0x4030 32 0\n"
+        //"addlist IRQS p2v(0x560000a8) 0x0 32 0\n"
+        // GPIOs
+        "addlist GPIOS p2v(0x7f008004)\n"	// GPADAT
+        "addlist GPIOS p2v(0x7f008024)\n"	// GPBDAT
+        "addlist GPIOS p2v(0x7f008044)\n"	// GPCDAT
+        "addlist GPIOS p2v(0x7f008064)\n"	// GPDDAT
+        "addlist GPIOS p2v(0x7f008084)\n"	// GPEDAT
+        "addlist GPIOS p2v(0x7f0080a4)\n"	// GPFDAT
+        "addlist GPIOS p2v(0x7f0080c4)\n"	// GPGDAT
+        "addlist GPIOS p2v(0x7f0080e4)\n"	// GPHDAT
+        "addlist GPIOS p2v(0x7f008104)\n"	// GPIDAT
+        "addlist GPIOS p2v(0x7f008124)\n"	// GPJDAT
+        "addlist GPIOS p2v(0x7f008808)\n"	// GPKDAT
+        "addlist GPIOS p2v(0x7f008818)\n"	// GPLDAT
+        "addlist GPIOS p2v(0x7f008824)\n"	// GPMDAT
+        "addlist GPIOS p2v(0x7f008834)\n"	// GPNDAT
+        "addlist GPIOS p2v(0x7f008144)\n"	// GPODAT
+        "addlist GPIOS p2v(0x7f008164)\n"	// GPPDAT
+        "addlist GPIOS p2v(0x7f008184)\n"	// GPQDAT
+        // GPIO functions
+        "addlist GPIOS p2v(0x7f008000)\n"	// GPACON
+        "addlist GPIOS p2v(0x7f008020)\n"	// GPBCON
+        "addlist GPIOS p2v(0x7f008040)\n"	// GPCCON
+        "addlist GPIOS p2v(0x7f008060)\n"	// GPDCON
+        "addlist GPIOS p2v(0x7f008080)\n"	// GPECON
+        "addlist GPIOS p2v(0x7f0080a0)\n"	// GPFCON
+        "addlist GPIOS p2v(0x7f0080c0)\n"	// GPGCON
+        "addlist GPIOS p2v(0x7f0080e0)\n"	// GPHCON
+        "addlist GPIOS p2v(0x7f008100)\n"	// GPICON
+        "addlist GPIOS p2v(0x7f008120)\n"	// GPJCON
+        "addlist GPIOS p2v(0x7f008800)\n"	// GPKCON0
+        "addlist GPIOS p2v(0x7f008804)\n"	// GPKCON1
+        "addlist GPIOS p2v(0x7f008810)\n"	// GPLCON0
+        "addlist GPIOS p2v(0x7f008814)\n"	// GPLCON1
+        "addlist GPIOS p2v(0x7f008820)\n"	// GPMCON
+        "addlist GPIOS p2v(0x7f008830)\n"	// GPNCON
+        "addlist GPIOS p2v(0x7f008140)\n"	// GPOCON
+        "addlist GPIOS p2v(0x7f008160)\n"	// GPPCON
+        "addlist GPIOS p2v(0x7f008180)\n"	// GPQCON
+        // Clock & Power registers
+        "newvar CLOCKS GPIOS 'Architecture clock and power registers'\n"
+        "addlist CLOCKS p2v(0x7e00f000)\n" // APLL_LOCK
+        "addlist CLOCKS p2v(0x7e00f004)\n" // MPLL_LOCK
+        "addlist CLOCKS p2v(0x7e00f008)\n" // EPLL_LOCK
+        "addlist CLOCKS p2v(0x7e00f00c)\n" // APLL_CON
+        "addlist CLOCKS p2v(0x7e00f010)\n" // MPLL_CON
+        "addlist CLOCKS p2v(0x7e00f014)\n" // EPLL_CON0
+        "addlist CLOCKS p2v(0x7e00f018)\n" // EPLL_CON1
+        "addlist CLOCKS p2v(0x7e00f01c)\n" // CLK_SRC
+        "addlist CLOCKS p2v(0x7e00f020)\n" // CLK_DIV0
+        "addlist CLOCKS p2v(0x7e00f024)\n" // CLK_DIV1
+        "addlist CLOCKS p2v(0x7e00f028)\n" // CLK_DIV2
+        "addlist CLOCKS p2v(0x7e00f02c)\n" // CLK_OUT
+        );
+}
+
+static inline uint32 s3c_readl(volatile uint32 *base, uint32 reg)
+{
+    return base[reg/4];
+}
+
+static inline void s3c_writel(volatile uint32 *base, uint32 reg, uint32 val)
+{
+    base[(reg/4)] = val;
+}
+
+#define S3C6400_PA_DMAC0	0x75000000
+#define S3C6400_PA_DMAC1	0x75100000
+#define S3C6400_PA_DMAC2	0x7db00000
+#define S3C6400_PA_DMAC3	0x7dc00000
+
+int
+MachineS3c6400::preHardwareShutdown()
+{
+	dma_base[0] = (uint32*)memPhysMap(S3C6400_PA_DMAC0);
+	dma_base[1] = (uint32*)memPhysMap(S3C6400_PA_DMAC1);
+	dma_base[2] = (uint32*)memPhysMap(S3C6400_PA_DMAC2);
+	dma_base[3] = (uint32*)memPhysMap(S3C6400_PA_DMAC3);
+
+	if (!dma_base[0] || !dma_base[1] || !dma_base[2] || !dma_base[3])
+		return -1;
+
+	return 0;
+}
+
+static void
+s3c6400ShutdownDMA(uint32 *dma_base[4])
+{
+	int dma_ctrl, dma_ch;
+
+	/* we have 4 controllers with 8 channels each */
+	for (dma_ctrl = 0; dma_ctrl < 4; dma_ctrl++) {
+		for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+			int offset = 0x114 + (dma_ch*0x20);
+			uint32 ctrl;
+
+			/* We don't care about loosing information
+			 * in the FIFO's, so we can just do this the
+			 * hard way: clear DMACCxConfiguration bit 0 */
+			ctrl = s3c_readl(dma_base[dma_ctrl], offset) & 0x1;
+
+			if (ctrl & 0x01)
+				s3c_writel(dma_base[dma_ctrl], offset, 
+					   ctrl & ~0x1);
+		}
+	}
+
+}
+
+// Reset USB host.
+static void
+ResetUHC(volatile uint32 *uhcmap)
+{
+//    uhcmap[2] = 1;
+}
+
+void
+MachineS3c6400::hardwareShutdown(struct fbinfo *fbi)
+{
+	s3c6400ShutdownDMA(dma_base);
+//    ResetUHC(uhcmap);
+
+}
+
+REGMACHINE(MachineS3c6400)
diff --git a/src/mach/machlist.txt b/src/mach/machlist.txt
index 4fde689..d11f0a9 100644
--- a/src/mach/machlist.txt
+++ b/src/mach/machlist.txt
@@ -90,6 +90,9 @@ Wallaby,    SA      ,PW10A1,                      XDA
 Raphael,    MSM7201A,HTC Touch Pro T7272;RAPH100;RAPH800, HTCRAPHAEL, \
         set ramsize 0x6400000, \
         set ramaddr 0x20000000
+M800,       S3c2442 ,M800V02,                     M800
+X800,       S3c2442 ,X800,                        M800
+DX900,	    S3c6400 ,DX900V040,                   DX900
 
 PLATFORM=Jupiter
 Jornada820, SA      ,"HP, Jornada 820",           JORNADA820
diff --git a/src/wince/cpu-s3c64xx.cpp b/src/wince/cpu-s3c64xx.cpp
new file mode 100644
index 0000000..66efa51
--- /dev/null
+++ b/src/wince/cpu-s3c64xx.cpp
@@ -0,0 +1,262 @@
+/*
+    Linux loader for Windows CE
+    Copyright (C) 2005 Ben Dooks
+    Copyright (C) 2009 Harald Welte
+
+    For conditions of use see file COPYING
+
+    $Id: cpu-s3c64xx.cpp,v 1.8 2006/11/19 23:37:14 koconnor Exp $
+*/
+
+
+#include "haret.h"
+#include "xtypes.h"
+#define CONFIG_ACCEPT_GPL
+#include "setup.h"
+#include "memory.h"
+#include "output.h"
+#include "gpio.h"
+#include "video.h"
+#include "cpu.h"
+#include "uart.h"
+#include "resource.h"
+#include "s3c24xx.h"
+
+static uint32 *s3c_gpio;
+
+static inline uint32 s3c_readl(volatile uint32 *base, uint32 reg)
+{
+	return base[reg/4];
+}
+
+static inline void s3c_writel(volatile uint32 *base, uint32 reg, uint32 val)
+{
+	base[(reg/4)] = val;
+}
+
+#if 0
+// uart drivers
+
+#define S3C_UART (0x50008000)
+
+//#define uart_full(base) (((base)[0x10/4] & (1<<2)) == 0)
+
+/* general s3c24xx uart support */
+
+static volatile uint32 *uart_base;
+
+static void UART_s3c24xx_map(void)
+{
+  if (uart_base == NULL)
+  {
+    uart_base = (volatile uint32 *)VirtualAlloc ((void*)0x0, sizeof (void*) * 0xffff,
+      MEM_RESERVE, PAGE_READWRITE);
+    VirtualCopy ((void *)uart_base, (void *) ((S3C_UART)/256), sizeof(void *) * 0xffff,
+      PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL);
+  }
+}
+
+/* S3C2440 */
+
+static void UART_s3c2440_setup()
+{
+  UART_s3c24xx_map();
+
+  uart_base[0x00] = 0x43;
+  uart_base[0x01] = 0x8c05;
+  uart_base[0x02] = 0x06;
+  uart_base[0x03] = 0x0;
+  uart_base[0x28/4] = 0x120;
+
+  //UART_s3c24xx_puts("testing UART...\n\r");
+}
+
+static void UART_s3c2440_checksetup(void)
+{
+  if (uart_base[0x00] != 0x43)
+    uart_base[0x00] = 0x43;
+  if (uart_base[0x01] != 0x8c05)
+    uart_base[0x01] = 0x8c05;
+  if (uart_base[0x02] & 0x01)
+    uart_base[0x02] = 0x06;
+  if (uart_base[0x03] != 0)
+    uart_base[0x03] = 0;
+}
+
+static int UART_s3c2440_full(volatile uint32 *base)
+{
+  if (s3c_readl(base, S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
+    return s3c_readl(base, S3C2410_UFSTAT) & S3C2440_UFSTAT_TXFULL;
+
+  return !(s3c_readl(base, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE);
+}
+
+static void UART_s3c2440_putc(char c)
+{
+  if (uart_base == NULL)
+    UART_s3c2440_setup ();
+
+  UART_s3c2440_checksetup ();
+
+  while(UART_s3c2440_full(uart_base))
+    UART_s3c2440_checksetup ();
+
+  ((volatile u8 *)uart_base)[S3C2410_UTXH] = c;
+}
+
+static void UART_s3c2440_puts (char *s)
+{
+  int a = 0;
+
+  while (s [a])
+  {
+    UART_s3c2440_putc (s [a]);
+    a++;
+  }
+}
+
+static struct uart_drv s3c2440_uarts =
+{
+  UART_s3c2440_setup,
+  UART_s3c2440_puts
+};
+
+/* S3C2410 UART driver */
+
+static int UART_s3c2410_full (volatile uint32 *base)
+{
+  if (s3c_readl(base, S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
+    return s3c_readl (base, S3C2410_UFSTAT) & S3C2410_UFSTAT_TXFULL;
+
+  return !(s3c_readl (base, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE);
+}
+
+static void UART_s3c2410_checksetup(void)
+{
+}
+
+static void UART_s3c2410_setup (void)
+{
+  UART_s3c24xx_map();
+}
+
+static void UART_s3c2410_putc (char c)
+{
+  if (uart_base == NULL)
+    UART_s3c2410_setup ();
+
+  UART_s3c2410_checksetup ();
+
+  while(UART_s3c2410_full(uart_base))
+    UART_s3c2410_checksetup ();
+
+  ((volatile u8 *)uart_base) [S3C2410_UTXH] = c;
+}
+
+static void UART_s3c2410_puts (char *s)
+{
+  int a = 0;
+
+  while (s [a])
+  {
+    UART_s3c2440_putc (s [a]);
+    a++;
+  }
+}
+
+static bool s3c24xxDetect ()
+{
+  uint32 p15r0 = cpuGetCP (15, 0);
+
+  // please add proper detection for Samsung CPUs
+#if 0
+  if ((p15r0 >> 24) == 'i'
+   && ((p15r0 >> 13) & 7) == 1)
+    return true;
+#endif
+
+  return false;
+}
+
+static struct uart_drv s3c2410_uarts =
+{
+  UART_s3c2410_setup,
+  UART_s3c2410_puts
+};
+
+#endif
+
+static int s3c64xxSetupLoad (void)
+{
+	uint32 s3c_ver;
+
+	s3c_gpio = (uint32 *)memPhysMap(S3C6400_PA_GPIO);
+	s3c_sys = (uint32 *)memPhysMap(S3C_PA_SYS);
+
+	s3c_ver = s3c_readl(s3c_sys, 0x118);
+
+	if (s3c_ver & 0xfffff000 == 0x36400000) {
+		//UART_setDriver(&s3c6400_uarts);
+		Output(L"Detected S3C6400, Version %d\n", s3c_ver & 0xfff)
+	} else if (s3c_ver & 0xffffff00 == 0x36410100) {
+		//UART_setDriver(&s3c6410_uarts);
+		Output(L"Detected S3C6410, Version %d\n", s3c_ver & 0xff)
+	} else
+		Output(L"Unknown S3C64XX, ID 0x%08x\n", s3c_ver);
+
+	return 0;
+}
+
+// TODO - sort out shutting down IIS, DMA, etc
+
+static void s3c64xxShutdownIIS (void)
+{
+
+}
+
+const u_int32_t *dma_base[] = 
+	{ 0x75000000, 0x75100000, 0x7db00000, 0x7dc00000 };
+
+static void s3c64xxShutdownDMA (void)
+{
+	int dma_ctrl, dma_ch;
+
+	/* we have 4 controllers with 8 channels each */
+	for (dma_ctrl = 0; dma_ctrl < 4; dma_ctrl++) {
+		for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+			int offset = 0x114 + (dma_ch*0x20);
+			u_int32_t ctrl;
+
+			/* We don't care about loosing information
+			 * in the FIFO's, so we can just do this the
+			 * hard way: clear DMACCxConfiguration bit 0 */
+			ctrl = s3c_readl(dma_base[dma_ctrl], offset) & 0x1)
+
+			if (ctrl & 0x01)
+				s3c_writel(dma_base[dma_ctrl], offset, 
+					   ctrl & ~0x1);
+		}
+	}
+}
+
+static int s3c64xxShutdownPerihperals(void)
+{
+	s3c64xxShutdownIIS ();
+	s3c64xxShutdownDMA ();
+
+	return 0;
+}
+
+static int s3c64xxAttemptRecovery(void)
+{
+	return 0;
+}
+
+struct cpu_fns cpu_s3c24xx =
+{
+	L"S3C64XX",
+	s3c64xxDetect,
+	s3c64xxSetupLoad,
+	s3c64xxShutdownPerihperals,
+	s3c64xxAttemptRecovery
+};
diff --git a/src/wince/haret.vcp b/src/wince/haret.vcp
index 2699cf6..4a3dd79 100644
--- a/src/wince/haret.vcp
+++ b/src/wince/haret.vcp
@@ -1797,6 +1797,493 @@ DEP_CPP_CPU_P=\
 # End Source File
 # Begin Source File
 
+SOURCE=".\cpu-s3c64xx.cpp"
+
+!IF  "$(CFG)" == "haret - Win32 (WCE x86) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE x86) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE SH4) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE SH4) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE SH3) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE SH3) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE emulator) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE emulator) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSIV_FP) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSIV_FP) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSIV) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSIV) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPS16) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPS16) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSII_FP) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSII_FP) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSII) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE MIPSII) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE ARMV4T) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE ARMV4T) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE ARMV4I) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE ARMV4I) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE ARMV4) Release"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ELSEIF  "$(CFG)" == "haret - Win32 (WCE ARMV4) Debug"
+
+DEP_CPP_CPU_S=\
+	"..\..\include\cpu.h"\
+	"..\..\include\gpio.h"\
+	"..\..\include\haret.h"\
+	"..\..\include\output.h"\
+	"..\..\include\pxa2xx.h"\
+	"..\..\include\resource.h"\
+	"..\..\include\s3c64xx.h"\
+	"..\..\include\s3c64xx\map.h"\
+	"..\..\include\s3c64xx\regs-dma.h"\
+	"..\..\include\s3c64xx\regs-gpio.h"\
+	"..\..\include\s3c64xx\regs-serial.h"\
+	"..\..\include\setup.h"\
+	"..\..\include\uart.h"\
+	"..\..\include\video.h"\
+	"..\..\include\xtypes.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
 SOURCE=".\cpu-s3c24xx.cpp"
 
 !IF  "$(CFG)" == "haret - Win32 (WCE x86) Release"

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Haret mailing list
[email protected]
https://handhelds.org/mailman/listinfo/haret

Reply via email to