[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, ®);
+ 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 */