#
# Patch managed by http://www.holgerschurig.de/patcher.html
#

--- linux-2.4.27/arch/arm/mach-sa1100/sa1100_usb.h~sa1100-usb
+++ linux-2.4.27/arch/arm/mach-sa1100/sa1100_usb.h
@@ -10,6 +10,11 @@
 #define _SA1100_USB_H
 #include <asm/byteorder.h>
 
+#define SA1100_USB_DEBUG
+#ifdef SA1100_USB_DEBUG
+extern int sa1100_usb_debug;
+#endif
+
 typedef void (*usb_callback_t)(int flag, int size);
 
 /* in usb_ctl.c (see also descriptor methods at bottom of file) */
--- linux-2.4.27/arch/arm/mach-sa1100/usb_ctl.c~sa1100-usb
+++ linux-2.4.27/arch/arm/mach-sa1100/usb_ctl.c
@@ -28,6 +28,12 @@
 #include "sa1100_usb.h"
 #include "usb_ctl.h"
 
+// Toby Churchill Ltd modification to re assert Ser0UDCOMP when it gets corrupted (why?)
+// Identified by Chris Jones for TCL.
+// Added 25/3/2004 N C Bane for balloon board.
+#define TCL_FIX
+
+
 //////////////////////////////////////////////////////////////////////////////
 // Prototypes
 //////////////////////////////////////////////////////////////////////////////
@@ -109,6 +115,45 @@
 //////////////////////////////////////////////////////////////////////////////
 // Async
 //////////////////////////////////////////////////////////////////////////////
+
+#ifdef CONFIG_SA1100_USB_HOTPLUG
+// user space notification support for sa1100 usb state change
+// Copyright (c) 2003 N C Bane
+#include <linux/kmod.h>
+#include <linux/interrupt.h>
+//static int usb_hotplug_state=USB_STATE_DEFAULT;
+
+static void do_usb_helper (void *status)
+{
+	char *argv [3], *envp [3];
+	int v;
+
+	argv [0] = "/sbin/sausb-hotplug";
+
+	argv [1] = device_state_names[(int)status];
+	argv [2] = NULL;
+
+	envp [0] = "HOME=/";
+	envp [1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp [2] = NULL;
+
+	v = call_usermodehelper (argv [0], argv, envp);
+
+	if (v != 0)
+		printk ("sausb hotplug returned 0x%x", v);
+}
+
+static struct tq_struct usb_task;
+
+static void usb_helper (int status) {
+//    usb_hotplug_state = status;
+    usb_task.routine=do_usb_helper;
+    usb_task.data=(void *)status;
+    schedule_task(&usb_task);
+}
+
+#endif
+
 static void core_kicker(void);
 
 static inline void enable_resume_mask_suspend( void );
@@ -119,6 +164,7 @@
 {
   	__u32 status = Ser0UDCSR;
 
+//static int reset;
 	/* ReSeT Interrupt Request - UDC has been reset */
 	if ( status & UDCSR_RSTIR )
 	{
@@ -133,6 +179,7 @@
 		// mask reset ints, they flood during sequence, enable
 		// suspend and resume
 		Ser0UDCCR |= UDCCR_REM;    // mask reset
+//reset=true;
 		Ser0UDCCR &= ~(UDCCR_SUSIM | UDCCR_RESIM); // enable suspend and resume
 		UDC_flip(  Ser0UDCSR, status );	// clear all pending sources
 		return;		// <-- no reason to continue if resetting
@@ -160,6 +207,13 @@
 	if (status & UDCSR_EIR)
 		 ep0_int_hndlr();
 
+#ifdef TCL_FIX
+	if (Ser0UDCOMP!=63) {
+	    printk("%s: Ser0UDCOMP = %d. Reset to 63\n",__FUNCTION__,Ser0UDCOMP);
+	    Ser0UDCOMP=63;
+	}
+#endif
+
 	if (status & UDCSR_RIR)
 		ep1_int_hndlr(status);
 
@@ -443,6 +497,12 @@
 			   ) {
 			  configured_callback();
 			}
+#ifdef CONFIG_SA1100_USB_HOTPLUG
+		    if (next_device_state == USB_STATE_CONFIGURED)
+			usb_helper(next_device_state);
+		    if ((next_device_state == USB_STATE_SUSPENDED) && (usbd_info.state == USB_STATE_CONFIGURED))
+			usb_helper(next_device_state);
+#endif
 			usbd_info.state = next_device_state;
 			ep1_state_change_notify( next_device_state );
 			ep2_state_change_notify( next_device_state );
@@ -683,6 +743,43 @@
 	 return len;
 }
 
+#ifdef SA1100_USB_DEBUG
+#include <asm/uaccess.h>                /* to copy to/from userspace */
+struct proc_dir_entry *debug_entry;
+
+static int proc_debug_read (struct file * file, char * buf,
+		size_t nbytes, loff_t *ppos)
+{
+	char outputbuf[8];
+	int count;
+	// read completed?
+	if (*ppos)
+	    return 0;
+	count=sprintf(outputbuf, "%d\n",sa1100_usb_debug);
+	if (copy_to_user(buf, outputbuf, count))
+		return -EFAULT;
+	return count;
+}
+
+static ssize_t proc_debug_write(struct file * file, const char * buffer,
+		size_t count, loff_t *ppos)
+{
+	char *endp;
+	if (*ppos)
+	    return -EINVAL;
+	sa1100_usb_debug = simple_strtoul(buffer,&endp,0);
+	// we claim all is read
+	return count;
+}
+
+
+
+static struct file_operations proc_debug_operations = {
+	read:	proc_debug_read,
+	write:	proc_debug_write
+};
+
+#endif
 #endif  /* CONFIG_PROC_FS */
 
 //////////////////////////////////////////////////////////////////////////////
@@ -703,6 +800,15 @@
 
 #if CONFIG_PROC_FS
 	create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL);
+#ifdef SA1100_USB_DEBUG
+	{
+	    debug_entry = create_proc_entry("sa1100_usb_debug",
+				S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH,
+				&proc_root);
+	    if (debug_entry) 
+		    debug_entry->proc_fops = &proc_debug_operations;
+	}
+#endif
 #endif
 
 	/* setup rx dma */
@@ -751,6 +857,9 @@
 
 #if CONFIG_PROC_FS
     remove_proc_entry ( PROC_NODE_NAME, NULL);
+#ifdef SA1100_USB_DEBUG
+    remove_proc_entry("sa1100_usb_debug",&proc_root);
+#endif
 #endif
 
     sa1100_free_dma(usbd_info.dmach_rx);
@@ -769,6 +878,10 @@
 EXPORT_SYMBOL( sa1100_usb_get_string_descriptor );
 EXPORT_SYMBOL( sa1100_usb_kmalloc_string_descriptor );
 
+#ifdef SA1100_USB_DEBUG
+int sa1100_usb_debug=0;
+EXPORT_SYMBOL(sa1100_usb_debug);
+#endif
 
 module_init( usbctl_init );
 module_exit( usbctl_exit );
--- linux-2.4.27/arch/arm/config.in~sa1100-usb
+++ linux-2.4.27/arch/arm/config.in
@@ -138,6 +138,9 @@
 dep_bool '  Yopy' CONFIG_SA1100_YOPY $CONFIG_ARCH_SA1100
 
 dep_tristate 'SA1100 USB function support' CONFIG_SA1100_USB $CONFIG_ARCH_SA1100
+if [ "$CONFIG_SA1100_USB" != "n" ]; then
+   bool '  Support for SA11x0 USB usb-hotplug' CONFIG_SA1100_USB_HOTPLUG
+fi
 dep_tristate '  Support for SA11x0 USB network link function' CONFIG_SA1100_USB_NETLINK $CONFIG_SA1100_USB
 dep_tristate '  Support for SA11x0 USB character device emulation' CONFIG_SA1100_USB_CHAR $CONFIG_SA1100_USB