[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[MiNT] [PATCH] NetUSBee usb driver
Please Alan commit this patch to add the NetUSBee driver for USB.
Thanks!
Index: sys/usb/src.km/ucd/Makefile
===================================================================
RCS file: /mint/freemint/sys/usb/src.km/ucd/Makefile,v
retrieving revision 1.1
diff -u -8 -p -r1.1 Makefile
--- sys/usb/src.km/ucd/Makefile 29 Apr 2011 11:39:28 -0000 1.1
+++ sys/usb/src.km/ucd/Makefile 22 May 2011 09:12:42 -0000
@@ -1,14 +1,14 @@
#
# Makefile for
#
SHELL = /bin/sh
-SUBDIRS = ethernat
+SUBDIRS = ethernat netusbee
srcdir = .
top_srcdir = ../../..
subdir = ucd
default: all
include $(top_srcdir)/CONFIGVARS
Index: sys/usb/src.km/ucd/netusbee/BINFILES
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/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 = netusbee.ucd
Index: sys/usb/src.km/ucd/netusbee/COPYING
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/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/netusbee/EXTRAFILES
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/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/netusbee/MISCFILES
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/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/netusbee/Makefile
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/Makefile
@@ -0,0 +1,41 @@
+#
+# Makefile for moose
+#
+
+SHELL = /bin/sh
+SUBDIRS =
+
+srcdir = .
+top_srcdir = ../../../..
+subdir = netusbee
+
+default: all
+
+include $(top_srcdir)/CONFIGVARS
+include $(top_srcdir)/RULES
+include $(top_srcdir)/PHONY
+
+all-here: entry
+
+# default overwrites
+INCLUDES = -I$(top_srcdir)
+DEFINITIONS = -D__KERNEL_MODULE__ -DMODULE_NAME=netusbee $(XDD_DEFINITIONS) -DUSB_SUPPORT
+XDD_DEFINITIONS =
+
+LD = $(CC) -nostdlib -Wl,--entry -Wl,_init
+LIBS = $(LIBKERN) -lgcc
+CPU = 030
+
+# default definitions
+SGENFILES = netusbee.ucd
+OBJS = $(SSOBJS:.s=.o)
+
+
+entry:
+ $(MAKE) netusbee.ucd
+
+netusbee.ucd: isp116x-hcd.o $(OBJS) $(LIBKERNTARGET)
+ $(LD) $(CFLAGS) -o $@ $< $(OBJS) $(LIBS)
+
+
+include $(top_srcdir)/DEPENDENCIES
Index: sys/usb/src.km/ucd/netusbee/README
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/README
@@ -0,0 +1 @@
+
Index: sys/usb/src.km/ucd/netusbee/SRCFILES
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/SRCFILES
@@ -0,0 +1,14 @@
+# This file gets included by the Makefile in this directory to determine
+# the files that should go only into source distributions.
+
+HEADER = \
+ isp116x.h \
+ netusbee_int.h
+
+COBJS = \
+ isp116x-hcd.c
+
+SSOBJS = \
+ netusbee_int.S
+
+SRCFILES = $(HEADER) $(COBJS) $(SSOBJS)
Index: sys/usb/src.km/ucd/netusbee/isp116x-hcd.c
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/isp116x-hcd.c
@@ -0,0 +1,1985 @@
+/*
+ * Modified for Atari-NetUSBee by David Gálvez. 2010 - 2011
+ *
+ * ISP116x HCD (Host Controller Driver) for u-boot.
+ *
+ * Copyright (C) 2006-2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2006-2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This file 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 file 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
+ *
+ *
+ * Derived in part from the SL811 HCD driver "u-boot/drivers/usb/sl811_usb.c"
+ * (original copyright message follows):
+ *
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This code is based on linux driver for sl811hs chip, source at
+ * drivers/usb/host/sl811.c:
+ *
+ * SL811 Host Controller Interface driver for USB.
+ *
+ * Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ * Based on:
+ * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ * Adam Richter, Gregory P. Smith;
+ * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ *
+ * [[GNU/GPL disclaimer]]
+ *
+ * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c"
+ * (original copyright message follows):
+ *
+ * URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * [[GNU/GPL disclaimer]]
+ *
+ * Note: Part of this code has been derived from linux
+ */
+
+#include <stddef.h>
+#include <mint/osbind.h> /* Setexc */
+
+#include "mint/mint.h"
+#include "libkern/libkern.h"
+#include "mint/dcntl.h"
+
+#include "../../config.h"
+#include "../../endian/io.h"
+#include "../../usb.h"
+#include "../ucd_defs.h"
+#include "netusbee_int.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 NetUSBee USB controller driver " MSG_VERSION " \033q\r\n"
+
+#define MSG_GREET \
+ "Ported, mixed and shaken 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"
+
+/*
+ * ISP116x chips require certain delays between accesses to its
+ * registers. The following timing options exist.
+ *
+ * 1. Configure your memory controller (the best)
+ * 2. Use ndelay (easiest, poorest). For that, enable the following macro.
+ *
+ * Value is in microseconds.
+ */
+#undef ISP116X_HCD_USE_UDELAY
+#ifdef ISP116X_HCD_USE_UDELAY
+# define UDELAY 1
+#endif
+
+/*
+ * On some (slowly?) machines an extra delay after data packing into
+ * controller's FIFOs is required, * otherwise you may get the following
+ * error:
+ *
+ * uboot> usb start
+ * (Re)start USB...
+ * USB: scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT
+ * isp116x: isp116x_submit_job: ****** FIFO not ready! ******
+ *
+ * USB device not responding, giving up (status=4)
+ * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ * 3 USB Device(s) found
+ * scanning bus for storage devices... 0 Storage Device(s) found
+ *
+ * Value is in milliseconds.
+ */
+#define ISP116X_HCD_USE_EXTRA_DELAY
+#ifdef ISP116X_HCD_USE_EXTRA_DELAY
+# define EXTRA_DELAY 10 /* DEFAULT 2 */
+#endif
+
+/*
+ * Debug section
+ */
+
+#if 0
+# define DEV_DEBUG 1
+#endif
+
+#ifdef DEV_DEBUG
+
+# define 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)
+# define ALERT(x) KERNEL_ALERT x
+# define DEBUG(x)
+# define TRACE(x)
+# define ASSERT(x) assert x
+
+#endif
+
+/*
+ * Enable the following defines if you wish enable extra debugging messages.
+ */
+#ifdef DEV_DEBUG
+# define TRACE_EXTRA /* enable tracing code */
+# define VERBOSE /* verbose debugging messages */
+#endif
+
+#include "isp116x.h"
+
+#define DRIVER_VERSION "02 Feb 2011"
+static const char hcd_name[] = "isp116x-hcd";
+
+/****************************************************************************/
+/* BEGIN kernel interface */
+
+struct kentry *kentry;
+struct ucdinfo *uinf;
+
+/* END kernel interface */
+/****************************************************************************/
+
+
+struct isp116x isp116x_dev;
+struct isp116x_platform_data isp116x_board;
+static long got_rhsc; /* root hub status change */
+struct usb_device *devgone; /* device which was disconnected */
+static long rh_devnum; /* address of Root Hub endpoint */
+
+/*
+ * interrupt handling - bottom half
+ */
+void _cdecl netusbee_int (void);
+/*
+ * interrupt handling - top half
+ */
+static void int_handle_tophalf (PROC *p, long arg);
+
+/*
+ *Function prototypes
+ */
+long isp116x_check_id (struct isp116x *);
+static long isp116x_reset (struct isp116x *);
+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 **);
+
+/*
+ * USB controller interface
+ */
+
+static long _cdecl netusbee_open (struct ucdif *);
+static long _cdecl netusbee_close (struct ucdif *);
+static long _cdecl netusbee_ioctl (struct ucdif *, short, long);
+
+static char lname[] = "NetUSBee USB controller driver for FreeMiNT\0";
+
+static struct ucdif netusbee_uif =
+{
+ 0, /* *next */
+ USB_CONTRLL, /* class */
+ lname, /* lname */
+ "netusbee", /* name */
+ 0, /* unit */
+ 0, /* flags */
+ netusbee_open, /* open */
+ netusbee_close, /* close */
+ 0, /* resrvd1 */
+ netusbee_ioctl, /* ioctl */
+ 0, /* resrvd2 */
+// submit_bulk_msg,
+// submit_control_msg,
+// submit_int_msg,
+// { NULL },
+};
+
+/* ------------------------------------------------------------------------- */
+
+#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
+#define min1_t(type,x,y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+
+/* Galvez: added to avoid shadow warnings */
+#define min2_t(type,x,y) \
+ ({ type __a = (x); type __b = (y); __a < __b ? __a : __b; })
+
+/* ------------------------------------------------------------------------- */
+
+
+/* --- Debugging functions ------------------------------------------------- */
+
+#define isp116x_show_reg(d, r) { \
+ if ((r) < 0x20) \
+ { \
+ DEBUG(("%12s[%02x]: %08lx", #r, \
+ r, isp116x_read_reg32(d, r))); \
+ } \
+ else \
+ { \
+ DEBUG(("%12s[%02x]: %04x", #r, \
+ r, isp116x_read_reg16(d, r))); \
+ } \
+}
+
+#define isp116x_show_regs(d) { \
+ isp116x_show_reg(d, HCREVISION); \
+ isp116x_show_reg(d, HCCONTROL); \
+ isp116x_show_reg(d, HCCMDSTAT); \
+ isp116x_show_reg(d, HCINTSTAT); \
+ isp116x_show_reg(d, HCINTENB); \
+ isp116x_show_reg(d, HCFMINTVL); \
+ isp116x_show_reg(d, HCFMREM); \
+ isp116x_show_reg(d, HCFMNUM); \
+ isp116x_show_reg(d, HCLSTHRESH); \
+ isp116x_show_reg(d, HCRHDESCA); \
+ isp116x_show_reg(d, HCRHDESCB); \
+ isp116x_show_reg(d, HCRHSTATUS); \
+ isp116x_show_reg(d, HCRHPORT1); \
+ isp116x_show_reg(d, HCRHPORT2); \
+ isp116x_show_reg(d, HCHWCFG); \
+ isp116x_show_reg(d, HCDMACFG); \
+ isp116x_show_reg(d, HCXFERCTR); \
+ isp116x_show_reg(d, HCuPINT); \
+ isp116x_show_reg(d, HCuPINTENB); \
+ isp116x_show_reg(d, HCCHIPID); \
+ isp116x_show_reg(d, HCSCRATCH); \
+ isp116x_show_reg(d, HCITLBUFLEN); \
+ isp116x_show_reg(d, HCATLBUFLEN); \
+ isp116x_show_reg(d, HCBUFSTAT); \
+ isp116x_show_reg(d, HCRDITL0LEN); \
+ isp116x_show_reg(d, HCRDITL1LEN); \
+}
+
+
+#if defined(TRACE_EXTRA)
+#if 0
+static long
+isp116x_get_current_frame_number(struct usb_device *usb_dev)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+
+ return isp116x_read_reg32(isp116x, HCFMNUM);
+}
+#endif
+
+static void
+dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ long len, char *str)
+{
+#if defined(VERBOSE)
+ long i;
+ char build_str[64];
+ char buf[(len * 4) + 24 + 6];
+#endif
+ DEBUG(("%s URB:[%4lx] dev:%2ld,ep:%2ld-%c,type:%s,len:%ld stat:0x%lx",
+ str, isp116x_get_current_frame_number(dev),
+ usb_pipedevice(pipe), usb_pipeendpoint(pipe),
+ usb_pipeout(pipe) ? 'O' : 'I',
+ usb_pipetype(pipe) < 2 ?
+ (usb_pipeint(pipe) ? "INTR" : "ISOC") :
+ (usb_pipecontrol(pipe) ? "CTRL" : "BULK"),
+ len, dev->status));
+
+#if defined(VERBOSE)
+ sprintf(buf, sizeof(buf),"\0");
+ if (len > 0 && buffer)
+ {
+ sprintf(build_str, sizeof(build_str), __FILE__ ": data(%ld):", len);
+ strcat(buf, build_str);
+ for (i = 0; i < 16 && i < len; i++)
+ {
+ sprintf(build_str, sizeof(build_str), " %02x", ((unsigned char *) buffer)[i]);
+ strcat(buf, build_str);
+ }
+ sprintf(build_str, sizeof(build_str), "%s\r\n", i < len ? "..." : "");
+ strcat(buf, build_str);
+ DEBUG((buf));
+ }
+#endif
+}
+
+# define PTD_DIR_STR(ptd) ({char __c; \
+ switch(PTD_GET_DIR(ptd)){ \
+ case 0: __c = 's'; break; \
+ case 1: __c = 'o'; break; \
+ default: __c = 'i'; break; \
+ }; __c;})
+
+/*
+ Dump PTD info. The code documents the format
+ perfectly, right :)
+*/
+static inline void
+dump_ptd(struct ptd *ptd)
+{
+#if defined(VERBOSE)
+ long k;
+ char build_str[64];
+ char buf[64 + 4 * sizeof(struct ptd)];
+#endif
+
+ DEBUG(("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x",
+ PTD_GET_CC(ptd),
+ PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+ PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+ PTD_GET_TOGGLE(ptd),
+ PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd)));
+#if defined(VERBOSE)
+ sprintf(buf, sizeof(buf),"\0");
+ sprintf(build_str, sizeof(build_str), "isp116x: %s: PTD(byte): ", __FUNCTION__);
+ strcat(buf, build_str);
+ for (k = 0; k < sizeof(struct ptd); ++k) /* Galvez: note that bytes in the words are shown swapped */
+ {
+ sprintf(build_str, sizeof(build_str),"%02x ", ((unsigned char *) ptd)[k]);
+ strcat(buf, build_str);
+ }
+ DEBUG((buf));
+#endif
+}
+
+static inline void
+dump_ptd_data(struct ptd *ptd, unsigned char * buffer, long type)
+{
+#if defined(VERBOSE)
+ long k;
+ char build_str[64];
+ char buf[64 + 4 * PTD_GET_LEN(ptd)];
+
+ sprintf(buf, sizeof(buf),"\0");
+ if (type == 0 /* 0ut data */ )
+ {
+ sprintf(build_str, sizeof(build_str), "isp116x: %s: out data: ", __FUNCTION__);
+ strcat(buf, build_str);
+ for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+ {
+ sprintf(build_str, sizeof(build_str), "%02x ", ((unsigned char *) buffer)[k]);
+ strcat(buf, build_str);
+ }
+ DEBUG((buf));
+ }
+ if (type == 1 /* 1n data */ )
+ {
+ sprintf(build_str, sizeof(build_str), "isp116x: %s: in data: ", __FUNCTION__);
+ strcat(buf, build_str);
+ for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+ {
+ sprintf(build_str, sizeof(build_str), "%02x ", ((unsigned char *) buffer)[k]);
+ strcat(buf, build_str);
+ }
+ DEBUG((buf));
+ }
+
+
+ if (PTD_GET_LAST(ptd))
+ {
+ DEBUG(("--- last PTD ---"));
+ }
+#endif
+}
+
+#else
+
+# define dump_msg(dev, pipe, buffer, len, str) do { } while (0)
+# define dump_pkt(dev, pipe, buffer, len, setup, str, small) do {} while (0)
+
+# define dump_ptd(ptd) do {} while (0)
+# define dump_ptd_data(ptd, buf, type) do {} while (0)
+
+#endif /* TRACE_EXTRA */
+
+/* --- Virtual Root Hub ---------------------------------------------------- */
+
+/* Device descriptor */
+static unsigned char root_hub_dev_des[] =
+{
+ 0x12, /* unsigned char bLength; */
+ 0x01, /* unsigned char bDescriptorType; Device */
+ 0x10, /* unsigned short bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* unsigned char bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* unsigned char bDeviceSubClass; */
+ 0x00, /* unsigned char bDeviceProtocol; */
+ 0x08, /* unsigned char bMaxPacketSize0; 8 Bytes */
+ 0x00, /* unsigned short idVendor; */
+ 0x00,
+ 0x00, /* unsigned short idProduct; */
+ 0x00,
+ 0x00, /* unsigned short bcdDevice; */
+ 0x00,
+ 0x00, /* unsigned char iManufacturer; */
+ 0x01, /* unsigned char iProduct; */
+ 0x00, /* unsigned char iSerialNumber; */
+ 0x01 /* unsigned char bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static unsigned char root_hub_config_des[] =
+{
+ 0x09, /* unsigned char bLength; */
+ 0x02, /* unsigned char bDescriptorType; Configuration */
+ 0x19, /* unsigned short wTotalLength; */
+ 0x00,
+ 0x01, /* unsigned char bNumInterfaces; */
+ 0x01, /* unsigned char bConfigurationValue; */
+ 0x00, /* unsigned char iConfiguration; */
+ 0x40, /* unsigned char bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* unsigned char MaxPower; */
+
+ /* interface */
+ 0x09, /* unsigned char if_bLength; */
+ 0x04, /* unsigned char if_bDescriptorType; Interface */
+ 0x00, /* unsigned char if_bInterfaceNumber; */
+ 0x00, /* unsigned char if_bAlternateSetting; */
+ 0x01, /* unsigned char if_bNumEndpoints; */
+ 0x09, /* unsigned char if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* unsigned char if_bInterfaceSubClass; */
+ 0x00, /* unsigned char if_bInterfaceProtocol; */
+ 0x00, /* unsigned char if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* unsigned char ep_bLength; */
+ 0x05, /* unsigned char ep_bDescriptorType; Endpoint */
+ 0x81, /* unsigned char ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* unsigned char ep_bmAttributes; Interrupt */
+ 0x00, /* unsigned short ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x02,
+ 0xff /* unsigned char ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* unsigned char bLength; */
+ 0x03, /* unsigned char bDescriptorType; String-descriptor */
+ 0x09, /* unsigned char lang ID */
+ 0x04, /* unsigned char lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 0x22, /* unsigned char bLength; */
+ 0x03, /* unsigned char bDescriptorType; String-descriptor */
+ 'I', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'S', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'P', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ '1', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ '1', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ '6', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'x', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ ' ', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'R', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'o', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'o', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 't', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ ' ', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'H', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'u', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+ 'b', /* unsigned char Unicode */
+ 0, /* unsigned char Unicode */
+};
+
+/*
+ * Hub class-specific descriptor is constructed dynamically
+ */
+
+/* --- Virtual root hub management functions ------------------------------- */
+
+static long
+rh_check_port_status(struct isp116x *isp116x)
+{
+ unsigned long temp, ndp, i;
+ long res;
+
+ res = -1;
+ temp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+ ndp = (temp & RH_A_NDP);
+ for (i = 0; i < ndp; i++)
+ {
+ temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0))
+ {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+/* --- HC management functions --------------------------------------------- */
+
+/* Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void
+write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, long len)
+{
+ unsigned char *dp = (unsigned char *) buf;
+ unsigned short *dp2 = (unsigned short *) buf;
+ unsigned short w;
+ long quot = len % 4;
+
+/* For NetUSBee, take the raw_write out in write functions, here we don't
+ * like that NetUSBee swap the bytes for us, so we swap them before we send
+ * them, then the bytes will arrive to the USB device with the correct positions
+ */
+ if ((unsigned long)dp2 & 1)
+ {
+ /* not aligned */
+ for (; len > 1; len -= 2)
+ {
+ w = *dp++;
+ w |= *dp++ << 8;
+ isp116x_write_data16(isp116x, w);
+ }
+ if (len)
+ isp116x_write_data16(isp116x, (unsigned short) * dp);
+ }
+ else
+ {
+ /* aligned */
+ for (; len > 1; len -= 2)
+ isp116x_write_data16(isp116x, *dp2++);
+ if (len)
+ {
+ isp116x_raw_write_data16(isp116x, 0xff & *((unsigned char *) dp2));
+ }
+ }
+ if (quot == 1 || quot == 2)
+ isp116x_write_data16(isp116x, 0);
+}
+
+/* Read len bytes from fifo and then read till 32-bit boundary
+ */
+static void
+read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, long len)
+{
+ unsigned char *dp = (unsigned char *) buf;
+ unsigned short *dp2 = (unsigned short *) buf;
+ unsigned short w;
+ long quot = len % 4;
+
+/* For NetUSBee, take the raw_read out from read functions, we want to swap the bytes to
+ * read correct values because NetUSBee swapped the bytes by hardware before we read them
+ */
+ if ((unsigned long)dp2 & 1)
+ {
+ /* not aligned */
+ for (; len > 1; len -= 2)
+ {
+ w = isp116x_read_data16(isp116x);
+ *dp++ = w & 0xff;
+ *dp++ = (w >> 8) & 0xff;
+ }
+ if (len)
+ *dp = 0xff & isp116x_read_data16(isp116x);
+ }
+ else
+ {
+ /* aligned */
+ for (; len > 1; len -= 2)
+ *dp2++ = isp116x_read_data16(isp116x);
+ if (len)
+ *(unsigned char *) dp2 = 0xff & isp116x_raw_read_data16(isp116x);
+
+ }
+ if (quot == 1 || quot == 2)
+ isp116x_read_data16(isp116x);
+}
+
+/* Write PTD's and data for scheduled transfers into the fifo ram.
+ * Fifo must be empty and ready
+ */
+static void
+pack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+ unsigned long pipe, struct ptd *ptd, long n, void *data,
+ long len)
+{
+ long buflen = n * sizeof(struct ptd) + len;
+ long i, done;
+
+ DEBUG(("--- pack buffer 0x%08lx - %ld bytes (fifo %ld) ---", data, len, buflen));
+
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+
+ isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+ set_int_lvl7();
+ isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+
+ done = 0;
+ for (i = 0; i < n; i++)
+ {
+ //DEBUG(("i=%ld - done=%ld - len=%d", i, done, PTD_GET_LEN(&ptd[i])));
+
+ /* For NetUSBee, use raw_write to don't swap bytes */
+// dump_ptd(&ptd[i]);
+ isp116x_raw_write_data16(isp116x, ptd[i].count);
+ isp116x_raw_write_data16(isp116x, ptd[i].mps);
+ isp116x_raw_write_data16(isp116x, ptd[i].len);
+ isp116x_raw_write_data16(isp116x, ptd[i].faddr);
+
+// dump_ptd_data(&ptd[i], (unsigned char *) data + done, 0);
+
+ /* This part is critical, disamble interrupts */
+// set_int_lvl7();
+ write_ptddata_to_fifo(isp116x,
+ (unsigned char *) data + done,
+ PTD_GET_LEN(&ptd[i]));
+// set_old_int_lvl();
+
+ done += PTD_GET_LEN(&ptd[i]);
+ set_old_int_lvl();
+ }
+}
+
+/* Read the processed PTD's and data from fifo ram back to URBs' buffers.
+ * Fifo must be full and done
+ */
+static long
+unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+ unsigned long pipe, struct ptd *ptd, long n, void *data,
+ long len)
+{
+ long buflen = n * sizeof(struct ptd) + len;
+ long i, done, cc, ret;
+
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+ isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+ set_int_lvl7();
+ isp116x_write_addr(isp116x, HCATLPORT);
+
+ ret = TD_CC_NOERROR;
+ done = 0;
+ for (i = 0; i < n; i++)
+ {
+ /* For NetUSBee, use raw_read to don't swap bytes */
+ ptd[i].count = isp116x_raw_read_data16(isp116x);
+ ptd[i].mps = isp116x_raw_read_data16(isp116x);
+ ptd[i].len = isp116x_raw_read_data16(isp116x);
+ ptd[i].faddr = isp116x_raw_read_data16(isp116x);
+// dump_ptd(&ptd[i]);
+
+ /* when cc is 15 the data has not being touch by the HC
+ * so we have to read all to empty completly the buffer
+ */
+ if (PTD_GET_COUNT(ptd) != 0 || PTD_GET_CC(ptd) == 15
+ || PTD_GET_CC(ptd) == 5 || PTD_GET_CC(ptd) == 6)
+ {
+ /* This part is critical, disamble interrupts */
+// set_int_lvl7();
+ read_ptddata_from_fifo(isp116x,
+ (unsigned char *) data + done,
+ PTD_GET_LEN(&ptd[i]));
+// set_old_int_lvl();
+ }
+
+ dump_ptd_data(&ptd[i], (unsigned char *) data + done, 1);
+
+ done += PTD_GET_LEN(&ptd[i]);
+
+ cc = PTD_GET_CC(&ptd[i]);
+
+ /* Data underrun means basically that we had more buffer space than
+ * the function had data. It is perfectly normal but upper levels have
+ * to know how much we actually transferred.
+ */
+ if (cc == TD_NOTACCESSED ||
+ (cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))
+ ret = cc;
+ }
+ DEBUG(("--- unpack buffer 0x%08lx - %ld bytes (fifo %ld) count: %d ---", data, len, buflen, PTD_GET_COUNT(ptd)));
+
+ set_old_int_lvl();
+
+ return ret;
+}
+
+/* Interrupt handling
+ */
+static long
+isp116x_interrupt(struct isp116x *isp116x)
+{
+ unsigned short irqstat;
+ unsigned long intstat;
+ long ret = 0;
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+ irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+ isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+ DEBUG((">>>>>> irqstat %x <<<<<<", irqstat));
+
+ if (irqstat & HCuPINT_ATL)
+ {
+ DEBUG((">>>>>> HCuPINT_ATL <<<<<<"));
+ udelay(500);
+ ret = 1;
+ }
+
+ if (irqstat & HCuPINT_OPR)
+ {
+ intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+ isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+ DEBUG((">>>>>> HCuPINT_OPR %x <<<<<<", intstat));
+
+ if (intstat & HCINT_UE)
+ {
+ ALERT(("unrecoverable error, controller disabled"));
+
+ /* FIXME: be optimistic, hope that bug won't repeat
+ * often. Make some non-interrupt context restart the
+ * controller. Count and limit the retries though;
+ * either hardware or software errors can go forever...
+ */
+ isp116x_reset(isp116x);
+ ret = -1;
+ return -1;
+ }
+
+ if (intstat & HCINT_RHSC)
+ {
+ got_rhsc = 1;
+ ret = 1;
+ /* When root hub or any of its ports is going
+ to come out of suspend, it may take more
+ than 10ms for status bits to stabilize. */
+ mdelay(20);
+ }
+
+ if (intstat & HCINT_SO)
+ {
+ ALERT(("schedule overrun"));
+ ret = -1;
+ }
+
+ irqstat &= ~HCuPINT_OPR;
+ }
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+ return ret;
+}
+
+/* With one PTD we can transfer almost 1K in one go;
+ * HC does the splitting into endpoint digestible transactions
+ */
+struct ptd ptd[1];
+
+static inline long
+max_transfer_len(struct usb_device *dev, unsigned long pipe)
+{
+ unsigned mpck = (*uinf->usb_maxpacket)(dev, pipe);
+
+ /* One PTD can transfer 1023 bytes but try to always
+ * transfer multiples of endpoint buffer size
+ */
+ return 1023 / mpck * mpck;
+}
+
+
+/* Do an USB transfer
+ */
+static long
+isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
+ long dir, void *buffer, long len)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+ long type = usb_pipetype(pipe);
+ long epnum = usb_pipeendpoint(pipe);
+ long max = (*uinf->usb_maxpacket)(dev, pipe);
+ long dir_out = usb_pipeout(pipe);
+ long speed_low = usb_pipeslow(pipe);
+ long i, done = 0, stat, timeout, cc;
+
+ /* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
+ long retries = 500;
+ short set_extra_delay = 0;
+
+ DEBUG(("------------------------------------------------"));
+ dump_msg(dev, pipe, buffer, len, "SUBMIT");
+ DEBUG(("------------------------------------------------"));
+
+ if (len >= 1024)
+ {
+ ALERT(("Too big job"));
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ if (isp116x->disabled)
+ {
+ ALERT(("EPIPE"));
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev)
+ {
+ ALERT(("ENODEV"));
+ dev->status = USB_ST_CRC_ERR;
+ return USB_ST_CRC_ERR;
+ }
+
+ if (!max)
+ {
+ ALERT(("pipesize for pipe %lx is zero", pipe));
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ if (type == PIPE_ISOCHRONOUS)
+ {
+ ALERT(("isochronous transfers not supported"));
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ /* FIFO not empty? */
+ if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL)
+ {
+ DEBUG(("****** FIFO not empty! ******"));
+ dev->status = USB_ST_BUF_ERR;
+ return -1;
+ }
+
+retry:
+ isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
+ /* Prepare the PTD data */
+ ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |
+ PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
+ ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;
+ ptd->len = PTD_LEN(len) | PTD_DIR(dir);
+ ptd->faddr = PTD_FA(usb_pipedevice(pipe));
+
+
+retry_same:
+
+ /* FIFO not empty? */
+ if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL)
+ {
+ DEBUG(("****** FIFO not empty! 2 ******"));
+ dev->status = USB_ST_BUF_ERR;
+ return -1;
+ }
+
+ /* Pack data into FIFO ram */
+ pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
+
+# ifdef EXTRA_DELAY
+// mdelay(EXTRA_DELAY);
+# endif
+ if(set_extra_delay)
+ {
+ mdelay(10);
+ }
+
+ /* Start the data transfer */
+
+ /* Allow more time for a BULK device to react - some are slow */
+ if (usb_pipebulk(pipe))
+ timeout = 5000; /* Galvez: default = 5000 */
+ else
+ timeout = 100; /* Galvez : netusbee : default = 100 */
+
+ /* Wait for it to complete */
+ for (;;)
+ {
+ /* Check whether the controller is done */
+ stat = isp116x_interrupt(isp116x);
+
+ if (stat < 0)
+ {
+ dev->status = USB_ST_CRC_ERR;
+ break;
+ }
+ if (stat > 0)
+ break;
+
+ /* Check the timeout */
+ if (--timeout)
+ udelay(1);
+ else
+ {
+ DEBUG(("CTL:TIMEOUT "));
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+ }
+
+ /* We got an Root Hub Status Change interrupt */
+ if (got_rhsc)
+ {
+ isp116x_show_regs(isp116x);
+
+ got_rhsc = 0;
+
+ /* Abuse timeout */
+ timeout = rh_check_port_status(isp116x);
+ if (timeout >= 0)
+ {
+ /*
+ * FIXME! NOTE! AAAARGH!
+ * This is potentially dangerous because it assumes
+ * that only one device is ever plugged in!
+ */
+ devgone = dev;
+ }
+ }
+
+
+ /* Ok, now we can read transfer status */
+
+ /* FIFO not ready? */
+ if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE))
+ {
+ DEBUG(("****** FIFO not ready! ******"));
+ dev->status = USB_ST_BUF_ERR;
+ return -1;
+ }
+
+ /* Unpack data from FIFO ram */
+ cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
+
+ i = PTD_GET_COUNT(ptd);
+ done += i;
+ buffer = (char *)buffer + i;
+ len -= i;
+
+
+ /* There was some kind of real problem; Prepare the PTD again
+ * and retry from the failed transaction on
+ */
+ if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN)
+ {
+ DEBUG(("PROBLEM cc: %ld", cc));
+ if (retries >= 100)
+ {
+ retries -= 100;
+ /* The chip will have toggled the toggle bit for the failed
+ * transaction too. We have to toggle it back.
+ */
+ usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));
+ goto retry;
+ }
+ }
+ /* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
+ * the transactions from the first on for the whole frame. It may be busy and we retry
+ * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the
+ * PTD didn't make it because the function was busy or the frame ended before the PTD
+ * finished. We prepare the rest of the data and try again.
+ */
+ else if ( cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || ( cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd)))
+ {
+ if (retries)
+ {
+ --retries;
+ if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd))
+ {
+ set_extra_delay = 1;
+ goto retry_same;
+ }
+ DEBUG(("cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) retry"));
+ usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
+ goto retry;
+ }
+ }
+
+ if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN)
+ {
+ DEBUG(("****** completion code error %lx ******", cc));
+ switch (cc)
+ {
+ case TD_CC_BITSTUFFING:
+ dev->status = USB_ST_BIT_ERR;
+ break;
+ case TD_CC_STALL:
+ dev->status = USB_ST_STALLED;
+ break;
+ case TD_BUFFEROVERRUN:
+ case TD_BUFFERUNDERRUN:
+ dev->status = USB_ST_BUF_ERR;
+ break;
+ default:
+ dev->status = USB_ST_CRC_ERR;
+ }
+ return -cc;
+ }
+ else
+ usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
+
+ dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
+
+ dev->status = 0;
+
+ return done;
+}
+
+/* Adapted from au1x00_usb_ohci.c
+ */
+static long
+isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, long transfer_len,
+ struct devrequest *cmd)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+ unsigned long tmp = 0;
+
+ long leni = transfer_len;
+ long len = 0;
+ long stat = 0;
+ unsigned long datab[4];
+ unsigned char *data_buf = (unsigned char *) datab;
+ unsigned short bmRType_bReq;
+ unsigned short wValue;
+ unsigned short wIndex;
+ unsigned short wLength;
+
+ if (usb_pipeint(pipe))
+ {
+ ALERT(("Root-Hub submit IRQ: NOT implemented"));
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = swap_16(cmd->value);
+ wIndex = swap_16(cmd->index);
+ wLength = swap_16(cmd->length);
+
+ DEBUG(("--- HUB ----------------------------------------"));
+ DEBUG(("submit rh urb, req=%x val=0x%x index=0x%x len=%d",
+ bmRType_bReq, wValue, wIndex, wLength);
+ dump_msg(dev, pipe, buffer, transfer_len, "RH"));
+ DEBUG(("------------------------------------------------"));
+
+ switch (bmRType_bReq)
+ {
+ case RH_GET_STATUS:
+ DEBUG(("RH_GET_STATUS"));
+
+ *(unsigned short *) data_buf = swap_16(1);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_INTERFACE:
+ DEBUG(("RH_GET_STATUS | RH_INTERFACE"));
+
+ *(unsigned short *) data_buf = swap_16(0);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_ENDPOINT:
+ DEBUG(("RH_GET_STATUS | RH_ENDPOINT"));
+
+ *(unsigned short *) data_buf = swap_16(0);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_CLASS:
+ DEBUG(("RH_GET_STATUS | RH_CLASS"));
+
+ tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+ *(unsigned long *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));
+ len = 4;
+ break;
+
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ DEBUG(("RH_GET_STATUS | RH_OTHER | RH_CLASS"));
+
+ tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);
+ *(unsigned long *) data_buf = swap_32(tmp);
+ isp116x_show_regs(isp116x);
+ len = 4;
+ break;
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ DEBUG(("RH_CLEAR_FEATURE | RH_ENDPOINT"));
+
+ switch (wValue)
+ {
+ case RH_ENDPOINT_STALL:
+ DEBUG(("C_HUB_ENDPOINT_STALL"));
+ len = 0;
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ DEBUG(("RH_CLEAR_FEATURE | RH_CLASS"));
+
+ switch (wValue)
+ {
+ case RH_C_HUB_LOCAL_POWER:
+ DEBUG(("C_HUB_LOCAL_POWER"));
+ len = 0;
+ break;
+
+ case RH_C_HUB_OVER_CURRENT:
+ DEBUG(("C_HUB_OVER_CURRENT"));
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+ len = 0;
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ DEBUG(("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS"));
+
+ switch (wValue)
+ {
+ case RH_PORT_ENABLE:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_CCS);
+ len = 0;
+ break;
+
+ case RH_PORT_SUSPEND:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_POCI);
+ len = 0;
+ break;
+
+ case RH_PORT_POWER:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_LSDA);
+ len = 0;
+ break;
+
+ case RH_C_PORT_CONNECTION:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_CSC);
+ len = 0;
+ break;
+
+ case RH_C_PORT_ENABLE:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PESC);
+ len = 0;
+ break;
+
+ case RH_C_PORT_SUSPEND:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PSSC);
+ len = 0;
+ break;
+
+ case RH_C_PORT_OVER_CURRENT:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_POCI);
+ len = 0;
+ break;
+
+ case RH_C_PORT_RESET:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PRSC);
+ len = 0;
+ break;
+
+ default:
+ ALERT(("invalid wValue"));
+ stat = USB_ST_STALLED;
+ }
+
+ isp116x_show_regs(isp116x);
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ DEBUG(("RH_SET_FEATURE | RH_OTHER | RH_CLASS"));
+
+ switch (wValue)
+ {
+ case RH_PORT_SUSPEND:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PSS);
+ len = 0;
+ break;
+
+ case RH_PORT_RESET:
+ /* Spin until any current reset finishes */
+ while (1)
+ {
+ tmp = isp116x_read_reg32(isp116x,
+ HCRHPORT1 + wIndex - 1);
+ if (!(tmp & RH_PS_PRS))
+ break;
+ mdelay(1);
+ }
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PRS);
+ mdelay(10);
+ len = 0;
+ break;
+
+ case RH_PORT_POWER:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PPS);
+ len = 0;
+ break;
+
+ case RH_PORT_ENABLE:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PES);
+ len = 0;
+ break;
+
+ default:
+ ALERT(("invalid wValue"));
+ stat = USB_ST_STALLED;
+ }
+ isp116x_show_regs(isp116x);
+ break;
+
+ case RH_SET_ADDRESS:
+ DEBUG(("RH_SET_ADDRESS"));
+
+ rh_devnum = wValue;
+ len = 0;
+ break;
+
+ case RH_GET_DESCRIPTOR:
+ DEBUG(("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength));
+
+ switch (wValue)
+ {
+ case (USB_DT_DEVICE << 8): /* device descriptor */
+ len = min1_t(unsigned long,
+ leni, min2_t(unsigned long,
+ sizeof(root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des;
+ break;
+
+ case (USB_DT_CONFIG << 8): /* configuration descriptor */
+ len = min1_t(unsigned long,
+ leni, min2_t(unsigned long,
+ sizeof(root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des;
+ break;
+
+ case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */
+ len = min1_t(unsigned long,
+ leni, min2_t(unsigned long,
+ sizeof(root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ break;
+
+ case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */
+ len = min1_t(unsigned long,
+ leni, min2_t(unsigned long,
+ sizeof(root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ break;
+
+ default:
+ ALERT(("invalid wValue"));
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ DEBUG(("RH_GET_DESCRIPTOR | RH_CLASS"));
+
+ tmp = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+ data_buf[0] = 0x09; /* min length; */
+ data_buf[1] = 0x29;
+ data_buf[2] = tmp & RH_A_NDP;
+ data_buf[3] = 0;
+ if (tmp & RH_A_PSM) /* per-port power switching? */
+ data_buf[3] |= 0x01;
+ if (tmp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf[3] |= 0x10;
+ else if (tmp & RH_A_OCPM) /* per-port overcurrent rep? */
+ data_buf[3] |= 0x08;
+
+ /* Corresponds to data_buf[4-7] */
+ datab[1] = 0;
+ data_buf[5] = (tmp & RH_A_POTPGT) >> 24;
+
+ tmp = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+ data_buf[7] = tmp & RH_B_DR;
+ if (data_buf[2] < 7)
+ data_buf[8] = 0xff;
+ else
+ {
+ data_buf[0] += 2;
+ data_buf[8] = (tmp & RH_B_DR) >> 8;
+ data_buf[10] = data_buf[9] = 0xff;
+ }
+
+ len = min1_t(unsigned long, leni,
+ min2_t(unsigned long, data_buf[0], wLength));
+ break;
+
+ case RH_GET_CONFIGURATION:
+ DEBUG(("RH_GET_CONFIGURATION"));
+
+ *(unsigned char *) data_buf = 0x01;
+ len = 1;
+ break;
+
+ case RH_SET_CONFIGURATION:
+ DEBUG(("RH_SET_CONFIGURATION"));
+
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC);
+ len = 0;
+ break;
+
+ default:
+ ALERT(("*** *** *** unsupported root hub command *** *** ***"));
+ stat = USB_ST_STALLED;
+ }
+
+ len = min1_t(long, len, leni);
+ if (buffer != data_buf)
+ memcpy(buffer, data_buf, len);
+
+ dev->act_len = len;
+ dev->status = stat;
+ DEBUG(("dev act_len %ld, status %ld", dev->act_len, dev->status));
+
+ dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)");
+
+ return stat;
+}
+
+/* --- Transfer functions -------------------------------------------------- */
+
+long
+submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ long len, long interval)
+{
+ DEBUG(("dev=0x%lx pipe=%lx buf=0x%lx size=%d int=%d",
+ dev, pipe, buffer, len, interval));
+
+ return -1;
+}
+
+long
+submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ long len, struct devrequest *setup)
+{
+ long devnum = usb_pipedevice(pipe);
+ long epnum = usb_pipeendpoint(pipe);
+ long max = max_transfer_len(dev, pipe);
+ long dir_in = usb_pipein(pipe);
+ long done, ret;
+
+
+ /* Control message is for the HUB? */
+ if (devnum == rh_devnum)
+ return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup);
+
+ /* Ok, no HUB message so send the message to the device */
+
+ /* Setup phase */
+ DEBUG(("--- SETUP PHASE --------------------------------"));
+ usb_settoggle(dev, epnum, 1, 0);
+
+
+ ret = isp116x_submit_job(dev, pipe,
+ PTD_DIR_SETUP,
+ setup, sizeof(struct devrequest));
+ if (ret < 0)
+ {
+ DEBUG(("control setup phase error (ret = %d", ret));
+ return -1;
+ }
+
+ /* Data phase */
+ DEBUG(("--- DATA PHASE ---------------------------------"));
+ done = 0;
+ usb_settoggle(dev, epnum, !dir_in, 1);
+ while (done < len)
+ {
+ ret = isp116x_submit_job(dev, pipe,
+ dir_in ? PTD_DIR_IN : PTD_DIR_OUT,
+ (unsigned char *) buffer + done,
+ max > len - done ? len - done : max);
+ if (ret < 0)
+ {
+ DEBUG(("control data phase error (ret = %d)", ret));
+ return -1;
+ }
+ done += ret;
+
+ if (dir_in && ret < max) /* short packet */
+ break;
+ }
+
+ /* Status phase */
+ DEBUG(("--- STATUS PHASE -------------------------------"));
+ usb_settoggle(dev, epnum, !dir_in, 1);
+ ret = isp116x_submit_job(dev, pipe,
+ !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0);
+ if (ret < 0)
+ {
+ DEBUG(("control status phase error (ret = %d", ret));
+ return -1;
+ }
+
+ dev->act_len = done;
+
+ dump_msg(dev, pipe, buffer, len, "DEV(ret)");
+
+ return done;
+}
+
+short flagy = 0;
+
+long
+submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ long len)
+{
+ long dir_out = usb_pipeout(pipe);
+ long max = max_transfer_len(dev, pipe);
+ long done, ret;
+
+ DEBUG(("--- BULK ---------------------------------------"));
+ DEBUG(("dev=%ld pipe=%ld buf=0x%lx size=%d dir_out=%d",
+ usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out));
+ done = 0;
+ while (done < len)
+ {
+
+ ret = isp116x_submit_job(dev, pipe,
+ !dir_out ? PTD_DIR_IN : PTD_DIR_OUT,
+ (unsigned char *) buffer + done,
+ max > len - done ? len - done : max);
+
+ if (ret < 0)
+ {
+ DEBUG(("error on bulk message (ret = %d)", ret));
+ return -1;
+ }
+
+ done += ret;
+
+ if (!dir_out && ret < max) /* short packet */
+ break;
+ }
+
+ dev->act_len = done;
+
+ return 0;
+}
+
+
+/* --- Basic functions ----------------------------------------------------- */
+
+
+# if 0
+/* GALVEZ: Test function */
+static long GALVEZ_test_function( struct isp116x *isp116x )
+{
+ short rwc;
+
+ rwc = isp116x_read_reg16(isp116x, HCCONTROL) & HCCONTROL_RWC;
+ if (rwc)
+ {
+ INFO ("remote wake-up supported \n\r");
+ }
+ return 0;
+
+}
+# endif
+
+static long
+isp116x_sw_reset(struct isp116x *isp116x)
+{
+ long retries = 15;
+ long ret = 0;
+
+ isp116x->disabled = 1;
+
+ isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+ isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+
+ while (--retries)
+ {
+ /* It usually resets within 1 ms */
+ /* GALVEZ: not enough for TOS, try 7 ms */
+ mdelay(7);
+ if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+ break;
+ }
+
+ if (!retries)
+ {
+ DEBUG(("software reset timeout"));
+ ret = -1;
+ }
+
+# if 0
+ /* GALVEZ: DEBUG SOFTWARE RESET */
+
+ retries = 5000;
+
+ while (--retries){
+ if ((isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR)) {
+ INFO ("HCR: 1 retries: %d\n\r",retries);
+ }
+ }
+# endif /* END DEBUG */
+
+ return ret;
+}
+
+static long
+isp116x_reset(struct isp116x *isp116x)
+{
+ unsigned long t;
+ unsigned short clkrdy = 0;
+ long ret, timeout = 1000;/* ms
+ * Galvez: 15 ms sometimes isn't enough,
+ * for NetUSBee under TOS ??????? increased to 150 ms
+ */
+
+ ret = isp116x_sw_reset(isp116x);
+
+ if (ret)
+ return ret;
+
+ for (t = 0; t < timeout; t++)
+ {
+ clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+ if (clkrdy)
+ break;
+ mdelay(4); /* Default 1 ms */
+ }
+ if (!clkrdy)
+ {
+ DEBUG(("clock not ready after %ldms", timeout));
+ /* After sw_reset the clock won't report to be ready, if
+ H_WAKEUP pin is high. */
+ DEBUG(("please make sure that the H_WAKEUP pin is pulled low!"));
+ ret = -1;
+ }
+ return ret;
+}
+
+static void
+isp116x_stop(struct isp116x *isp116x)
+{
+ unsigned long val;
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+ /* Switch off ports' power, some devices don't come up
+ after next 'start' without this */
+ val = isp116x_read_reg32(isp116x, HCRHDESCA);
+ val &= ~(RH_A_NPS | RH_A_PSM);
+ isp116x_write_reg32(isp116x, HCRHDESCA, val);
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+
+ isp116x_sw_reset(isp116x);
+}
+
+
+static void
+int_handle_tophalf(PROC *process, long arg)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+
+ if (isp116x->rhport[0] & RH_PS_CSC)
+ {
+ (*uinf->usb_rh_wakeup)();
+ }
+
+ if (isp116x->rhport[1] & RH_PS_CSC)
+ {
+ (*uinf->usb_rh_wakeup)();
+ }
+}
+
+
+void _cdecl netusbee_hub_events(void);
+
+void _cdecl
+netusbee_hub_events(void)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+ unsigned short irqstat;
+ unsigned long intstat;
+
+ /* Shut out all further interrupts */
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+ irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+
+// set_old_int_lvl();
+
+ if (irqstat & HCuPINT_OPR)
+ {
+ intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+ isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+
+ if (intstat & HCINT_RHSC)
+ {
+ isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+ isp116x->rhport[0] = isp116x_read_reg32(isp116x, HCRHPORT1);
+ isp116x->rhport[1] = isp116x_read_reg32(isp116x, HCRHPORT2);
+
+ addroottimeout (0L, int_handle_tophalf, 0x1);
+ }
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_OPR);
+ }
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+// set_int_lvl7();
+}
+
+void netusbee_hub_poll_thread(void *);
+void netusbee_hub_poll(PROC *proc, long dummy);
+
+void
+netusbee_hub_poll(PROC *proc, long dummy)
+{
+ wake(WAIT_Q, (long)&netusbee_hub_poll_thread);
+}
+
+void
+netusbee_hub_poll_thread(void *dummy)
+{
+
+ /* join process group of loader,
+ * otherwise doesn't ends when shutingdown
+ */
+
+ for (;;)
+ {
+ netusbee_hub_events();
+ addtimeout(1000L, netusbee_hub_poll);
+ sleep(WAIT_Q, (long)&netusbee_hub_poll_thread);
+ }
+
+ kthread_exit(0);
+}
+
+
+/*
+ * Configure the chip. The chip must be successfully reset by now.
+ */
+static long
+isp116x_start(struct isp116x *isp116x)
+{
+ struct isp116x_platform_data *board = isp116x->board;
+ unsigned long val;
+
+ /* Clear interrupt status and disable all interrupt sources */
+ isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+ isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+ isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+ /* Hardware configuration */
+ val = HCHWCFG_DBWIDTH(1);
+
+ if (board->int_act_high)
+ val |= HCHWCFG_INT_POL;
+ if (board->int_edge_triggered)
+ val |= HCHWCFG_INT_TRIGGER;
+ if (board->sel15Kres)
+ val |= HCHWCFG_15KRSEL;
+ /* Remote wakeup won't work without working clock */
+ if (board->remote_wakeup_enable)
+ val |= HCHWCFG_CLKNOTSTOP;
+ if (board->oc_enable)
+ val |= HCHWCFG_ANALOG_OC;
+ isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+ /* --- Root hub configuration */
+ val = (25L << 24) & RH_A_POTPGT;
+ /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
+ be always set. Yet, instead, we request individual port
+ power switching. */
+ /* For NetUSBee ports are always powered */
+ val |= RH_A_NPS;
+// val |= RH_A_PSM;
+ /* Report overcurrent per port */
+// val |= RH_A_OCPM;
+ /* Overcurrent protection disable */
+ val |= RH_A_NOCP;
+
+ isp116x_write_reg32(isp116x, HCRHDESCA, val);
+ isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+ val = RH_B_PPCM;
+ isp116x_write_reg32(isp116x, HCRHDESCB, val);
+ isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+ val = 0;
+ if (board->remote_wakeup_enable)
+ val |= RH_HS_DRWE;
+ isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+ isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+ isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+ /* Go operational */
+ val = HCCONTROL_USB_OPER;
+ if (board->remote_wakeup_enable)
+ val |= HCCONTROL_RWE;
+ isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+ /* Disable ports to avoid race in device enumeration */
+ isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+ isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+ isp116x->intenb = HCINT_MIE | HCINT_RHSC; /* HCINT_UE */
+ isp116x_write_reg32(isp116x, HCINTENB, isp116x->intenb);
+// isp116x->irqenb = HCuPINT_OPR; /* | HCuPINT_ATL; | HCuPINT_SUSP */
+// isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+// val = isp116x_read_reg16(isp116x, HCHWCFG);
+// val |= HCHWCFG_INT_ENABLE;
+// isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+ long r;
+ r = kthread_create(NULL, netusbee_hub_poll_thread, NULL, NULL, "hubpoll");
+
+ if (r)
+ {
+ /* XXX todo -> exit gracefully */
+ //DEBUG((/*0000000a*/"can't create NetUSBee kernel thread"));
+ }
+
+ isp116x_show_regs(isp116x);
+
+ isp116x->disabled = 0;
+
+ return 0;
+}
+
+/* --- Inteface functions -------------------------------------------------- */
+
+static long _cdecl
+netusbee_open(struct ucdif *u)
+{
+ return E_OK;
+}
+
+static long _cdecl
+netusbee_close(struct ucdif *u)
+{
+ return E_OK;
+}
+
+static long _cdecl
+netusbee_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 (0, NULL);
+ break;
+ }
+ case LOWLEVEL_STOP :
+ {
+ ret = usb_lowlevel_stop ();
+ 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 ------------------------------------------------------ */
+
+long
+isp116x_check_id(struct isp116x *isp116x)
+{
+ unsigned short val;
+
+ val = isp116x_read_reg16(isp116x, HCCHIPID);
+ DEBUG(("chip ID: %x", val));
+
+ if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC)
+ {
+ ALERT(("invalid chip ID %04x", val));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+long
+usb_lowlevel_init(long dummy1, const struct pci_device_id *dummy2)
+{
+// unsigned short val;
+
+ struct isp116x *isp116x = &isp116x_dev;
+
+ got_rhsc = rh_devnum = 0;
+
+ /* Init device registers addr */
+ isp116x->addr_reg = (unsigned short *) ISP116X_HCD_ADDR;
+ isp116x->data_reg = (unsigned short *) ISP116X_HCD_DATA;
+
+ /* Setup specific board settings */
+#ifdef ISP116X_HCD_INT_ACT_HIGH
+ isp116x_board.int_act_high = 1;
+#endif
+#ifdef ISP116X_HCD_INT_EDGE_TRIGGERED
+ isp116x_board.int_edge_triggered = 1;
+#endif
+#define ISP116X_HCD_SEL15kRES
+#ifdef ISP116X_HCD_SEL15kRES
+ isp116x_board.sel15Kres = 1;
+#endif
+#define ISP116X_HCD_OC_ENABLE
+#ifdef ISP116X_HCD_OC_ENABLE
+ isp116x_board.oc_enable = 1;
+#endif
+#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE
+ isp116x_board.remote_wakeup_enable = 1;
+#endif
+ isp116x->board = &isp116x_board;
+
+ /* Try to get ISP116x silicon chip ID */
+ if (isp116x_check_id(isp116x) < 0)
+ return (-1);
+
+ isp116x->disabled = 1;
+ isp116x->sleeping = 0;
+
+ isp116x_reset(isp116x);
+ isp116x_start(isp116x);
+
+ return 0;
+}
+
+long
+usb_lowlevel_stop(void)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+
+ if (!isp116x->disabled)
+ isp116x_stop(isp116x);
+
+ return 0;
+}
+
+long _cdecl
+init(struct kentry *k, struct ucdinfo *uinfo, char **reason)
+{
+ long ret;
+
+ kentry = k;
+ uinf = uinfo;
+
+ if (check_kentry_version())
+ return -1;
+
+ c_conws (MSG_BOOT);
+ c_conws (MSG_GREET);
+ DEBUG (("%s: enter init", __FILE__));
+
+ ret = (*uinf->ucd_register)(&netusbee_uif);
+ if (ret)
+ {
+ DEBUG (("%s: ucd register failed!", __FILE__));
+ return 1;
+ }
+
+ DEBUG (("%s: ucd register ok", __FILE__));
+ return 0;
+}
Index: sys/usb/src.km/ucd/netusbee/isp116x.h
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/isp116x.h
@@ -0,0 +1,560 @@
+/*
+ * Modified for Atari-NetUSBee by David Gálvez. 2010 - 2011
+ *
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ *
+ * This file 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 file 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 _NETUSBEE_ISP116X_H
+#define _NETUSBEE_ISP116X_H
+
+/* ------------------------------------------------------------------------- */
+
+/* us of 1ms frame */
+#define MAX_LOAD_LIMIT 850
+
+/* Full speed: max # of bytes to transfer for a single urb
+ at a time must be < 1024 && must be multiple of 64.
+ 832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED 832
+
+/* Low speed: there is no reason to schedule in very big
+ chunks; often the requested long transfers are for
+ string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED 64
+
+/* Bytetime (us), a rough indication of how much time it
+ would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED 1
+#define BYTE_TIME_LOWSPEED 20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE 4096
+#define ISP116x_ITL_BUFSIZE 0
+#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET 0x80
+
+/* --- ISP116x address registers in Netusbee --------------------------------*/
+
+#define ISP116X_HCD_ADDR 0x00FBC000
+#define ISP116X_HCD_DATA 0x00FA0000
+
+/* --- ISP116x registers/bits ---------------------------------------------- */
+
+#define HCREVISION 0x00
+#define HCCONTROL 0x01
+#define HCCONTROL_HCFS (3UL << 6) /* host controller
+ functional state */
+#define HCCONTROL_USB_RESET (0UL << 6)
+#define HCCONTROL_USB_RESUME (1UL << 6)
+#define HCCONTROL_USB_OPER (2UL << 6)
+#define HCCONTROL_USB_SUSPEND (3UL << 6)
+#define HCCONTROL_RWC (1UL << 9) /* remote wakeup connected */
+#define HCCONTROL_RWE (1UL << 10) /* remote wakeup enable */
+#define HCCMDSTAT 0x02
+#define HCCMDSTAT_HCR (1UL << 0) /* host controller reset */
+#define HCCMDSTAT_SOC (3UL << 16) /* scheduling overrun count */
+#define HCINTSTAT 0x03
+#define HCINT_SO (1UL << 0) /* scheduling overrun */
+#define HCINT_WDH (1UL << 1) /* writeback of done_head */
+#define HCINT_SF (1UL << 2) /* start frame */
+#define HCINT_RD (1UL << 3) /* resume detect */
+#define HCINT_UE (1UL << 4) /* unrecoverable error */
+#define HCINT_FNO (1UL << 5) /* frame number overflow */
+#define HCINT_RHSC (1UL << 6) /* root hub status change */
+#define HCINT_OC (1UL << 30) /* ownership change */
+#define HCINT_MIE (1UL << 31) /* master interrupt enable */
+#define HCINTENB 0x04
+#define HCINTDIS 0x05
+#define HCFMINTVL 0x0d
+#define HCFMREM 0x0e
+#define HCFMNUM 0x0f
+#define HCLSTHRESH 0x11
+#define HCRHDESCA 0x12
+#define RH_A_NDP (0x3UL << 0) /* #downstream ports */
+#define RH_A_PSM (1UL << 8) /* power switching mode */
+#define RH_A_NPS (1UL << 9) /* no power switching */
+#define RH_A_DT (1UL << 10) /* device type (mbz) */
+#define RH_A_OCPM (1UL << 11) /* overcurrent protection
+ mode */
+#define RH_A_NOCP (1UL << 12) /* no overcurrent protection */
+#define RH_A_POTPGT (0xffUL << 24) /* power on -> power good
+ time */
+#define HCRHDESCB 0x13
+#define RH_B_DR (0xffffUL << 0) /* device removable flags */
+#define RH_B_PPCM (0xffffUL << 16) /* port power control mask */
+#define HCRHSTATUS 0x14
+#define RH_HS_LPS (1UL << 0) /* local power status */
+#define RH_HS_OCI (1UL << 1) /* over current indicator */
+#define RH_HS_DRWE (1UL << 15) /* device remote wakeup
+ enable */
+#define RH_HS_LPSC (1UL << 16) /* local power status change */
+#define RH_HS_OCIC (1UL << 17) /* over current indicator
+ change */
+#define RH_HS_CRWE (1UL << 31) /* clear remote wakeup
+ enable */
+#define HCRHPORT1 0x15
+#define RH_PS_CCS (1UL << 0) /* current connect status */
+#define RH_PS_PES (1UL << 1) /* port enable status */
+#define RH_PS_PSS (1UL << 2) /* port suspend status */
+#define RH_PS_POCI (1UL << 3) /* port over current
+ indicator */
+#define RH_PS_PRS (1UL << 4) /* port reset status */
+#define RH_PS_PPS (1UL << 8) /* port power status */
+#define RH_PS_LSDA (1UL << 9) /* low speed device attached */
+#define RH_PS_CSC (1UL << 16) /* connect status change */
+#define RH_PS_PESC (1UL << 17) /* port enable status change */
+#define RH_PS_PSSC (1UL << 18) /* port suspend status
+ change */
+#define RH_PS_OCIC (1UL << 19) /* over current indicator
+ change */
+#define RH_PS_PRSC (1UL << 20) /* port reset status change */
+#define HCRHPORT_CLRMASK (0x1f << 16)
+#define HCRHPORT2 0x16
+#define HCHWCFG 0x20
+#define HCHWCFG_15KRSEL (1 << 12)
+#define HCHWCFG_CLKNOTSTOP (1 << 11)
+#define HCHWCFG_ANALOG_OC (1 << 10)
+#define HCHWCFG_DACK_MODE (1 << 8)
+#define HCHWCFG_EOT_POL (1 << 7)
+#define HCHWCFG_DACK_POL (1 << 6)
+#define HCHWCFG_DREQ_POL (1 << 5)
+#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
+#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define HCHWCFG_INT_POL (1 << 2)
+#define HCHWCFG_INT_TRIGGER (1 << 1)
+#define HCHWCFG_INT_ENABLE (1 << 0)
+#define HCDMACFG 0x21
+#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
+#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
+#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
+#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
+#define HCDMACFG_DMA_ENABLE (1 << 4)
+#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
+#define HCDMACFG_CTR_SEL (1 << 2)
+#define HCDMACFG_ITLATL_SEL (1 << 1)
+#define HCDMACFG_DMA_RW_SELECT (1 << 0)
+#define HCXFERCTR 0x22
+#define HCuPINT 0x24
+#define HCuPINT_SOF (1 << 0)
+#define HCuPINT_ATL (1 << 1)
+#define HCuPINT_AIIEOT (1 << 2)
+#define HCuPINT_OPR (1 << 4)
+#define HCuPINT_SUSP (1 << 5)
+#define HCuPINT_CLKRDY (1 << 6)
+#define HCuPINTENB 0x25
+#define HCCHIPID 0x27
+#define HCCHIPID_MASK 0xff00
+#define HCCHIPID_MAGIC 0x6100
+#define HCSCRATCH 0x28
+#define HCSWRES 0x29
+#define HCSWRES_MAGIC 0x00f6
+#define HCITLBUFLEN 0x2a
+#define HCATLBUFLEN 0x2b
+#define HCBUFSTAT 0x2c
+#define HCBUFSTAT_ITL0_FULL (1 << 0)
+#define HCBUFSTAT_ITL1_FULL (1 << 1)
+#define HCBUFSTAT_ATL_FULL (1 << 2)
+#define HCBUFSTAT_ITL0_DONE (1 << 3)
+#define HCBUFSTAT_ITL1_DONE (1 << 4)
+#define HCBUFSTAT_ATL_DONE (1 << 5)
+#define HCRDITL0LEN 0x2d
+#define HCRDITL1LEN 0x2e
+#define HCITLPORT 0x40
+#define HCATLPORT 0x41
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK)
+
+/* Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+ /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+ /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED 0x0F
+
+/* ------------------------------------------------------------------------- */
+
+#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
+#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
+
+/* Philips transfer descriptor */
+struct ptd {
+ unsigned short count;
+#define PTD_COUNT_MSK (0x3ff << 0)
+#define PTD_TOGGLE_MSK (1 << 10)
+#define PTD_ACTIVE_MSK (1 << 11)
+#define PTD_CC_MSK (0xf << 12)
+ unsigned short mps;
+#define PTD_MPS_MSK (0x3ff << 0)
+#define PTD_SPD_MSK (1 << 10)
+#define PTD_LAST_MSK (1 << 11)
+#define PTD_EP_MSK (0xf << 12)
+ unsigned short len;
+#define PTD_LEN_MSK (0x3ff << 0)
+#define PTD_DIR_MSK (3 << 10)
+#define PTD_DIR_SETUP (0)
+#define PTD_DIR_OUT (1)
+#define PTD_DIR_IN (2)
+#define PTD_B5_5_MSK (1 << 13)
+ unsigned short faddr;
+#define PTD_FA_MSK (0x7f << 0)
+#define PTD_FMT_MSK (1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+struct isp116x_ep
+{
+ struct usb_device *udev;
+ struct ptd ptd;
+
+ unsigned char maxpacket;
+ unsigned char epnum;
+ unsigned char nextpid;
+
+ unsigned short length; /* of current packet */
+ unsigned char *data; /* to databuf */
+
+ unsigned short error_count;
+};
+
+/* URB struct */
+#define N_URB_TD 48
+#define URB_DEL 1
+typedef struct
+{
+ struct isp116x_ep *ed;
+ void *transfer_buffer; /* (in) associated data buffer */
+ long actual_length; /* (return) actual transfer length */
+ unsigned long pipe; /* (in) pipe information */
+#if 0
+ long state;
+#endif
+} urb_priv_t;
+
+struct isp116x_platform_data
+{
+ /* Enable internal resistors on downstream ports */
+ unsigned sel15Kres:1;
+ /* On-chip overcurrent detection */
+ unsigned oc_enable:1;
+ /* Enable wakeup by devices on usb bus (e.g. wakeup
+ by attachment/detachment or by device activity
+ such as moving a mouse). When chosen, this option
+ prevents stopping internal clock, increasing
+ thereby power consumption in suspended state. */
+ unsigned remote_wakeup_enable:1;
+ /* INT output polarity */
+ unsigned int_act_high:1;
+ /* INT edge or level triggered */
+ unsigned int_edge_triggered:1;
+
+};
+
+struct isp116x
+{
+ unsigned short *addr_reg;
+ unsigned short *data_reg;
+
+ struct isp116x_platform_data *board;
+
+ struct dentry *dentry;
+ unsigned long stat1, stat2, stat4, stat8, stat16;
+
+ unsigned long intenb; /* "OHCI" interrupts */
+ unsigned short irqenb; /* uP interrupts */
+
+ /* Status flags */
+ unsigned disabled:1;
+ unsigned sleeping:1;
+
+ /* Root hub registers */
+ unsigned long rhdesca;
+ unsigned long rhdescb;
+ unsigned long rhstatus;
+ unsigned long rhport[2];
+
+ /* Schedule for the current frame */
+ struct isp116x_ep *atl_active;
+ long atl_buflen;
+ long atl_bufshrt;
+ long atl_last_dir;
+ long atl_finishing;
+};
+
+/* ------------------------------------------------- */
+
+/* Inter-io delay (ns). The chip is picky about access timings; it
+ * expects at least:
+ * 150ns delay between consecutive accesses to DATA_REG,
+ * 300ns delay between access to ADDR_REG and DATA_REG
+ * OE, WE MUST NOT be changed during these intervals
+ */
+#if defined(UDELAY)
+# define isp116x_delay(h,d) udelay(d)
+#else
+# define isp116x_delay(h,d) do {} while (0)
+#endif
+
+
+unsigned long p;
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+ u16 dumm;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + ((reg & 0x00ff)<<1));
+ dumm = __raw_readw(isp116x->data_reg);
+ isp116x->addr_reg = (u16*)ISP116X_HCD_ADDR;
+ dumm = __raw_readw(isp116x->addr_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, unsigned short val)
+{
+ u16 dumm;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + ((val & 0xff00)>>7));
+ dumm = __raw_readw(isp116x->data_reg);
+ isp116x->addr_reg = (u16*)((ISP116X_HCD_ADDR - 0x4000) + ((val & 0x00ff)<<1));
+ dumm = __raw_readw(isp116x->addr_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, unsigned short val)
+{
+ u16 dumm;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + ((val & 0x00ff)<<1));
+ dumm = __raw_readw(isp116x->data_reg);
+ isp116x->addr_reg = (u16*)((ISP116X_HCD_ADDR - 0x4000) + ((val & 0xff00)>>7));
+ dumm = __raw_readw(isp116x->addr_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline unsigned short isp116x_read_data16(struct isp116x *isp116x)
+{
+ unsigned short val;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + 0x8000);
+ val = readw(isp116x->data_reg );
+ isp116x_delay(isp116x, UDELAY);
+
+ return val;
+}
+
+static inline unsigned short isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+ unsigned short val;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + 0x8000);
+ val = __raw_readw(isp116x->data_reg );
+ isp116x_delay(isp116x, UDELAY);
+
+ return val;
+}
+
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, unsigned long val)
+{
+ writew(val & 0xffff, isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+ writew(val >> 16, isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+/*
+ * Added for NetUSBee, to write HC registers without swapping them
+ * NetUSBee already swap them by hardware (i suppose.....)
+ */
+static inline void isp116x_raw_write_data32(struct isp116x *isp116x, unsigned long val)
+{
+ u16 dumm;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + ((val & 0x000000ff)<<1));
+ dumm = __raw_readw(isp116x->data_reg);
+ isp116x->addr_reg = (u16*)((ISP116X_HCD_ADDR - 0x4000) + ((val & 0x0000ff00)>>7));
+ dumm = __raw_readw(isp116x->addr_reg);
+ isp116x_delay(isp116x, UDELAY);
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + ((val & 0x00ff0000)>>15));
+ dumm = __raw_readw(isp116x->data_reg);
+ isp116x->addr_reg = (u16*)((ISP116X_HCD_ADDR - 0x4000) + ((val & 0xff000000)>>23) );
+ dumm = __raw_readw(isp116x->addr_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+/***********************************************/
+
+static inline unsigned long isp116x_read_data32(struct isp116x *isp116x)
+{
+ unsigned long val;
+
+ val = (unsigned long) readw(isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+ val |= ((unsigned long) readw(isp116x->data_reg)) << 16;
+ isp116x_delay(isp116x, UDELAY);
+
+ return val;
+}
+
+/*
+ * Added for NetUSBee, to read HC registers without swapping them
+ * NetUSBee already swap them by hardware (i suppose.....)
+ */
+static inline unsigned long isp116x_raw_read_data32(struct isp116x *isp116x)
+{
+ unsigned long val;
+
+ isp116x->data_reg = (u16*)(ISP116X_HCD_DATA + 0x8000);
+ val = (u32) __raw_readw(isp116x->data_reg );
+ isp116x_delay(isp116x, UDELAY);
+ val |= ((u32) __raw_readw(isp116x->data_reg )) << 16;
+ isp116x_delay(isp116x, UDELAY);
+
+ return val;
+}
+/*******************************************************************/
+
+/* Let's keep register access functions out of line. Hint:
+ we wait at least 150 ns at every access.
+*/
+
+/* with NetUSBee use raw_read to avoid swapping bytes*/
+
+static unsigned short isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+ isp116x_write_addr(isp116x, reg);
+ return isp116x_raw_read_data16(isp116x);
+}
+
+static unsigned long isp116x_read_reg32(struct isp116x *isp116x, unsigned long reg)
+{
+ isp116x_write_addr(isp116x, reg);
+ return isp116x_raw_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+ unsigned val)
+{
+ isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+ isp116x_raw_write_data16(isp116x, (unsigned short) (val & 0xffff));
+}
+
+/* with NetUSBee used raw_write to avoid swapping bytes by software */
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned long reg,
+ unsigned long val)
+{
+ isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+ isp116x_raw_write_data32(isp116x, (unsigned long) val);
+}
+
+/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+#endif /* _NETUSBEE_ISP116X_H */
Index: sys/usb/src.km/ucd/netusbee/netusbee_int.S
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/netusbee_int.S
@@ -0,0 +1,112 @@
+/*
+ * NetUSBee USB driver for FreeMiNT.
+ * Modified for USB by David Galvez. 2010 - 2011
+ *
+ * This file belongs to FreeMiNT. It's not in the original MiNT 1.12
+ * distribution. See the file CHANGES for a detailed log of changes.
+ *
+ * Copyright (c) 2007 Henrik Gilda.
+ *
+ * This file 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, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Low level and interrupt routines for the NetUSBee driver
+ *
+ * 2005-02-12 Henrik Gilda
+ * 2000-08-02 Frank Naumann
+ * 2000-03-24 Vassilis Papathanassiou
+ *
+ *
+ */
+
+//#define RESMAGIC 0x31415926
+//#define _resvalid 0x426
+//#define _resvector 0x42a
+
+
+// .globl _netusbee_int
+ .globl _set_old_int_lvl
+ .globl _set_int_lvl5
+ .globl _set_int_lvl6
+ .globl _set_int_lvl7
+ .globl _old_200Hz_int
+ .globl _interrupt_200Hz
+
+
+
+ .text
+#if 0
+ dc.l 0x58425241 | XBRA
+ dc.l 0x00000000 | (no cookie)
+_old_200Hz_int:
+ ds.l 1
+_interrupt_200Hz:
+ move.w (sp),oldSR
+ movem.l a0-a7/d0-d7,-(sp)
+ bsr _netusbee_int
+ movem.l (sp)+,a0-a7/d0-d7
+ move.l _old_200Hz_int(PC),-(sp) |jump through old handler
+ rts
+
+#endif
+
+oldSR: ds.w 1
+
+// Sets interrupt level to what was in the SR
+_set_old_int_lvl:
+// move.w (sp),oldSR
+ andi.w #0x0f00,oldSR //just keep the int lvl
+ move.l d0,-(sp)
+ move.w sr,d0
+ andi.w #0xf0ff,d0
+ or.w oldSR,d0
+ move.w d0,sr
+ move.l (sp)+,d0
+ rts
+
+// Sets interrupt level to 5
+_set_int_lvl5:
+ move.w d0,-(sp)
+ move.w sr,d0
+ move.w d0,oldSR
+ andi.w #0xf0ff,d0
+ ori.w #0x0500,d0
+ move.w d0,sr
+ move.w (sp)+,d0
+ rts
+
+// Sets interrupt level to 6
+_set_int_lvl6:
+ move.w d0,-(sp)
+ move.w sr,d0
+ move.w d0,oldSR
+ andi.w #0xf0ff,d0
+ ori.w #0x0600,d0
+ move.w d0,sr
+ move.w (sp)+,d0
+ rts
+
+// Sets interrupt level to 7
+_set_int_lvl7:
+ move.w d0,-(sp)
+ move.w sr,d0
+ move.w d0,oldSR
+ andi.w #0xf0ff,d0
+ ori.w #0x0700,d0
+ move.w d0,sr
+ move.w (sp)+,d0
+ rts
+
+
Index: sys/usb/src.km/ucd/netusbee/netusbee_int.h
--- /dev/null
+++ sys/usb/src.km/ucd/netusbee/netusbee_int.h
@@ -0,0 +1,40 @@
+/*
+ * NetUSBee USB driver for FreeMiNT.
+ * Modified for USB by David Galvez. 2010 - 2011
+ *
+ * This file belongs to FreeMiNT. It's not in the original MiNT 1.12
+ * distribution. See the file CHANGES for a detailed log of changes.
+ *
+ * Copyright (c) 2007 Henrik Gilda
+ *
+ * This file 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, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _netusbee_int_h
+#define _netusbee_int_h
+
+
+// old handler
+extern void (*old_200Hz_int)(void);
+
+// interrupt wrapper routine
+void interrupt_200Hz(void);
+
+void set_old_int_lvl(void);
+void set_int_lvl5(void);
+void set_int_lvl6(void);
+void set_int_lvl7(void);
+
+#endif // _netusbee_int_h