[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[MiNT] [PATCH] EHCI host controller driver



Please commit this patch that adds support for USB EHCI host controllers.

To dont' break builds the patch from yesterday "[PATCH] Add more
useful macros to kcompiler.h" must be applied too.


Thanks!
Index: sys/usb/src.km/usb.h
===================================================================
RCS file: /mint/freemint/sys/usb/src.km/usb.h,v
retrieving revision 1.13
diff -u -8 -r1.13 usb.h
--- sys/usb/src.km/usb.h	9 Apr 2014 09:27:23 -0000	1.13
+++ sys/usb/src.km/usb.h	30 Apr 2014 08:58:14 -0000
@@ -41,16 +41,22 @@
 #define USB_MAXINTERFACES		8
 #define USB_MAXENDPOINTS		16
 #define USB_MAXCHILDREN			8	/* This is arbitrary */
 #define USB_MAX_HUB			16
 
 #define USB_CNTL_TIMEOUT 		100	/* 100ms timeout */
 #define USB_BUFSIZ			512
 
+/*
+ * This is the timeout to allow for submitting a message in ms.
+ * We allow more time for a BULK device to react - some are slow.
+ */
+#define USB_TIMEOUT_MS(pipe) (usb_pipebulk(pipe) ? 5000 : 100)
+
 /* String descriptor */
 struct usb_string_descriptor
 {
 	unsigned char	bLength;
 	unsigned char	bDescriptorType;
 	unsigned short	wData[1];
 } __attribute__ ((packed));
 
Index: sys/usb/src.km/ucd/Makefile
===================================================================
RCS file: /mint/freemint/sys/usb/src.km/ucd/Makefile,v
retrieving revision 1.6
diff -u -8 -r1.6 Makefile
--- sys/usb/src.km/ucd/Makefile	13 Jan 2014 16:01:46 -0000	1.6
+++ sys/usb/src.km/ucd/Makefile	30 Apr 2014 08:58:15 -0000
@@ -1,14 +1,14 @@
 #
 # Makefile for 
 #
 
 SHELL = /bin/sh
-SUBDIRS = aranym ethernat netusbee unicorn
+SUBDIRS = aranym ehci ethernat netusbee unicorn
 
 srcdir = .
 top_srcdir = ../../..
 subdir = ucd
 
 default: all
 
 include $(top_srcdir)/CONFIGVARS
Index: sys/usb/src.km/ucd/ehci/BINFILES
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/BINFILES
@@ -0,0 +1,4 @@
+# This file gets included by the Makefile in this directory to determine
+# the files that should go only into binary distributions.
+
+BINFILES = ehci-pci.ucd
Index: sys/usb/src.km/ucd/ehci/COPYING
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: sys/usb/src.km/ucd/ehci/EXTRAFILES
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/EXTRAFILES
@@ -0,0 +1,4 @@
+# This file gets included by the Makefile in this directory to determine
+# the files that should go only into source distributions.
+
+SRCFILES += BINFILES EXTRAFILES MISCFILES Makefile SRCFILES
Index: sys/usb/src.km/ucd/ehci/MISCFILES
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/MISCFILES
@@ -0,0 +1,4 @@
+# This file gets included by the Makefile in this directory to determine
+# the files that should go both into source and binary distributions.
+
+MISCFILES = README
Index: sys/usb/src.km/ucd/ehci/Makefile
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for ucd module
+#
+TARGET = ehci-pci.ucd
+
+SHELL = /bin/sh
+SUBDIRS = 
+
+srcdir = .
+top_srcdir = ../../../..
+subdir = ehci-pci
+
+default: all
+
+include $(top_srcdir)/CONFIGVARS
+include $(top_srcdir)/RULES
+include $(top_srcdir)/PHONY
+
+all-here: $(TARGET)
+
+# default overwrites
+INCLUDES = -I$(top_srcdir)
+DEFINITIONS = -D__KERNEL_MODULE__ -DMODULE_NAME=ehci-pci $(XDD_DEFINITIONS)
+XDD_DEFINITIONS = 
+
+LD = $(CC) -nostdlib -Wl,--entry -Wl,_init
+LIBS = $(LIBKERN) -lgcc
+CPU = 000
+
+# default definitions
+SGENFILES = $(TARGET)
+OBJS = $(SSOBJS:.S=.o) $(COBJS:.c=.o)
+
+$(TARGET): $(OBJS) $(LIBKERNTARGET)
+	$(LD) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+include $(top_srcdir)/DEPENDENCIES
Index: sys/usb/src.km/ucd/ehci/README
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/README
@@ -0,0 +1 @@
+
Index: sys/usb/src.km/ucd/ehci/SRCFILES
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/SRCFILES
@@ -0,0 +1,13 @@
+# This file gets included by the Makefile in this directory to determine
+# the files that should go only into source distributions.
+
+HEADER = \
+	ehci.h \
+
+COBJS = \
+	ehci-hcd.c \
+	ehci-pci.c
+
+SSOBJS = \
+
+SRCFILES = $(HEADER) $(COBJS) $(SSOBJS)
Index: sys/usb/src.km/ucd/ehci/ehci-hcd.c
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/ehci-hcd.c
@@ -0,0 +1,1215 @@
+/*
+ * Adapted for FreeMiNT by David Galvez 2014
+ * Ported for Atari by Didier Mequignon
+ *
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Excito Elektronik i Skåne AB
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * 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 version 2 of
+ * the License.
+ *
+ * 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
+ */
+
+#include <stddef.h>
+
+#include "mint/mint.h"
+#include "mint/dcntl.h"
+
+#include "libkern/libkern.h"
+
+#include "../../usb.h"
+#include "../../hub.h"
+#include "../ucd_defs.h"
+#include "ehci.h"
+
+
+#define VER_MAJOR	0
+#define VER_MINOR	1
+#define VER_STATUS
+
+#define MSG_VERSION	str (VER_MAJOR) "." str (VER_MINOR) str (VER_STATUS)
+#define MSG_BUILDDATE	__DATE__
+
+#define MSG_BOOT	\
+	"\033p EHCI USB controller driver " MSG_VERSION " \033q\r\n"
+
+#define MSG_GREET	\
+	"Ported by David Galvez.\r\n" \
+	"Compiled " MSG_BUILDDATE ".\r\n\r\n"
+
+#define MSG_MINT	\
+	"\033pMiNT too old!\033q\r\n"
+
+#define MSG_FAILURE	\
+	"\7\r\nSorry, failed!\r\n\r\n"
+
+/*
+ * Debug section
+ */
+
+#if 0
+# define DEV_DEBUG	1
+#endif
+
+#ifdef DEV_DEBUG
+
+# define FORCE(x)	KERNEL_FORCE x
+# define ALERT(x)	KERNEL_ALERT x
+# define DEBUG(x)	KERNEL_DEBUG x
+# define TRACE(x)	KERNEL_TRACE x
+# define ASSERT(x)	assert x
+
+#else
+
+# define FORCE(x)	KERNEL_FORCE x
+# define ALERT(x)	KERNEL_ALERT x
+# define DEBUG(x)
+# define TRACE(x)
+# define ASSERT(x)	assert x
+
+#endif
+
+/*
+ * kernel interface
+ */
+
+struct kentry	*kentry;
+struct ucdinfo	*uinf;
+
+/*
+ * USB controller interface
+ */
+
+static long _cdecl	ehci_open		(struct ucdif *);
+static long _cdecl	ehci_close		(struct ucdif *);
+static long _cdecl	ehci_ioctl		(struct ucdif *, short, long);
+
+static char lname[] = "EHCI-PCI USB controller driver for FreeMiNT\0";
+
+/*
+ * Function prototypes
+ */
+
+void		ehci_usb_enable_interrupt	(long);
+void		ehci_show_registers	(struct ehci *, struct devrequest *);
+void		ehci_show_qh		(struct QH *, struct ehci *);
+void		__ehci_powerup_fixup	(unsigned long *, unsigned long *);
+
+long		submit_bulk_msg		(struct usb_device *, unsigned long, void *, long);
+long		submit_control_msg	(struct usb_device *, unsigned long, void *, long, struct devrequest *);
+long		submit_int_msg		(struct usb_device *, unsigned long, void *, long, long);
+
+long _cdecl	init			(struct kentry *, struct ucdinfo *, char **);
+
+/*
+ * Structures
+ */
+
+struct descriptor {
+	struct usb_hub_descriptor hub;
+	struct usb_device_descriptor device;
+	struct usb_linux_config_descriptor config;
+	struct usb_linux_interface_descriptor interface;
+	struct usb_endpoint_descriptor endpoint;
+} __attribute__ ((packed));
+
+static struct descriptor rom_descriptor = {
+	{
+		0x8,		/* bDescLength */
+		0x29,		/* bDescriptorType: hub descriptor */
+		2,		/* bNrPorts -- runtime modified */
+		0,		/* wHubCharacteristics */
+		10,		/* bPwrOn2PwrGood */
+		0,		/* bHubCntrCurrent */
+		{},		/* Device removable */
+		{}		/* at most 7 ports! XXX */
+	},
+	{
+		0x12,		/* bLength */
+		1,		/* bDescriptorType: UDESC_DEVICE */
+		0x0002,		/* bcdUSB: v2.0 cpu2le16(0x0200)*/
+		9,		/* bDeviceClass: UDCLASS_HUB */
+		0,		/* bDeviceSubClass: UDSUBCLASS_HUB */
+		1,		/* bDeviceProtocol: UDPROTO_HSHUBSTT */
+		64,		/* bMaxPacketSize: 64 bytes */
+		0x0000,		/* idVendor */
+		0x0000,		/* idProduct */
+		0x0001,		/* bcdDevice cpu2le16(0x0100)*/
+		1,		/* iManufacturer */
+		2,		/* iProduct */
+		0,		/* iSerialNumber */
+		1		/* bNumConfigurations: 1 */
+	},
+	{
+		0x9,
+		2,		/* bDescriptorType: UDESC_CONFIG */
+		(0x19 << 8),	/* cpu_to_le16(0x19), */
+		1,		/* bNumInterface */
+		1,		/* bConfigurationValue */
+		0,		/* iConfiguration */
+		0x40,		/* bmAttributes: UC_SELF_POWER */
+		0		/* bMaxPower */
+	},
+	{
+		0x9,		/* bLength */
+		4,		/* bDescriptorType: UDESC_INTERFACE */
+		0,		/* bInterfaceNumber */
+		0,		/* bAlternateSetting */
+		1,		/* bNumEndpoints */
+		9,		/* bInterfaceClass: UICLASS_HUB */
+		0,		/* bInterfaceSubClass: UISUBCLASS_HUB */
+		0,		/* bInterfaceProtocol: UIPROTO_HSHUBSTT */
+		0		/* iInterface */
+	},
+	{
+		0x7,		/* bLength */
+		5,		/* bDescriptorType: UDESC_ENDPOINT */
+		0x81,		/* bEndpointAddress: UE_DIR_IN | EHCI_INTR_ENDPT */
+		3,		/* bmAttributes: UE_INTERRUPT */
+		8, 0,		/* wMaxPacketSize */
+		255		/* bInterval */
+	},
+};
+
+#if defined(CONFIG_EHCI_IS_TDI)
+#define ehci_is_TDI()	(1)
+#else
+#define ehci_is_TDI()	(0)
+#endif
+
+/*
+ * Debug functions
+ */
+
+void ehci_show_registers(struct ehci *gehci, struct devrequest *req)
+{
+	DEBUG(("[USBCMD] %08lx", ehci_readl(&gehci->hcor->or_usbcmd)));
+	DEBUG(("[USBSTS] %08lx", ehci_readl(&gehci->hcor->or_usbsts)));
+
+	int i = gehci->descriptor->hub.bNbrPorts;
+	while (i) {
+		DEBUG(("status reg port[%d] 0x%08lx", i + 1, ehci_readl(&gehci->hcor->or_portsc[i])));
+		i--;
+	};
+}
+
+void ehci_show_qh(struct QH *qh, struct ehci *gehci)
+{
+	DEBUG(("[0x%08lx] %08lx", ((unsigned long *)qh) + 0, hc32_to_cpu(qh->qh_link)));
+	DEBUG(("[0x%08lx] %08lx", ((unsigned long *)qh) + 1, hc32_to_cpu(qh->qh_endpt1)));
+	DEBUG(("[0x%08lx] %08lx", ((unsigned long *)qh) + 2, hc32_to_cpu(qh->qh_endpt2)));
+	DEBUG(("[0x%08lx] %08lx current qtd", ((unsigned long *)qh) + 3, hc32_to_cpu(qh->qh_curtd)));
+	DEBUG(("[0x%08lx] %08lx", ((unsigned long *)qh) + 4, hc32_to_cpu(qh->qh_overlay.qt_next)));
+	DEBUG(("[0x%08lx] %08lx", ((unsigned long *)qh) + 5, hc32_to_cpu(qh->qh_overlay.qt_altnext)));
+	DEBUG(("[0x%08lx] %08lx", ((unsigned long *)qh) + 6, hc32_to_cpu(qh->qh_overlay.qt_token)));
+	DEBUG(("[0x%08lx] %08lx buffer", ((unsigned long *)qh) + 7, hc32_to_cpu(qh->qh_overlay.qt_buffer[0])));
+
+	if (qh->qh_curtd != 0) {
+		DEBUG(("[0x%08lx] %08lx current qtd", 
+					hc32_to_cpu(qh->qh_curtd), 
+					hc32_to_cpu(*(((unsigned long *)(hc32_to_cpu(qh->qh_curtd)))))));
+		DEBUG(("[0x%08lx] %08lx", 
+					(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 1), 
+					hc32_to_cpu(*(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 1))));
+		DEBUG(("[0x%08lx] %08lx", 
+					(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 2), 
+					hc32_to_cpu(*(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 2))));
+		DEBUG(("[0x%08lx] %08lx", 
+					(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 3), 
+					hc32_to_cpu(*(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 3))));
+		DEBUG(("[0x%08lx] %08lx", 
+					hc32_to_cpu(*(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 3)), 
+					*((unsigned long *)(hc32_to_cpu(*(((unsigned long *)hc32_to_cpu(qh->qh_curtd)) + 3))))));
+	}
+}
+
+
+/*
+ * EHCI functions
+ */
+
+void __ehci_powerup_fixup(unsigned long *status_reg, unsigned long *reg)
+{
+	mdelay(50);
+}
+void ehci_powerup_fixup(unsigned long *status_reg, unsigned long *reg)
+	__attribute__((weak, alias("__ehci_powerup_fixup")));
+
+static long handshake(unsigned long *ptr, unsigned long mask, unsigned long done, long usec)
+{
+	unsigned long result;
+	do
+	{
+		result = ehci_readl(ptr);
+		udelay(5);
+		if(result == ~(unsigned long)0)
+			return -1;
+		result &= mask;
+		if(result == done)
+			return 0;
+		usec--;
+	}
+	while(usec > 0);
+	return -1;
+}
+
+static void ehci_free(void *p, size_t sz)
+{
+}
+
+static long ehci_reset(struct ehci *gehci)
+{
+	unsigned long cmd;
+	unsigned long tmp;
+	unsigned long *reg_ptr;
+	long ret = 0;
+
+	ehci_bus_reset(gehci);
+
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+	cmd = (cmd & ~CMD_RUN) | CMD_RESET;
+	ehci_writel(&gehci->hcor->or_usbcmd, cmd);
+	ret = handshake((unsigned long *)&gehci->hcor->or_usbcmd, CMD_RESET, 0, 250L * 1000L);
+	if(ret < 0)
+	{
+		ALERT(("EHCI fail to reset"));
+		FORCE(("EHCI fail to reset"));
+		goto out;
+	}
+	if(ehci_is_TDI())
+	{
+		reg_ptr = (unsigned long *)((unsigned char *)gehci->hcor + USBMODE);
+		tmp = ehci_readl(reg_ptr);
+		tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+		tmp |= USBMODE_BE;
+#endif
+		ehci_writel(reg_ptr, tmp);
+	}
+out:
+	return ret;
+}
+
+static void *ehci_alloc(struct ehci *gehci, size_t sz, size_t align)
+{
+	static long ntds;
+	void *p;
+	switch(sz)
+	{
+		case sizeof(struct QH):
+			p = gehci->qh;
+			ntds = 0;
+			break;
+		case sizeof(struct qTD):
+			if(ntds == 3)
+			{
+				DEBUG(("out of TDs"));
+				return NULL;
+			}
+			p = gehci->td[ntds];
+			ntds++;
+			break;
+		default:
+			DEBUG(("unknown allocation size"));
+			return NULL;
+	}
+	memset(p, 0, sz);
+	return p;
+}
+
+static long ehci_td_buffer(struct ehci *gehci, struct qTD *td, void *buf, size_t sz)
+{
+	unsigned long delta, next;
+	unsigned long addr = (ulong)buf;
+	size_t rsz = ROUNDUP(sz, 32);
+	long idx;
+
+	if (sz != rsz)
+		DEBUG(("EHCI-HCD: Misaligned buffer size (%08x)\n", sz));
+	if (addr & 31)
+		DEBUG(("EHCI-HCD: Misaligned buffer address (%lx)\n", buf));
+
+	idx = 0;
+	while(idx < 5)
+	{
+		td->qt_buffer[idx] = cpu_to_hc32(addr - gehci->dma_offset);
+		next = (addr + 4096) & ~4095;
+		delta = next - addr;
+		if (delta >= sz)
+			break;
+		sz -= delta;
+		addr = next;
+		idx++;
+	}
+	if(idx == 5)
+	{
+		DEBUG(("out of buffer pointers (%u bytes left)", sz));
+		return -1;
+	}
+	return 0;
+}
+
+static inline unsigned char ehci_encode_speed(enum usb_device_speed speed)
+{
+	#define QH_HIGH_SPEED	2
+	#define QH_FULL_SPEED	0
+	#define QH_LOW_SPEED	1
+	if (speed == USB_SPEED_HIGH)
+		return QH_HIGH_SPEED;
+	if (speed == USB_SPEED_LOW)
+		return QH_LOW_SPEED;
+	return QH_FULL_SPEED;
+}
+
+static long ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, long length, struct devrequest *req)
+{
+	struct QH *qh;
+	struct qTD *td;
+	volatile struct qTD *vtd;
+	unsigned long ts;
+	unsigned long *tdp;
+	unsigned long endpt, token, usbsts;
+	unsigned long c, toggle;
+	unsigned long cmd;
+	int timeout;
+	long ret = 0;
+
+	struct ehci *gehci = ((struct ucdif*)dev->controller)->ucd_priv;
+
+	DEBUG(("dev=0x%lx, pipe=0x%lx, buffer=0x%lx, length=%ld, req=0x%lx", dev, pipe, buffer, length, req));
+	if(req != NULL)
+		DEBUG(("ehci_submit_async req=%u (0x%x), type=%u (0x%x), value=%u (0x%x), index=%u",
+		req->request, req->request, req->requesttype, req->requesttype,
+		le2cpu16(req->value), le2cpu16(req->value), le2cpu16(req->index)));
+	qh = ehci_alloc(gehci, sizeof(struct QH), 32);
+
+	if(qh == NULL)
+	{
+		DEBUG(("unable to allocate QH"));
+		return -1;
+	}
+
+	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+	qh->qh_link = cpu_to_hc32(((unsigned long)gehci->qh_list - gehci->dma_offset) | QH_LINK_TYPE_QH);
+	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && usb_pipeendpoint(pipe) == 0) ? 1 : 0;
+
+	endpt = (8UL << 28) | (c << 27) | ((*uinf->usb_maxpacket)(dev, pipe) << 16) |
+		(0 << 15) | (1 << 14) | (ehci_encode_speed(usb_pipespeed(pipe)) << 12) |
+		(usb_pipeendpoint(pipe) << 8) | (0 << 7) | (usb_pipedevice(pipe) << 0);
+	qh->qh_endpt1 = cpu_to_hc32(endpt);
+	endpt = (1UL << 30) | (dev->portnr << 23) | (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
+	qh->qh_endpt2 = cpu_to_hc32(endpt);
+	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+
+	td = NULL;
+	tdp = &qh->qh_overlay.qt_next;
+
+	if(req != NULL)
+	{
+		td = ehci_alloc(gehci, sizeof(struct qTD), 32);
+		if(td == NULL)
+		{
+			DEBUG(("unable to allocate SETUP td"));
+			goto fail;
+		}
+		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		token = (0UL << 31) | (sizeof(*req) << 16) | (0 << 15) |
+			(0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
+		td->qt_token = cpu_to_hc32(token);
+
+		if(ehci_td_buffer(gehci, td, req, sizeof(*req)) != 0)
+		{
+			DEBUG(("unable construct SETUP td"));
+			ehci_free(td, sizeof(*td));
+			goto fail;
+		}
+		*tdp = cpu_to_hc32((unsigned long)td - gehci->dma_offset);
+		tdp = &td->qt_next;
+		toggle = 1;
+	}
+
+	if(length > 0 || req == NULL)
+	{
+		td = ehci_alloc(gehci, sizeof(struct qTD), 32);
+		if(td == NULL)
+		{
+			DEBUG(("unable to allocate DATA td"));
+			goto fail;
+		}
+		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		token = (toggle << 31) | (length << 16) | ((req == NULL ? 1U : 0) << 15) |
+			(0 << 12) | (3 << 10) | ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
+		td->qt_token = cpu_to_hc32(token);
+		if(ehci_td_buffer(gehci, td, buffer, length) != 0)
+		{
+			DEBUG(("unable construct DATA td"));
+			ehci_free(td, sizeof(*td));
+			goto fail;
+		}
+		*tdp = cpu_to_hc32((unsigned long)td - gehci->dma_offset);
+		tdp = &td->qt_next;
+	}
+
+	if(req != NULL)
+	{
+		td = ehci_alloc(gehci, sizeof(struct qTD), 32);
+		if(td == NULL)
+		{
+			DEBUG(("unable to allocate ACK td"));
+			goto fail;
+		}
+		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		token = (toggle << 31) | (0UL << 16) | (1U << 15) | (0 << 12) |
+			(3 << 10) | ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
+		td->qt_token = cpu_to_hc32(token);
+		*tdp = cpu_to_hc32((unsigned long)td - gehci->dma_offset);
+		tdp = &td->qt_next;
+	}
+
+	gehci->qh_list->qh_link = cpu_to_hc32(((unsigned long)qh - gehci->dma_offset) | QH_LINK_TYPE_QH);
+	/* Flush dcache */
+	cpush(&gehci->qh_list, (long)&gehci->qh_list + sizeof(struct QH));
+	cpush(&qh, (long)&qh + sizeof(struct QH));
+	cpush(td, (long)td + sizeof(struct qTD));
+	usbsts = ehci_readl(&gehci->hcor->or_usbsts);
+	ehci_writel(&gehci->hcor->or_usbsts, (usbsts & 0x3f));
+
+	/* Enable async. schedule. */
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+	cmd |= CMD_ASE;
+	ehci_writel(&gehci->hcor->or_usbcmd, cmd);
+	ret = handshake((unsigned long *)&gehci->hcor->or_usbsts, STD_ASS, STD_ASS, 100L * 1000L);
+	if(ret < 0)
+	{
+		ALERT(("EHCI fail timeout STD_ASS set (usbsts=%x)", ehci_readl(&gehci->hcor->or_usbsts)));
+		goto fail;
+	}
+
+	/* Wait for TDs to be processed. */
+	ts = 0;
+	timeout = USB_TIMEOUT_MS(pipe);
+	vtd = td;
+	do
+	{
+		/* Invalidate dcache */
+		cpush(&gehci->qh_list, (long)&gehci->qh_list + sizeof(struct QH));
+		cpush(&qh, (long)&qh + sizeof(struct QH));
+		cpush(td, (long)td + sizeof(struct qTD));
+		token = hc32_to_cpu(vtd->qt_token);
+		if(!(token & 0x80))
+			break;
+		mdelay(1);
+		ts++;
+	}
+	while(ts < timeout);
+
+	/* Invalidate the memory area occupied by buffer */
+	cpush((void *)((ulong)buffer & ~31), ((long)buffer & ~31) + ROUNDUP(length, 32));
+
+	/* Check that the TD processing happened */
+	if (token & 0x80) {
+		DEBUG(("EHCI timed out on TD - token=%02lx\n", 0xff & token));
+	}
+
+	/* Disable async schedule. */
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+	cmd &= ~CMD_ASE;
+	ehci_writel(&gehci->hcor->or_usbcmd, cmd);
+	ret = handshake((unsigned long *)&gehci->hcor->or_usbsts, STD_ASS, 0, 100L * 1000L);
+	if(ret < 0)
+	{
+		ALERT(("EHCI fail timeout STD_ASS reset (usbsts=%x)", ehci_readl(&gehci->hcor->or_usbsts)));
+		goto fail;
+	}
+
+	gehci->qh_list->qh_link = cpu_to_hc32(((unsigned long)gehci->qh_list - gehci->dma_offset) | QH_LINK_TYPE_QH);
+	if(!(token & 0x80))
+	{
+		DEBUG(("TOKEN=%lx", token));
+		switch(token & 0xfc)
+		{
+			case 0:
+				toggle = token >> 31;
+				usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle);
+				dev->status = 0;
+				break;
+			case 0x40:
+				dev->status = USB_ST_STALLED;
+				break;
+			case 0xa0:
+			case 0x20:
+				dev->status = USB_ST_BUF_ERR;
+				break;
+			case 0x50:
+			case 0x10:
+				dev->status = USB_ST_BABBLE_DET;
+				break;
+			default:
+				dev->status = USB_ST_CRC_ERR;
+				if ((token & 0x40) == 0x40)
+					dev->status |= USB_ST_STALLED;
+				break;
+		}
+		dev->act_len = length - ((token >> 16) & 0x7fff);
+	}
+	else
+	{
+		dev->act_len = 0;
+		DEBUG(("dev=%ld, usbsts=0x%lx, p[1]=0x%lx, p[2]=0x%lx",
+		 dev->devnum, ehci_readl(&gehci->hcor->or_usbsts), ehci_readl(&gehci->hcor->or_portsc[0]), ehci_readl(&gehci->hcor->or_portsc[1])));
+	}
+	return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
+fail:
+	td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
+	if(td != (void *)QT_NEXT_TERMINATE)
+		td = (struct qTD *)(gehci->dma_offset + (unsigned long)td);
+	while(td != (void *)QT_NEXT_TERMINATE)
+	{
+		qh->qh_overlay.qt_next = td->qt_next;
+		ehci_free(td, sizeof(*td));
+		td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
+		if(td != (void *)QT_NEXT_TERMINATE)
+			td = (struct qTD *)(gehci->dma_offset + (unsigned long)td);
+	}
+	ehci_free(qh, sizeof(*qh));
+	if(ehci_readl(&gehci->hcor->or_usbsts) & STS_HSE) /* Host System Error */
+	{
+		ALERT(("EHCI Host System Error"));
+		ehci_bus_error(gehci);
+	}
+	return -1;
+}
+
+static long ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, long length, struct devrequest *req)
+{
+	unsigned char tmpbuf[4];
+	unsigned short typeReq;
+	void *srcptr = NULL;
+	long len, srclen;
+	unsigned long reg;
+	unsigned long *status_reg;
+
+	struct ehci *gehci = ((struct ucdif*)dev->controller)->ucd_priv;
+
+	if(le2cpu16(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
+	{
+		ALERT(("The request port(%d) is not configured", le2cpu16(req->index) - 1));
+		DEBUG(("The request port(%d) is not configured", le2cpu16(req->index) - 1));
+		return -1;
+	}
+
+	status_reg = (unsigned long *)&gehci->hcor->or_portsc[le2cpu16(req->index) - 1];
+	srclen = 0;
+	DEBUG(("ehci_submit_root req=%u (0x%x), type=%u (0x%x), value=%u, index=%u",
+	 req->request, req->request, req->requesttype, req->requesttype, le2cpu16(req->value), le2cpu16(req->index)));
+	typeReq = req->request | req->requesttype << 8;
+	switch(typeReq)
+	{
+		case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+			switch(le2cpu16(req->value) >> 8)
+			{
+				case USB_DT_DEVICE:
+					DEBUG(("USB_DT_DEVICE request"));
+					srcptr = &gehci->descriptor->device;
+					srclen = 0x12;
+					break;
+				case USB_DT_CONFIG:
+					DEBUG(("USB_DT_CONFIG config"));
+					srcptr = &gehci->descriptor->config;
+					srclen = 0x19;
+					break;
+				case USB_DT_STRING:
+					DEBUG(("USB_DT_STRING config"));
+					switch(le2cpu16(req->value) & 0xff)
+					{
+						case 0:	/* Language */
+							srcptr = "\4\3\1\0";
+							srclen = 4;
+							break;
+						case 1:	/* Vendor */
+							srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
+							srclen = 14;
+							break;
+						case 2:	/* Product */
+							srcptr = "\52\3E\0H\0C\0I\0 \0H\0o\0s\0t\0 \0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
+							srclen = 42;
+							break;
+						default:
+							DEBUG(("unknown value DT_STRING %x",
+							le2cpu16(req->value)));
+							goto unknown;
+					}
+					break;
+				default:
+					DEBUG(("unknown value %x", le2cpu16(req->value)));
+					goto unknown;
+			}
+			break;
+		case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
+			switch(le2cpu16(req->value) >> 8)
+			{
+				case USB_DT_HUB:
+					DEBUG(("USB_DT_HUB config"));
+					srcptr = &gehci->descriptor->hub;
+					srclen = 0x8;
+					break;
+				default:
+					DEBUG(("unknown value %x", le2cpu16(req->value)));
+					goto unknown;
+			}
+			break;
+		case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
+			DEBUG(("USB_REQ_SET_ADDRESS"));
+			gehci->rootdev = le2cpu16(req->value);
+			break;
+		case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+			DEBUG(("USB_REQ_SET_CONFIGURATION"));
+			/* Nothing to do */
+			break;
+		case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
+			tmpbuf[0] = 1;	/* USB_STATUS_SELFPOWERED */
+			tmpbuf[1] = 0;
+			srcptr = tmpbuf;
+			srclen = 2;
+			break;
+		case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+			memset(tmpbuf, 0, 4);
+			reg = ehci_readl(status_reg);
+			if(reg & EHCI_PS_CS)
+				tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
+			if(reg & EHCI_PS_PE)
+				tmpbuf[0] |= USB_PORT_STAT_ENABLE;
+			if(reg & EHCI_PS_SUSP)
+				tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
+			if(reg & EHCI_PS_OCA)
+				tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
+			if (reg & EHCI_PS_PR)
+				tmpbuf[0] |= USB_PORT_STAT_RESET;
+			if(reg & EHCI_PS_PP)
+				tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
+			if(ehci_is_TDI())
+			{
+				switch((reg >> 26) & 3)
+				{
+					case 0: break;
+					case 1: tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8; break;
+					case 2:
+					default: tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; break;
+				}
+			}
+			else
+				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+			if(reg & EHCI_PS_CSC)
+				tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
+			if(reg & EHCI_PS_PEC)
+				tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
+			if(reg & EHCI_PS_OCC)
+				tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
+			if(gehci->portreset & (1 << le2cpu16(req->index)))
+				tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+			srcptr = tmpbuf;
+			srclen = 4;
+			break;
+		case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+			reg = ehci_readl(status_reg);
+			reg &= ~EHCI_PS_CLEAR;
+			switch(le2cpu16(req->value))
+			{
+				case USB_PORT_FEAT_ENABLE:
+					reg |= EHCI_PS_PE;
+					ehci_writel(status_reg, reg);
+					break;
+				case USB_PORT_FEAT_POWER:
+					if(HCS_PPC(ehci_readl(&gehci->hccr->cr_hcsparams)))
+					{
+						reg |= EHCI_PS_PP;
+						ehci_writel(status_reg, reg);
+					}
+					break;
+				case USB_PORT_FEAT_RESET:
+					if((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS && !ehci_is_TDI() && EHCI_PS_IS_LOWSPEED(reg))
+					{
+						/* Low speed device, give up ownership. */
+						DEBUG(("port %d low speed --> companion", le2cpu16(req->index)));
+						reg |= EHCI_PS_PO;
+						ehci_writel(status_reg, reg);
+						gehci->companion |= (1 << le2cpu16(req->index));
+						break;
+					}
+					else
+					{
+						int ret;
+
+						reg |= EHCI_PS_PR;
+						reg &= ~EHCI_PS_PE;
+						ehci_writel(status_reg, reg);
+						/*
+						 * caller must wait, then call GetPortStatus
+						 * usb 2.0 specification say 50 ms resets on root
+						 */
+						ehci_powerup_fixup(status_reg, &reg);
+						ehci_writel(status_reg, reg & ~EHCI_PS_PR);
+						/*
+						* A host controller must terminate the reset
+						* and stabilize the state of the port within
+						* 2 milliseconds
+						*/
+						ret = handshake(status_reg, EHCI_PS_PR, 0,
+								2 * 1000L);
+						if (!ret)
+							gehci->portreset |=
+								1 << le2cpu16(req->index);
+						else
+							ALERT(("port(%d) reset error\n",
+								le2cpu16(req->index) - 1));
+					}
+					break;
+				default:
+					DEBUG(("unknown feature %x", le2cpu16(req->value)));
+					goto unknown;
+			}
+			/* unblock posted writes */
+			(void)ehci_readl(&gehci->hcor->or_usbcmd);
+			break;
+		case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+			reg = ehci_readl(status_reg);
+			switch(le2cpu16(req->value))
+			{
+				case USB_PORT_FEAT_ENABLE:
+					reg &= ~EHCI_PS_PE;
+					break;
+				case USB_PORT_FEAT_C_ENABLE:
+					reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
+					break;
+				case USB_PORT_FEAT_POWER:
+					if(HCS_PPC(ehci_readl(&gehci->hccr->cr_hcsparams)))
+						reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
+				case USB_PORT_FEAT_C_CONNECTION:
+					reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
+					break;
+				case USB_PORT_FEAT_OVER_CURRENT:
+					reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
+					break;
+				case USB_PORT_FEAT_C_RESET:
+					gehci->portreset &= ~(1 << le2cpu16(req->index));
+					break;
+				default:
+					DEBUG(("unknown feature %x", le2cpu16(req->value)));
+					goto unknown;
+			}
+			ehci_writel(status_reg, reg);
+			/* unblock posted write */
+			(void)ehci_readl(&gehci->hcor->or_usbcmd);
+			break;
+		default:
+			DEBUG(("Unknown request"));
+			goto unknown;
+	}
+	mdelay(1);
+	len = MIN3(srclen, le2cpu16(req->length), length);
+	if(srcptr != NULL && len > 0)
+		memcpy(buffer, srcptr, len);
+	else
+		DEBUG(("Len is 0"));
+	dev->act_len = len;
+	dev->status = 0;
+	return 0;
+unknown:
+	DEBUG(("requesttype=%x, request=%x, value=%x, index=%x, length=%x",
+	 req->requesttype, req->request, le2cpu16(req->value), le2cpu16(req->index), le2cpu16(req->length)));
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+	return -1;
+}
+
+long ehci_interrupt_handle(struct ehci *ehci)
+{
+	unsigned long status;
+
+	/* flush caches */
+	cpush(ehci, -1);
+
+	status = ehci_readl(&ehci->hcor->or_usbsts);
+	if(status & STS_PCD) /* port change detect */
+	{
+		unsigned long reg = ehci_readl(&ehci->hccr->cr_hcsparams);
+		unsigned long i = HCS_N_PORTS(reg);
+		while(i--)
+		{
+			unsigned long pstatus = ehci_readl(&ehci->hcor->or_portsc[i-1]);
+			if(pstatus & EHCI_PS_PO)
+				continue;
+			if(ehci->companion & (1 << i))
+			{
+				/* Low speed device, give up ownership. */
+				pstatus |= EHCI_PS_PO;
+				ehci_writel(&ehci->hcor->or_portsc[i-1], pstatus);
+			}
+			else if((pstatus & EHCI_PS_CSC))
+				(*uinf->usb_rh_wakeup)();
+		}
+	} 
+	ehci_writel(&ehci->hcor->or_usbsts, status);
+	return 1; /* clear interrupt, 0: disable interrupt */
+}
+
+static void hc_free_buffers(struct ehci *ehci)
+{
+	long i;
+	if(ehci->descriptor != NULL)
+	{
+		kfree(ehci->descriptor);
+		ehci->descriptor = NULL;
+	}
+	for(i = 0; i < 3; i++)
+	{
+		if(ehci->td_unaligned[i] != NULL)
+		{
+			kfree(ehci->td_unaligned[i]);
+			ehci->td_unaligned[i] = NULL;
+		}
+	}
+	if(ehci->qh_unaligned != NULL)
+	{
+		kfree(ehci->qh_unaligned);
+		ehci->qh_unaligned = NULL;
+	}
+	if(ehci->qh_list_unaligned != NULL)
+	{
+		kfree(ehci->qh_list_unaligned);
+		ehci->qh_list_unaligned = NULL;
+	}
+}
+
+/*
+ * IOCTL functions
+ */
+
+long usb_lowlevel_init(void *ucd_priv)
+{
+	long i;
+	unsigned long reg;
+	unsigned long cmd;
+
+	struct ehci *gehci = (struct ehci*)ucd_priv;
+
+	if(ehci_bus_init(gehci)) 
+	{
+		hc_free_buffers(gehci);
+		return (-1);
+	};
+
+	gehci->qh_list_unaligned = (struct QH *)kmalloc(sizeof(struct QH) + 32);
+	if(gehci->qh_list_unaligned == NULL)
+	{
+		DEBUG(("QHs malloc failed"));
+		hc_free_buffers(gehci);
+		return(-1);
+	}
+	gehci->qh_list = (struct QH *)(((unsigned long)gehci->qh_list_unaligned + 31) & ~31);
+	memset(gehci->qh_list, 0, sizeof(struct QH));
+	gehci->qh_unaligned = (struct QH *)kmalloc(sizeof(struct QH) + 32);
+	if(gehci->qh_unaligned == NULL)
+	{
+		DEBUG(("QHs malloc failed"));
+		hc_free_buffers(gehci);
+		return(-1);
+	}
+	gehci->qh = (struct QH *)(((unsigned long)gehci->qh_unaligned + 31) & ~31);
+	memset(gehci->qh, 0, sizeof(struct QH));
+	for(i = 0; i < 3; i++)
+	{
+		gehci->td_unaligned[i] = (struct qTD *)kmalloc(sizeof(struct qTD) + 32);
+		if(gehci->td_unaligned[i] == NULL)
+		{
+			DEBUG(("TDs malloc failed"));
+			hc_free_buffers(gehci);
+			return(-1);
+		}
+		gehci->td[i] = (struct qTD *)(((unsigned long)gehci->td_unaligned[i] + 31) & ~31);
+		memset(gehci->td[i], 0, sizeof(struct qTD));	
+	}
+	gehci->descriptor = (struct descriptor *)kmalloc(sizeof(struct descriptor));
+	if(gehci->descriptor == NULL)
+	{
+		DEBUG(("decriptor malloc failed"));
+		hc_free_buffers(gehci);
+		return(-1);
+	}
+	memcpy(gehci->descriptor, &rom_descriptor, sizeof(struct descriptor));
+
+	gehci->hcor = (struct ehci_hcor *)((unsigned long)gehci->hccr + HC_LENGTH(ehci_readl(&gehci->hccr->cr_capbase)));
+
+	/* EHCI spec section 4.1 */
+	if(ehci_reset(gehci) != 0)
+	{
+		hc_free_buffers(gehci);
+		return(-1);
+	}
+	/* Set head of reclaim list */
+	gehci->qh_list->qh_link = cpu_to_hc32(((unsigned long)gehci->qh_list - gehci->dma_offset) | QH_LINK_TYPE_QH);
+	gehci->qh_list->qh_endpt1 = cpu_to_hc32((1UL << 15) | (USB_SPEED_HIGH << 12));
+	gehci->qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
+	gehci->qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+	gehci->qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+	gehci->qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40);
+
+	/* Set async. queue head pointer. */
+	ehci_writel(&gehci->hcor->or_asynclistaddr, (unsigned long)gehci->qh_list - gehci->dma_offset);
+	reg = ehci_readl(&gehci->hccr->cr_hcsparams);
+	gehci->descriptor->hub.bNbrPorts = HCS_N_PORTS(reg);
+	DEBUG(("Register %lx NbrPorts %d", reg, gehci->descriptor->hub.bNbrPorts));
+
+	/* Port Indicators */
+	if(HCS_INDICATOR(reg))
+		gehci->descriptor->hub.wHubCharacteristics |= 0x80;
+	/* Port Power Control */
+
+	if(HCS_PPC(reg))
+		gehci->descriptor->hub.wHubCharacteristics |= 0x01;
+	/* Start the host controller. */
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+
+	/*
+	 * Philips, Intel, and maybe others need CMD_RUN before the
+	 * root hub will detect new devices (why?); NEC doesn't
+	 */
+	cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+	cmd |= CMD_RUN;
+	ehci_writel(&gehci->hcor->or_usbcmd, cmd);
+
+	/* take control over the ports */
+	ehci_writel(&gehci->hcor->or_configflag, FLAG_CF);
+
+	/* unblock posted write */
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+	mdelay(5);
+	reg = HC_VERSION(ehci_readl(&gehci->hccr->cr_capbase));
+
+
+	/* turn on interrupts */
+	ehci_writel(&gehci->hcor->or_usbintr, INTR_PCDE);
+	gehci->rootdev = 0;
+	gehci->ehci_inited = 1;
+
+	return 0;
+}
+
+long usb_lowlevel_stop(void *ucd_priv)
+{
+	unsigned long cmd;
+
+	struct ehci *gehci = (struct ehci*)ucd_priv;
+
+	if(!gehci->ehci_inited)
+		return(0);
+	/* turn off interrupts */
+	ehci_writel(&gehci->hcor->or_usbintr, 0);
+
+	/* stop the controller */
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+	cmd &= ~CMD_RUN;
+	ehci_writel(&gehci->hcor->or_usbcmd, cmd);
+
+	/* turn off all ports => todo */
+	/* use the companions */
+	ehci_writel(&gehci->hcor->or_configflag, 0);
+
+	/* unblock posted write */
+	cmd = ehci_readl(&gehci->hcor->or_usbcmd);
+	ehci_reset(gehci);
+	hc_free_buffers(gehci);
+	gehci->ehci_inited = 0;
+
+	ehci_bus_stop(gehci);
+
+	return(0);
+}
+
+long submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, long length)
+{
+	if(usb_pipetype(pipe) != PIPE_BULK)
+	{
+		DEBUG(("non-bulk pipe (type=%lu)", usb_pipetype(pipe)));
+		return -1;
+	}
+	return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+long submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, long length, struct devrequest *setup)
+{
+	struct ehci *gehci = ((struct ucdif*)dev->controller)->ucd_priv;
+
+	if(usb_pipetype(pipe) != PIPE_CONTROL)
+	{
+		DEBUG(("non-control pipe (type=%lu)", usb_pipetype(pipe)));
+		return -1;
+	}
+	if(usb_pipedevice(pipe) == gehci->rootdev)
+	{
+		if(gehci->rootdev == 0)
+			dev->speed = USB_SPEED_HIGH;
+		return ehci_submit_root(dev, pipe, buffer, length, setup);
+	}
+	return ehci_submit_async(dev, pipe, buffer, length, setup);
+}
+
+long submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, long length, long interval)
+{
+	DEBUG(("submit_int_msg dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d", dev, pipe, buffer, length, interval));
+	return -1;
+}
+
+/*
+ * Inteface functions
+ */
+
+static long _cdecl
+ehci_open(struct ucdif *u)
+{
+	return E_OK;
+}
+
+static long _cdecl
+ehci_close(struct ucdif *u)
+{
+	return E_OK;
+}
+
+static long _cdecl
+ehci_ioctl(struct ucdif *u, short cmd, long arg)
+{
+	long ret = E_OK;
+
+	switch (cmd)
+	{
+		case FS_INFO:
+		{
+			*(long *)arg = (((long)VER_MAJOR << 16) | VER_MINOR);
+			break;
+		}
+		case LOWLEVEL_INIT :
+		{
+			ret = usb_lowlevel_init (u->ucd_priv);
+			break;
+		}
+		case LOWLEVEL_STOP :
+		{
+			ret = usb_lowlevel_stop (u->ucd_priv);
+			break;
+		}
+		case SUBMIT_CONTROL_MSG :
+		{
+			struct control_msg *ctrl_msg = (struct control_msg *)arg;
+
+			ret = submit_control_msg (ctrl_msg->dev, ctrl_msg->pipe,
+						  ctrl_msg->data, ctrl_msg->size,
+						  ctrl_msg->setup);
+			break;
+		}
+		case SUBMIT_BULK_MSG :
+		{
+			struct bulk_msg *bulk_msg = (struct bulk_msg *)arg;
+
+			ret = submit_bulk_msg (bulk_msg->dev, bulk_msg->pipe,
+					       bulk_msg->data, bulk_msg->len);
+
+			break;
+		}
+		case SUBMIT_INT_MSG :
+		{
+			struct int_msg *int_msg = (struct int_msg *)arg;
+
+			ret = submit_int_msg(int_msg->dev, int_msg->pipe,
+					     int_msg->buffer, int_msg->transfer_len,
+					     int_msg->interval);
+
+			break;
+		}
+		default:
+		{
+			return ENOSYS;
+		}
+	}
+	return ret;
+}
+
+/*
+ * Init functions
+ */
+
+char fail_kentry[] = "wrong kentry version";
+char fail_probe[] = "probe failed";
+
+long
+ehci_alloc_ucdif(struct ucdif **u)
+{
+	struct ucdif *ehci_uif;
+
+	if(!(*u = kmalloc(sizeof(struct ucdif))))
+		return -1;
+	ehci_uif = *u;
+
+	ehci_uif->next = 0;
+	ehci_uif->class = USB_CONTRLL;
+	ehci_uif->lname = lname;
+	ehci_uif->unit = 0;
+	ehci_uif->flags = 0;
+	ehci_uif->open = ehci_open;
+	ehci_uif->close = ehci_close;
+	ehci_uif->resrvd1 = 0;
+	ehci_uif->ioctl = ehci_ioctl;
+	ehci_uif->resrvd2 = 0;
+	if(!(ehci_uif->ucd_priv = kmalloc(sizeof(struct ehci))))
+		return -1;
+
+	return 0;
+}
+
+/* Entry function */
+
+long _cdecl
+init(struct kentry *k, struct ucdinfo *uinfo, char **reason)
+{
+	long ret;
+
+	kentry	= k;
+	uinf	= uinfo;
+
+	struct ucdif *ehci_uif = NULL;
+
+	if (check_kentry_version())
+	{
+		*reason = fail_kentry;
+		return -1;
+	}
+	ret = ehci_bus_probe(uinf, ehci_uif);
+	if (ret < 0) 
+	{
+		*reason = fail_probe;
+		return -1;
+	}
+
+	c_conws (MSG_BOOT);
+	c_conws (MSG_GREET);
+
+	return 0;
+}
Index: sys/usb/src.km/ucd/ehci/ehci-pci.c
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/ehci-pci.c
@@ -0,0 +1,252 @@
+/*
+ * Adapted for FreeMiNT by David Galvez 2014
+ * Ported for Atari by Didier Mequignon
+ *
+ * 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 version 2 of
+ * the License.
+ *
+ * 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
+ */
+
+#include "mint/pcibios.h"
+#include "mint/pci_ids.h"
+
+#include "libkern/libkern.h"
+
+#include "../ucd_defs.h"
+#include "ehci.h"
+
+/*
+ * Debug section
+ */
+
+#if 0
+# define DEV_DEBUG	1
+#endif
+
+#ifdef DEV_DEBUG
+
+# define FORCE(x)	KERNEL_FORCE x
+# define ALERT(x)	KERNEL_ALERT x
+# define DEBUG(x)	KERNEL_DEBUG x
+# define TRACE(x)	KERNEL_TRACE x
+# define ASSERT(x)	assert x
+
+#else
+
+# define FORCE(x)	KERNEL_FORCE x
+# define ALERT(x)	KERNEL_ALERT x
+# define DEBUG(x)
+# define TRACE(x)
+# define ASSERT(x)	assert x
+
+#endif
+
+/*
+ * Function prototypes
+ */
+long ehci_pci_init	(void *);
+void ehci_pci_stop	(struct ehci *);
+long ehci_pci_probe	(struct ucdinfo *uinf, struct ucdif *);
+long ehci_pci_reset	(struct ehci *);
+void ehci_pci_error	(struct ehci *);
+
+
+struct ehci_pci {
+	long handle;				/* PCI BIOS */
+	const struct pci_device_id *ent;
+};
+
+struct pci_device_id ehci_usb_pci_table[] = {
+	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB_2, 
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SERIAL_USB_EHCI, 0, 0 }, /* NEC PCI EHCI module ids */
+	{ PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_ISP1561_2, 
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SERIAL_USB_EHCI, 0, 0 }, /* Philips 1561 PCI EHCI module ids */
+	/* Please add supported PCI EHCI controller ids here */
+	{ 0, 0, 0, 0, 0, 0, 0 }
+};
+
+struct ehci_bus ehci_bus = {
+	.init = ehci_pci_init,
+	.stop = ehci_pci_stop,
+	.probe = ehci_pci_probe,
+	.reset = ehci_pci_reset,
+	.error = ehci_pci_error,
+};
+
+void
+ehci_pci_error(struct ehci *gehci)
+{
+	unsigned short status = Fast_read_config_word(((struct ehci_pci *)gehci->bus)->handle, PCISR);
+	ALERT(("EHCI Host System Error, controller usb-%s disabled\r\n(SR:0x%04x%s%s%s%s%s%s)", gehci->slot_name, status & 0xFFFF,
+	 status & 0x8000 ? ", Parity error" : "", status & 0x4000 ? ", Signaled system error" : "", status & 0x2000 ? ", Received master abort" : "",
+	 status & 0x1000 ? ", Received target abort" : "", status & 0x800 ? ", Signaled target abort" : "", status & 0x100 ? ", Data parity error" : ""));
+}
+
+long
+ehci_pci_reset(struct ehci *gehci)
+{
+	if (machine == machine_firebee) 
+	{
+		if((((struct ehci_pci *)gehci->bus)->ent->vendor == PCI_VENDOR_ID_NEC)
+		 && (((struct ehci_pci *)gehci->bus)->ent->device == PCI_DEVICE_ID_NEC_USB_2))
+		{
+			DEBUG(("ehci_reset set 48MHz clock"));
+			Write_config_longword(((struct ehci_pci *)gehci->bus)->handle, 0xE4, 0x20); // oscillator
+		}
+	}
+	return 0;
+}
+
+long
+ehci_pci_init(void *ucd_priv)
+{
+	unsigned long usb_base_addr = 0xFFFFFFFF;
+
+	PCI_RSC_DESC *pci_rsc_desc;
+
+	struct ehci *gehci = (struct ehci*)ucd_priv;
+	if(!((struct ehci_pci *)gehci->bus)->handle) /* for restart USB cmd */
+		return(-1);
+
+	pci_rsc_desc = (PCI_RSC_DESC *)Get_resource(((struct ehci_pci *)gehci->bus)->handle); /* USB OHCI */
+	if((long)pci_rsc_desc >= 0)
+	{
+		unsigned short flags;
+		do
+		{
+			DEBUG(("PCI USB descriptors: flags 0x%08x start 0x%08x \r\n offset 0x%08x dmaoffset 0x%08x length 0x%08x",
+			 pci_rsc_desc->flags, pci_rsc_desc->start, pci_rsc_desc->offset, pci_rsc_desc->dmaoffset, pci_rsc_desc->length));
+			if(!(pci_rsc_desc->flags & FLG_IO))
+			{
+				if(usb_base_addr == 0xFFFFFFFF)
+				{
+					usb_base_addr = pci_rsc_desc->start;
+					gehci->hccr = (struct ehci_hccr *)(pci_rsc_desc->offset + pci_rsc_desc->start);
+					gehci->dma_offset = pci_rsc_desc->dmaoffset;
+					if((pci_rsc_desc->flags & FLG_ENDMASK) == ORD_MOTOROLA)
+						gehci->big_endian = 0; /* hardware makes swapping intel -> motorola */
+					else
+						gehci->big_endian = 1; /* driver must swap intel -> motorola */
+				}
+			}
+			flags = pci_rsc_desc->flags;
+			pci_rsc_desc = (PCI_RSC_DESC *)((unsigned long)pci_rsc_desc->next + (unsigned long)pci_rsc_desc);
+		}
+		while(!(flags & FLG_LAST));
+	}
+	else
+	{
+		return(-1); /* get_resource error */
+	}
+	if(usb_base_addr == 0xFFFFFFFF)
+	{
+		return(-1);
+	}
+	if(((struct ehci_pci *)gehci->bus)->handle && ((((struct ehci_pci *)gehci->bus)->ent) != NULL))
+	{
+		switch(((struct ehci_pci *)gehci->bus)->ent->vendor)
+		{
+			case PCI_VENDOR_ID_NEC: gehci->slot_name = "uPD720101"; break;
+			case PCI_VENDOR_ID_PHILIPS: gehci->slot_name = "isp1561"; break;
+			default: gehci->slot_name = "generic"; break;
+		}
+	}
+
+	/* hook interrupt handler */
+	Hook_interrupt(((struct ehci_pci *)gehci->bus)->handle, (void *)ehci_interrupt_handle, (unsigned long *)gehci);
+
+	return 0;
+}
+
+void ehci_pci_stop(struct ehci *gehci)
+{
+	Unhook_interrupt(((struct ehci_pci *)gehci->bus)->handle);
+}
+
+long
+ehci_pci_probe(struct ucdinfo	*uinf, struct ucdif *ehci_uif)
+{
+	short index;
+	long err;
+	int loop_counter = 0;
+
+	long handle;
+	struct pci_device_id *board;
+
+	if(pcibios_installed == 0)
+	{
+		ALERT(("PCI-BIOS not found. You need a PCI-BIOS to use this driver"));
+		return -1;
+	}
+
+	/* PCI devices detection */
+	index = 0;
+	do
+	{
+		do
+		{
+			handle = Find_pci_device(0x0000FFFFL, index++);
+			if(handle >= 0)
+			{
+				unsigned long id = 0;
+				err = Read_config_longword(handle, PCIIDR, &id);
+				/* test USB devices */
+				if((err >= 0))
+				{
+					unsigned long class;
+					if(Read_config_longword(handle, PCIREV, &class) >= 0
+					   && ((class >> 16) == PCI_CLASS_SERIAL_USB))
+					{
+						if((class >> 8) == PCI_CLASS_SERIAL_USB_EHCI)
+						{
+							board = ehci_usb_pci_table; /* compare table */
+							while(board->vendor)
+							{
+								if((board->vendor == (id & 0xFFFF))
+								    && (board->device == (id >> 16)))
+								{
+									err = ehci_alloc_ucdif(&ehci_uif);
+									strcpy(ehci_uif->name, "ehci-pci");
+									if (err < 0)
+										break;
+									/* assign an interface */
+									err = (*uinf->ucd_register)(ehci_uif);
+									if (err) 
+									{
+										DEBUG (("%s: ucd register failed!", __FILE__));
+										break;
+									}
+									struct ehci *gehci = ehci_uif->ucd_priv;
+									gehci->bus = kmalloc (sizeof(struct ehci_pci));
+									((struct ehci_pci *)gehci->bus)->handle = handle;
+									((struct ehci_pci *)gehci->bus)->ent = board;
+									DEBUG (("%s: ucd register ok", __FILE__));
+									break;
+								}
+								board++;
+							}
+						}
+					}
+				}
+			}
+		}
+		while(handle >= 0);
+		loop_counter++;
+	}
+	while(loop_counter <= 2); /* Number of card slots */
+
+	return 0;
+}
Index: sys/usb/src.km/ucd/ehci/ehci.h
--- /dev/null
+++ sys/usb/src.km/ucd/ehci/ehci.h
@@ -0,0 +1,251 @@
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ * 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 version 2 of
+ * the License.
+ *
+ * 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
+ */
+
+#ifndef USB_EHCI_H
+#define USB_EHCI_H
+
+#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS	5
+#endif
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+	((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
+
+#define DeviceOutRequest \
+	((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
+
+#define InterfaceRequest \
+	((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+#define EndpointRequest \
+	((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+#define EndpointOutRequest \
+	((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+/*
+ * Register Space.
+ */
+struct ehci_hccr {
+	unsigned long cr_capbase;
+#define HC_LENGTH(p)		(((p) >> 0) & 0x00ff)
+#define HC_VERSION(p)		(((p) >> 16) & 0xffff)
+	unsigned long cr_hcsparams;
+#define HCS_PPC(p)		((p) & (1 << 4))
+#define HCS_INDICATOR(p)	((p) & (1UL << 16)) /* Port indicators */
+#define HCS_N_PORTS(p)		(((p) >> 0) & 0xf)
+	unsigned long cr_hccparams;
+	unsigned char cr_hcsp_portrt[8];
+} __attribute__ ((packed));
+
+struct ehci_hcor {
+	unsigned long or_usbcmd;
+#define CMD_PARK	(1UL << 11)		/* enable "park" */
+#define CMD_PARK_CNT(c)	(((c) >> 8) & 3UL)	/* how many transfers to park */
+#define CMD_ASE		(1UL << 5)		/* async schedule enable */
+#define CMD_LRESET	(1UL << 7)		/* partial reset */
+#define CMD_IAAD	(1UL << 5)		/* "doorbell" interrupt */
+#define CMD_PSE		(1UL << 4)		/* periodic schedule enable */
+#define CMD_RESET	(1UL << 1)		/* reset HC not bus */
+#define CMD_RUN		(1UL << 0)		/* start/stop HC */
+	unsigned long or_usbsts;
+#define STD_ASS		(1UL << 15)
+#define STS_PSSTAT	(1UL << 14)
+#define STS_RECL	(1UL << 13)
+#define STS_HALT	(1UL << 12)
+#define STS_IAA		(1UL << 5)
+#define STS_HSE		(1UL << 4)
+#define STS_FLR		(1UL << 3)
+#define STS_PCD		(1UL << 2)
+#define STS_USBERRINT	(1UL << 1)
+#define STS_USBINT	(1UL << 0)
+	unsigned long or_usbintr;
+#define INTR_IAAE	(1UL << 5)
+#define INTR_HSEE	(1UL << 4)
+#define INTR_FLRE	(1UL << 3)
+#define INTR_PCDE	(1UL << 2)
+#define INTR_USBERRINTE	(1UL << 1)
+#define INTR_USBINTE	(1UL << 0)
+	unsigned long or_frindex;
+	unsigned long or_ctrldssegment;
+	unsigned long or_periodiclistbase;
+	unsigned long or_asynclistaddr;
+	unsigned long _reserved_[9];
+	unsigned long or_configflag;
+#define FLAG_CF		(1UL << 0)	/* true:  we'll support "high speed" */
+	unsigned long or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
+	unsigned long or_systune;
+} __attribute__ ((packed));
+
+#define USBMODE		0x68		/* USB Device mode */
+#define USBMODE_SDIS	(1 << 3)	/* Stream disable */
+#define USBMODE_BE	(1 << 2)	/* BE/LE endiannes select */
+#define USBMODE_CM_HC	(3 << 0)	/* host controller mode */
+#define USBMODE_CM_IDLE	(0 << 0)	/* idle state */
+
+/* Interface descriptor */
+struct usb_linux_interface_descriptor {
+	unsigned char	bLength;
+	unsigned char	bDescriptorType;
+	unsigned char	bInterfaceNumber;
+	unsigned char	bAlternateSetting;
+	unsigned char	bNumEndpoints;
+	unsigned char	bInterfaceClass;
+	unsigned char	bInterfaceSubClass;
+	unsigned char	bInterfaceProtocol;
+	unsigned char	iInterface;
+} __attribute__ ((packed));
+
+/* Configuration descriptor information.. */
+struct usb_linux_config_descriptor {
+	unsigned char	bLength;
+	unsigned char	bDescriptorType;
+	unsigned short	wTotalLength;
+	unsigned char	bNumInterfaces;
+	unsigned char	bConfigurationValue;
+	unsigned char	iConfiguration;
+	unsigned char	bmAttributes;
+	unsigned char	MaxPower;
+} __attribute__ ((packed));
+
+#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
+#define	ehci_readl(x)		(*((volatile unsigned long *)(x)))
+#define ehci_writel(a, b)	(*((volatile unsigned long *)(a)) = ((volatile unsigned long)b))
+#else
+#define ehci_readl(x)		le2cpu32((*((volatile unsigned long *)(x))))
+#define ehci_writel(a, b)	(*((volatile unsigned long *)(a)) = cpu2le32(((volatile unsigned long)b)))
+#endif
+
+#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
+#define hc32_to_cpu(x)		be2cpu32((x))
+#define cpu_to_hc32(x)		cpu2be32((x))
+#else
+#define hc32_to_cpu(x)		le2cpu32((x))
+#define cpu_to_hc32(x)		cpu2le32((x))
+#endif
+
+#define EHCI_PS_WKOC_E		(1UL << 22)	/* RW wake on over current */
+#define EHCI_PS_WKDSCNNT_E	(1UL << 21)	/* RW wake on disconnect */
+#define EHCI_PS_WKCNNT_E	(1UL << 20)	/* RW wake on connect */
+#define EHCI_PS_PO		(1UL << 13)	/* RW port owner */
+#define EHCI_PS_PP		(1UL << 12)	/* RW,RO port power */
+#define EHCI_PS_LS		(3UL << 10)	/* RO line status */
+#define EHCI_PS_PR		(1UL << 8)	/* RW port reset */
+#define EHCI_PS_SUSP		(1UL << 7)	/* RW suspend */
+#define EHCI_PS_FPR		(1UL << 6)	/* RW force port resume */
+#define EHCI_PS_OCC		(1UL << 5)	/* RWC over current change */
+#define EHCI_PS_OCA		(1UL << 4)	/* RO over current active */
+#define EHCI_PS_PEC		(1UL << 3)	/* RWC port enable change */
+#define EHCI_PS_PE		(1UL << 2)	/* RW port enable */
+#define EHCI_PS_CSC		(1UL << 1)	/* RWC connect status change */
+#define EHCI_PS_CS		(1UL << 0)	/* RO connect status */
+#define EHCI_PS_CLEAR		(EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
+
+#define EHCI_PS_IS_LOWSPEED(x)	(((x) & EHCI_PS_LS) == (1 << 10))
+
+/*
+ * Schedule Interface Space.
+ *
+ * IMPORTANT: Software must ensure that no interface data structure
+ * reachable by the EHCI host controller spans a 4K page boundary!
+ *
+ * Periodic transfers (i.e. isochronous and interrupt transfers) are
+ * not supported.
+ */
+
+/* Queue Element Transfer Descriptor (qTD). */
+struct qTD {
+	/* this part defined by EHCI spec */
+	unsigned long qt_next;		/* see EHCI 3.5.1 */
+#define	QT_NEXT_TERMINATE	1
+	unsigned long qt_altnext;		/* see EHCI 3.5.2 */
+	unsigned long qt_token;		/* see EHCI 3.5.3 */
+	unsigned long qt_buffer[5];		/* see EHCI 3.5.4 */
+	/* pad struct for 32 byte alignment */
+};
+
+/* Queue Head (QH). */
+struct QH {
+	unsigned long qh_link;
+#define	QH_LINK_TERMINATE	1
+#define	QH_LINK_TYPE_ITD	0
+#define	QH_LINK_TYPE_QH		2
+#define	QH_LINK_TYPE_SITD	4
+#define	QH_LINK_TYPE_FSTN	6
+	unsigned long qh_endpt1;
+	unsigned long qh_endpt2;
+	unsigned long qh_curtd;
+	struct qTD qh_overlay;
+	/*
+	 * Add dummy fill value to make the size of this struct
+	 * aligned to 32 bytes
+	 */
+	unsigned char fill[16];
+};
+
+struct ehci {
+	void *bus;				/* Inteface with bus/platform. (ex: pci) */
+	long big_endian;
+	struct ehci_hccr *hccr;		/* R/O registers, not need for volatile */
+	volatile struct ehci_hcor *hcor;
+	struct QH *qh_list_unaligned;
+	struct QH *qh_list;
+	struct QH *qh_unaligned;
+	struct QH *qh;
+	struct qTD *td_unaligned[3];
+	struct qTD *td[3];
+	struct descriptor *descriptor;
+	long irq;
+	unsigned long dma_offset;
+	const char *slot_name;
+	char ehci_inited;
+	long rootdev;
+	unsigned short portreset;
+	unsigned short companion;
+};
+
+/* Functions prototypes */
+
+long ehci_hcd_init(void);
+long ehci_hcd_stop(void);
+long ehci_alloc_ucdif(struct ucdif **);
+long ehci_interrupt_handle(struct ehci *ehci);
+
+/* Interface with bus/platform */
+
+struct ehci_bus {
+	long (*init)(void *);
+	void (*stop)(struct ehci *);
+	long (*probe)(struct ucdinfo *uinf, struct ucdif *);
+	long (*reset)(struct ehci *);
+	void (*error)(struct ehci *);
+};
+
+#define ehci_bus_init	ehci_bus.init
+#define ehci_bus_stop	ehci_bus.stop
+#define ehci_bus_probe	ehci_bus.probe
+#define ehci_bus_reset	ehci_bus.reset
+#define ehci_bus_error	ehci_bus.error
+
+extern struct ehci_bus ehci_bus;
+
+#endif /* USB_EHCI_H */