This is a multi-part message in MIME format.

------=_NextPart_000_004D_01C4C57D.B68E9D00
Content-Type: text/plain;
	charset="us-ascii"
Content-Transfer-Encoding: 7bit

Move drivers from arch/cris/arch-v10/drivers/ to drivers/.

Signed-off-by: Mikael Starvik <starvik@axis.com>

------=_NextPart_000_004D_01C4C57D.B68E9D00
Content-Type: application/octet-stream;
	name="cris269_8.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="cris269_8.patch"

modif/arch/cris/arch-v10/drivers/ethernet.c=0A=
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 /dev/null                             |12837 ----------------------------------
 25-akpm/drivers/ide/cris/ide-v10.c    |  940 ++
 25-akpm/drivers/net/cris/eth_v10.c    | 1836 ++++
 25-akpm/drivers/serial/crisv10.c      | 5061 +++++++++++++
 25-akpm/drivers/serial/crisv10.h      |  137 
 25-akpm/drivers/usb/host/hc_crisv10.c | 4574 ++++++++++++
 25-akpm/drivers/usb/host/hc_crisv10.h |  289 
 7 files changed, 12837 insertions(+), 12837 deletions(-)

diff -L arch/cris/arch-v10/drivers/ethernet.c -puN arch/cris/arch-v10/drivers/ethernet.c~cris-architecture-update-move-drivers /dev/null
--- 25/arch/cris/arch-v10/drivers/ethernet.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,1836 +0,0 @@
-/* $Id: ethernet.c,v 1.31 2004/10/18 14:49:03 starvik Exp $
- *
- * e100net.c: A network driver for the ETRAX 100LX network controller.
- *
- * Copyright (c) 1998-2002 Axis Communications AB.
- *
- * The outline of this driver comes from skeleton.c.
- *
- * $Log: ethernet.c,v $
- * Revision 1.31  2004/10/18 14:49:03  starvik
- * Use RX interrupt as random source
- *
- * Revision 1.30  2004/09/29 10:44:04  starvik
- * Enabed MAC-address output again
- *
- * Revision 1.29  2004/08/24 07:14:05  starvik
- * Make use of generic MDIO interface and constants.
- *
- * Revision 1.28  2004/08/20 09:37:11  starvik
- * Added support for Intel LXT972A. Creds to Randy Scarborough.
- *
- * Revision 1.27  2004/08/16 12:37:22  starvik
- * Merge of Linux 2.6.8
- *
- * Revision 1.25  2004/06/21 10:29:57  starvik
- * Merge of Linux 2.6.7
- *
- * Revision 1.23  2004/06/09 05:29:22  starvik
- * Avoid any race where R_DMA_CH1_FIRST is NULL (may trigger cache bug).
- *
- * Revision 1.22  2004/05/14 07:58:03  starvik
- * Merge of changes from 2.4
- *
- * Revision 1.20  2004/03/11 11:38:40  starvik
- * Merge of Linux 2.6.4
- *
- * Revision 1.18  2003/12/03 13:45:46  starvik
- * Use hardware pad for short packets to prevent information leakage.
- *
- * Revision 1.17  2003/07/04 08:27:37  starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.16  2003/04/24 08:28:22  starvik
- * New LED behaviour: LED off when no link
- *
- * Revision 1.15  2003/04/09 05:20:47  starvik
- * Merge of Linux 2.5.67
- *
- * Revision 1.13  2003/03/06 16:11:01  henriken
- * Off by one error in group address register setting.
- *
- * Revision 1.12  2003/02/27 17:24:19  starvik
- * Corrected Rev to Revision
- *
- * Revision 1.11  2003/01/24 09:53:21  starvik
- * Oops. Initialize GA to 0, not to 1
- *
- * Revision 1.10  2003/01/24 09:50:55  starvik
- * Initialize GA_0 and GA_1 to 0 to avoid matching of unwanted packets
- *
- * Revision 1.9  2002/12/13 07:40:58  starvik
- * Added basic ethtool interface
- * Handled out of memory when allocating new buffers
- *
- * Revision 1.8  2002/12/11 13:13:57  starvik
- * Added arch/ to v10 specific includes
- * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
- *
- * Revision 1.7  2002/11/26 09:41:42  starvik
- * Added e100_set_config (standard interface to set media type)
- * Added protection against preemptive scheduling
- * Added standard MII ioctls
- *
- * Revision 1.6  2002/11/21 07:18:18  starvik
- * Timers must be initialized in 2.5.48
- *
- * Revision 1.5  2002/11/20 11:56:11  starvik
- * Merge of Linux 2.5.48
- *
- * Revision 1.4  2002/11/18 07:26:46  starvik
- * Linux 2.5 port of latest Linux 2.4 ethernet driver
- *
- * Revision 1.33  2002/10/02 20:16:17  hp
- * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
- *
- * Revision 1.32  2002/09/16 06:05:58  starvik
- * Align memory returned by dev_alloc_skb
- * Moved handling of sent packets to interrupt to avoid reference counting problem
- *
- * Revision 1.31  2002/09/10 13:28:23  larsv
- * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
- * for supported functionality by issuing special ioctls, i.e. wireless
- * extensions.
- *
- * Revision 1.30  2002/05/07 18:50:08  johana
- * Correct spelling in comments.
- *
- * Revision 1.29  2002/05/06 05:38:49  starvik
- * Performance improvements:
- *    Large packets are not copied (breakpoint set to 256 bytes)
- *    The cache bug workaround is delayed until half of the receive list
- *      has been used
- *    Added transmit list
- *    Transmit interrupts are only enabled when transmit queue is full
- *
- * Revision 1.28.2.1  2002/04/30 08:15:51  starvik
- * Performance improvements:
- *   Large packets are not copied (breakpoint set to 256 bytes)
- *   The cache bug workaround is delayed until half of the receive list
- *     has been used.
- *   Added transmit list
- *   Transmit interrupts are only enabled when transmit queue is full
- *
- * Revision 1.28  2002/04/22 11:47:21  johana
- * Fix according to 2.4.19-pre7. time_after/time_before and
- * missing end of comment.
- * The patch has a typo for ethernet.c in e100_clear_network_leds(),
- *  that is fixed here.
- *
- * Revision 1.27  2002/04/12 11:55:11  bjornw
- * Added TODO
- *
- * Revision 1.26  2002/03/15 17:11:02  bjornw
- * Use prepare_rx_descriptor after the CPU has touched the receiving descs
- *
- * Revision 1.25  2002/03/08 13:07:53  bjornw
- * Unnecessary spinlock removed
- *
- * Revision 1.24  2002/02/20 12:57:43  fredriks
- * Replaced MIN() with min().
- *
- * Revision 1.23  2002/02/20 10:58:14  fredriks
- * Strip the Ethernet checksum (4 bytes) before forwarding a frame to upper layers.
- *
- * Revision 1.22  2002/01/30 07:48:22  matsfg
- * Initiate R_NETWORK_TR_CTRL
- *
- * Revision 1.21  2001/11/23 11:54:49  starvik
- * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list
- * Removed compiler warnings
- *
- * Revision 1.20  2001/11/12 19:26:00  pkj
- * * Corrected e100_negotiate() to not assign half to current_duplex when
- *   it was supposed to compare them...
- * * Cleaned up failure handling in e100_open().
- * * Fixed compiler warnings.
- *
- * Revision 1.19  2001/11/09 07:43:09  starvik
- * Added full duplex support
- * Added ioctl to set speed and duplex
- * Clear LED timer only runs when LED is lit
- *
- * Revision 1.18  2001/10/03 14:40:43  jonashg
- * Update rx_bytes counter.
- *
- * Revision 1.17  2001/06/11 12:43:46  olof
- * Modified defines for network LED behavior
- *
- * Revision 1.16  2001/05/30 06:12:46  markusl
- * TxDesc.next should not be set to NULL
- *
- * Revision 1.15  2001/05/29 10:27:04  markusl
- * Updated after review remarks:
- * +Use IO_EXTRACT
- * +Handle underrun
- *
- * Revision 1.14  2001/05/29 09:20:14  jonashg
- * Use driver name on printk output so one can tell which driver that complains.
- *
- * Revision 1.13  2001/05/09 12:35:59  johana
- * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
- *
- * Revision 1.12  2001/04/05 11:43:11  tobiasa
- * Check dev before panic.
- *
- * Revision 1.11  2001/04/04 11:21:05  markusl
- * Updated according to review remarks
- *
- * Revision 1.10  2001/03/26 16:03:06  bjornw
- * Needs linux/config.h
- *
- * Revision 1.9  2001/03/19 14:47:48  pkj
- * * Make sure there is always a pause after the network LEDs are
- *   changed so they will not look constantly lit during heavy traffic.
- * * Always use HZ when setting times relative to jiffies.
- * * Use LED_NETWORK_SET() when setting the network LEDs.
- *
- * Revision 1.8  2001/02/27 13:52:48  bjornw
- * malloc.h -> slab.h
- *
- * Revision 1.7  2001/02/23 13:46:38  bjornw
- * Spellling check
- *
- * Revision 1.6  2001/01/26 15:21:04  starvik
- * Don't disable interrupts while reading MDIO registers (MDIO is slow)
- * Corrected promiscuous mode
- * Improved deallocation of IRQs ("ifconfig eth0 down" now works)
- *
- * Revision 1.5  2000/11/29 17:22:22  bjornw
- * Get rid of the udword types legacy stuff
- *
- * Revision 1.4  2000/11/22 16:36:09  bjornw
- * Please marketing by using the correct case when spelling Etrax.
- *
- * Revision 1.3  2000/11/21 16:43:04  bjornw
- * Minor short->int change
- *
- * Revision 1.2  2000/11/08 14:27:57  bjornw
- * 2.4 port
- *
- * Revision 1.1  2000/11/06 13:56:00  bjornw
- * Verbatim copy of the 1.24 version of e100net.c from elinux
- *
- * Revision 1.24  2000/10/04 15:55:23  bjornw
- * * Use virt_to_phys etc. for DMA addresses
- * * Removed bogus CHECKSUM_UNNECESSARY
- *
- *
- */
-
-#include <linux/config.h>
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <linux/if.h>
-#include <linux/mii.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-
-#include <asm/arch/svinto.h>/* DMA and register descriptions */
-#include <asm/io.h>         /* LED_* I/O functions */
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/ethernet.h>
-#include <asm/cache.h>
-
-//#define ETHDEBUG
-#define D(x)
-
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-
-static const char* cardname = "ETRAX 100LX built-in ethernet controller";
-
-/* A default ethernet address. Highlevel SW will set the real one later */
-
-static struct sockaddr default_mac = {
-	0,
-	{ 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
-};
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	struct net_device_stats stats;
-	struct mii_if_info mii_if;
-
-	/* Tx control lock.  This protects the transmit buffer ring
-	 * state along with the "tx full" state of the driver.  This
-	 * means all netif_queue flow control actions are protected
-	 * by this lock as well.
-	 */
-	spinlock_t lock;
-};
-
-typedef struct etrax_eth_descr
-{
-	etrax_dma_descr descr;
-	struct sk_buff* skb;
-} etrax_eth_descr;
-
-/* Some transceivers requires special handling */
-struct transceiver_ops
-{
-	unsigned int oui;
-	void (*check_speed)(struct net_device* dev);
-	void (*check_duplex)(struct net_device* dev);
-};
-
-struct transceiver_ops* transceiver;
-
-/* Duplex settings */
-enum duplex
-{
-	half,
-	full,
-	autoneg
-};
-
-/* Dma descriptors etc. */
-
-#define MAX_MEDIA_DATA_SIZE 1518
-
-#define MIN_PACKET_LEN      46
-#define ETHER_HEAD_LEN      14
-
-/* 
-** MDIO constants.
-*/
-#define MDIO_START                          0x1
-#define MDIO_READ                           0x2
-#define MDIO_WRITE                          0x1
-#define MDIO_PREAMBLE              0xfffffffful
-
-/* Broadcom specific */
-#define MDIO_AUX_CTRL_STATUS_REG           0x18
-#define MDIO_BC_FULL_DUPLEX_IND             0x1
-#define MDIO_BC_SPEED                       0x2
-
-/* TDK specific */
-#define MDIO_TDK_DIAGNOSTIC_REG              18
-#define MDIO_TDK_DIAGNOSTIC_RATE          0x400
-#define MDIO_TDK_DIAGNOSTIC_DPLX          0x800
-
-/*Intel LXT972A specific*/
-#define MDIO_INT_STATUS_REG_2			0x0011
-#define MDIO_INT_FULL_DUPLEX_IND		( 1 << 9 )
-#define MDIO_INT_SPEED				( 1 << 14 )
-
-/* Network flash constants */
-#define NET_FLASH_TIME                  (HZ/50) /* 20 ms */
-#define NET_FLASH_PAUSE                (HZ/100) /* 10 ms */
-#define NET_LINK_UP_CHECK_INTERVAL       (2*HZ) /* 2 s   */
-#define NET_DUPLEX_CHECK_INTERVAL        (2*HZ) /* 2 s   */
-
-#define NO_NETWORK_ACTIVITY 0
-#define NETWORK_ACTIVITY    1
-
-#define NBR_OF_RX_DESC     64
-#define NBR_OF_TX_DESC     256
-
-/* Large packets are sent directly to upper layers while small packets are */
-/* copied (to reduce memory waste). The following constant decides the breakpoint */
-#define RX_COPYBREAK 256
-
-/* Due to a chip bug we need to flush the cache when descriptors are returned */
-/* to the DMA. To decrease performance impact we return descriptors in chunks. */
-/* The following constant determines the number of descriptors to return. */
-#define RX_QUEUE_THRESHOLD  NBR_OF_RX_DESC/2
-
-#define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
-
-/* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
-					  IO_FIELD_(reg##_, field##_, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
-					  IO_STATE_(reg##_, field##_, _##val)
-
-static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
-                                          to be processed */
-static etrax_eth_descr *myLastRxDesc;  /* The last processed descriptor */
-static etrax_eth_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
-
-static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
-
-static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */
-static etrax_eth_descr* myLastTxDesc;  /* End of send queue */
-static etrax_eth_descr* myNextTxDesc;  /* Next descriptor to use */
-static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
-
-static unsigned int network_rec_config_shadow = 0;
-static unsigned int mdio_phy_addr; /* Transciever address */
-
-static unsigned int network_tr_ctrl_shadow = 0;
-
-/* Network speed indication. */
-static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0);
-static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0);
-static int current_speed; /* Speed read from transceiver */
-static int current_speed_selection; /* Speed selected by user */
-static unsigned long led_next_time;
-static int led_active;
-static int rx_queue_len;
-
-/* Duplex */
-static struct timer_list duplex_timer = TIMER_INITIALIZER(NULL, 0, 0);
-static int full_duplex;
-static enum duplex current_duplex;
-
-/* Index to functions, as function prototypes. */
-
-static int etrax_ethernet_init(void);
-
-static int e100_open(struct net_device *dev);
-static int e100_set_mac_address(struct net_device *dev, void *addr);
-static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void e100_rx(struct net_device *dev);
-static int e100_close(struct net_device *dev);
-static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
-static int e100_set_config(struct net_device* dev, struct ifmap* map);
-static void e100_tx_timeout(struct net_device *dev);
-static struct net_device_stats *e100_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void e100_hardware_send_packet(char *buf, int length);
-static void update_rx_stats(struct net_device_stats *);
-static void update_tx_stats(struct net_device_stats *);
-static int e100_probe_transceiver(struct net_device* dev);
-
-static void e100_check_speed(unsigned long priv);
-static void e100_set_speed(struct net_device* dev, unsigned long speed);
-static void e100_check_duplex(unsigned long priv);
-static void e100_set_duplex(struct net_device* dev, enum duplex);
-static void e100_negotiate(struct net_device* dev);
-
-static int e100_get_mdio_reg(struct net_device *dev, int phy_id, int location);
-static void e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value);
-
-static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
-static void e100_send_mdio_bit(unsigned char bit);
-static unsigned char e100_receive_mdio_bit(void);
-static void e100_reset_transceiver(struct net_device* net);
-
-static void e100_clear_network_leds(unsigned long dummy);
-static void e100_set_network_leds(int active);
-
-static void broadcom_check_speed(struct net_device* dev);
-static void broadcom_check_duplex(struct net_device* dev);
-static void tdk_check_speed(struct net_device* dev);
-static void tdk_check_duplex(struct net_device* dev);
-static void intel_check_speed(struct net_device* dev);
-static void intel_check_duplex(struct net_device* dev);
-static void generic_check_speed(struct net_device* dev);
-static void generic_check_duplex(struct net_device* dev);
-
-struct transceiver_ops transceivers[] =
-{
-	{0x1018, broadcom_check_speed, broadcom_check_duplex},  /* Broadcom */
-	{0xC039, tdk_check_speed, tdk_check_duplex},            /* TDK 2120 */
-	{0x039C, tdk_check_speed, tdk_check_duplex},            /* TDK 2120C */
-        {0x04de, intel_check_speed, intel_check_duplex},     	/* Intel LXT972A*/
-	{0x0000, generic_check_speed, generic_check_duplex}     /* Generic, must be last */
-};
-
-#define tx_done(dev) (*R_DMA_CH0_CMD == 0)
-
-/*
- * Check for a network adaptor of this type, and return '0' if one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
- */
-
-static int __init
-etrax_ethernet_init(void)
-{
-	struct net_device *dev;
-        struct net_local* np;
-	int i, err;
-
-	printk(KERN_INFO
-	       "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
-
-	dev = alloc_etherdev(sizeof(struct net_local));
-	np = dev->priv;
-
-	if (!dev)
-		return -ENOMEM;
-
-	dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */	
-
-	/* now setup our etrax specific stuff */
-
-	dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */
-	dev->dma = NETWORK_RX_DMA_NBR;
-
-	/* fill in our handlers so the network layer can talk to us in the future */
-
-	dev->open               = e100_open;
-	dev->hard_start_xmit    = e100_send_packet;
-	dev->stop               = e100_close;
-	dev->get_stats          = e100_get_stats;
-	dev->set_multicast_list = set_multicast_list;
-	dev->set_mac_address    = e100_set_mac_address;
-	dev->do_ioctl           = e100_ioctl;
-	dev->set_config		= e100_set_config;
-	dev->tx_timeout         = e100_tx_timeout;
-
-	/* Initialise the list of Etrax DMA-descriptors */
-
-	/* Initialise receive descriptors */
-
-	for (i = 0; i < NBR_OF_RX_DESC; i++) {
-		/* Allocate two extra cachelines to make sure that buffer used by DMA
-		 * does not share cacheline with any other data (to avoid cache bug)
-		 */
-		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
-		RxDescList[i].descr.ctrl   = 0;
-		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
-		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
-		RxDescList[i].descr.status = 0;
-		RxDescList[i].descr.hw_len = 0;             
-		prepare_rx_descriptor(&RxDescList[i].descr);
-	}
-
-	RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl   = d_eol;
-	RxDescList[NBR_OF_RX_DESC - 1].descr.next   = virt_to_phys(&RxDescList[0]);
-	rx_queue_len = 0;
-
-	/* Initialize transmit descriptors */
-	for (i = 0; i < NBR_OF_TX_DESC; i++) {
-		TxDescList[i].descr.ctrl   = 0;
-		TxDescList[i].descr.sw_len = 0;
-		TxDescList[i].descr.next   = virt_to_phys(&TxDescList[i + 1].descr);
-		TxDescList[i].descr.buf    = 0;
-		TxDescList[i].descr.status = 0;
-		TxDescList[i].descr.hw_len = 0;
-		TxDescList[i].skb = 0;
-	}
-
-	TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl   = d_eol;
-	TxDescList[NBR_OF_TX_DESC - 1].descr.next   = virt_to_phys(&TxDescList[0].descr);
-        
-	/* Initialise initial pointers */
-
-	myNextRxDesc  = &RxDescList[0];
-	myLastRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
-	myPrevRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
-	myFirstTxDesc = &TxDescList[0];
-	myNextTxDesc  = &TxDescList[0];
-	myLastTxDesc  = &TxDescList[NBR_OF_TX_DESC - 1];
-
-	/* Register device */
-	err = register_netdev(dev);
-	if (err) {
-		free_netdev(dev);
-		return err;
-	}
-
-	/* set the default MAC address */
-
-	e100_set_mac_address(dev, &default_mac);
-
-	/* Initialize speed indicator stuff. */
-
-	current_speed = 10;
-	current_speed_selection = 0; /* Auto */
-	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
-        duplex_timer.data = (unsigned long)dev;
-	speed_timer.function = e100_check_speed;
-        
-	clear_led_timer.function = e100_clear_network_leds;
-        
-	full_duplex = 0;
-	current_duplex = autoneg;
-	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;		
-        duplex_timer.data = (unsigned long)dev;
-	duplex_timer.function = e100_check_duplex;
-
-        /* Initialize mii interface */
-	np->mii_if.phy_id = mdio_phy_addr;
-	np->mii_if.phy_id_mask = 0x1f;
-	np->mii_if.reg_num_mask = 0x1f;
-	np->mii_if.dev = dev;
-	np->mii_if.mdio_read = e100_get_mdio_reg;
-	np->mii_if.mdio_write = e100_set_mdio_reg;
-
-	/* Initialize group address registers to make sure that no */
-	/* unwanted addresses are matched */
-	*R_NETWORK_GA_0 = 0x00000000;
-	*R_NETWORK_GA_1 = 0x00000000;
-	return 0;
-}
-
-/* set MAC address of the interface. called from the core after a
- * SIOCSIFADDR ioctl, and from the bootup above.
- */
-
-static int
-e100_set_mac_address(struct net_device *dev, void *p)
-{
-	struct net_local *np = (struct net_local *)dev->priv;
-	struct sockaddr *addr = p;
-	int i;
-
-	spin_lock(&np->lock); /* preemption protection */
-
-	/* remember it */
-
-	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-
-	/* Write it to the hardware.
-	 * Note the way the address is wrapped:
-	 * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24);
-	 * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8);
-	 */
-	
-	*R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
-		(dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
-	*R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
-	*R_NETWORK_SA_2 = 0;
-
-	/* show it in the log as well */
-
-	printk(KERN_INFO "%s: changed MAC to ", dev->name);
-
-	for (i = 0; i < 5; i++)
-		printk("%02X:", dev->dev_addr[i]);
-
-	printk("%02X\n", dev->dev_addr[i]);
-
-	spin_unlock(&np->lock);
-
-	return 0;
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-
-static int
-e100_open(struct net_device *dev)
-{
-	unsigned long flags;
-
-	/* enable the MDIO output pin */
-
-	*R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable);
-
-	*R_IRQ_MASK0_CLR =
-		IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
-		IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
-		IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
-	
-	/* clear dma0 and 1 eop and descr irq masks */
-	*R_IRQ_MASK2_CLR =
-		IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
-		IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
-		IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
-		IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
-
-	/* Reset and wait for the DMA channels */
-
-	RESET_DMA(NETWORK_TX_DMA_NBR);
-	RESET_DMA(NETWORK_RX_DMA_NBR);
-	WAIT_DMA(NETWORK_TX_DMA_NBR);
-	WAIT_DMA(NETWORK_RX_DMA_NBR);
-
-	/* Initialise the etrax network controller */
-
-	/* allocate the irq corresponding to the receiving DMA */
-
-	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt,
-			SA_SAMPLE_RANDOM, cardname, (void *)dev)) {
-		goto grace_exit0;
-	}
-
-	/* allocate the irq corresponding to the transmitting DMA */
-
-	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
-			cardname, (void *)dev)) {
-		goto grace_exit1;
-	}
-
-	/* allocate the irq corresponding to the network errors etc */
-
-	if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0,
-			cardname, (void *)dev)) {
-		goto grace_exit2;
-	}
-
-	/* give the HW an idea of what MAC address we want */
-
-	*R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
-		(dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
-	*R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
-	*R_NETWORK_SA_2 = 0;
-
-#if 0
-	/* use promiscuous mode for testing */
-	*R_NETWORK_GA_0 = 0xffffffff;
-	*R_NETWORK_GA_1 = 0xffffffff;
-
-	*R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
-#else
-	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
-	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
-	SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
-	*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
-#endif
-
-	*R_NETWORK_GEN_CONFIG =
-		IO_STATE(R_NETWORK_GEN_CONFIG, phy,    mii_clk) |
-		IO_STATE(R_NETWORK_GEN_CONFIG, enable, on);
-
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none);
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont);
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable);
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable);
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable);
-	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
-	*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
-
-	save_flags(flags);
-	cli();
-
-	/* enable the irq's for ethernet DMA */
-
-	*R_IRQ_MASK2_SET =
-		IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
-		IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
-
-	*R_IRQ_MASK0_SET =
-		IO_STATE(R_IRQ_MASK0_SET, overrun,       set) |
-		IO_STATE(R_IRQ_MASK0_SET, underrun,      set) |
-		IO_STATE(R_IRQ_MASK0_SET, excessive_col, set);
-
-	/* make sure the irqs are cleared */
-
-	*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-	*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
-
-	/* make sure the rec and transmit error counters are cleared */
-
-	(void)*R_REC_COUNTERS;  /* dummy read */
-	(void)*R_TR_COUNTERS;   /* dummy read */
-
-	/* start the receiving DMA channel so we can receive packets from now on */
-
-	*R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc);
-	*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start);
-
-	/* Set up transmit DMA channel so it can be restarted later */
-        
-	*R_DMA_CH0_FIRST = 0;
-	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
-
-	restore_flags(flags);
-	
-	/* Probe for transceiver */
-	if (e100_probe_transceiver(dev))
-		goto grace_exit3;
-
-	/* Start duplex/speed timers */
-	add_timer(&speed_timer);
-	add_timer(&duplex_timer);
-
-	/* We are now ready to accept transmit requeusts from
-	 * the queueing layer of the networking.
-	 */
-	netif_start_queue(dev);
-
-	return 0;
-
-grace_exit3:
-	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
-grace_exit2:
-	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
-grace_exit1:
-	free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
-grace_exit0:
-	return -EAGAIN;
-}
-
-
-static void
-generic_check_speed(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
-	if ((data & ADVERTISE_100FULL) ||
-	    (data & ADVERTISE_100HALF))
-		current_speed = 100;
-	else
-		current_speed = 10;
-}
-
-static void
-tdk_check_speed(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
-	current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
-}
-
-static void
-broadcom_check_speed(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
-	current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
-}
-
-static void
-intel_check_speed(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
-	current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
-}
-
-static void
-e100_check_speed(unsigned long priv)
-{
-	struct net_device* dev = (struct net_device*)priv;
-	static int led_initiated = 0;
-	unsigned long data;
-	int old_speed = current_speed;
-
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR);
-	if (!(data & BMSR_LSTATUS)) {
-		current_speed = 0;
-	} else {
-		transceiver->check_speed(dev);
-	}
-	
-	if ((old_speed != current_speed) || !led_initiated) {
-		led_initiated = 1;
-		e100_set_network_leds(NO_NETWORK_ACTIVITY);
-	}
-
-	/* Reinitialize the timer. */
-	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
-	add_timer(&speed_timer);
-}
-
-static void
-e100_negotiate(struct net_device* dev)
-{
-	unsigned short data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
-
-	/* Discard old speed and duplex settings */
-	data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL |
-	          ADVERTISE_10HALF | ADVERTISE_10FULL);
-  
-	switch (current_speed_selection) {
-		case 10 :
-			if (current_duplex == full)
-				data |= ADVERTISE_10FULL;
-			else if (current_duplex == half)
-				data |= ADVERTISE_10HALF;
-			else
-				data |= ADVERTISE_10HALF | ADVERTISE_10FULL;
-			break;
-
-		case 100 :
-			 if (current_duplex == full)
-				data |= ADVERTISE_100FULL;
-			else if (current_duplex == half)
-				data |= ADVERTISE_100HALF;
-			else
-				data |= ADVERTISE_100HALF | ADVERTISE_100FULL;
-			break;
-
-		case 0 : /* Auto */
-			 if (current_duplex == full)
-				data |= ADVERTISE_100FULL | ADVERTISE_10FULL;
-			else if (current_duplex == half)
-				data |= ADVERTISE_100HALF | ADVERTISE_10HALF;
-			else
-				data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
-				  ADVERTISE_100HALF | ADVERTISE_100FULL;
-			break;
-
-		default : /* assume autoneg speed and duplex */
-			data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
-				  ADVERTISE_100HALF | ADVERTISE_100FULL;
-	}
-
-	e100_set_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE, data);
-
-	/* Renegotiate with link partner */
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
-	data |= BMCR_ANENABLE | BMCR_ANRESTART;
-
-	e100_set_mdio_reg(dev, mdio_phy_addr, MII_BMCR, data);
-}
-
-static void
-e100_set_speed(struct net_device* dev, unsigned long speed)
-{
-	if (speed != current_speed_selection) {
-		current_speed_selection = speed;
-		e100_negotiate(dev);
-	}
-}
-
-static void
-e100_check_duplex(unsigned long priv)
-{
-	struct net_device *dev = (struct net_device *)priv;
-	struct net_local *np = (struct net_local *)dev->priv;
-	int old_duplex = full_duplex;
-	transceiver->check_duplex(dev);
-	if (old_duplex != full_duplex) {
-		/* Duplex changed */
-		SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
-		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
-	}
-
-	/* Reinitialize the timer. */
-	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
-	add_timer(&duplex_timer);
-	np->mii_if.full_duplex = full_duplex;
-}
-
-static void
-generic_check_duplex(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
-	if ((data & ADVERTISE_10FULL) ||
-	    (data & ADVERTISE_100FULL))
-		full_duplex = 1;
-	else
-		full_duplex = 0;
-}
-
-static void
-tdk_check_duplex(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
-	full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
-}
-
-static void
-broadcom_check_duplex(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
-	full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
-}
-
-static void
-intel_check_duplex(struct net_device* dev)
-{
-	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
-	full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;
-}
-
-static void 
-e100_set_duplex(struct net_device* dev, enum duplex new_duplex)
-{
-	if (new_duplex != current_duplex) {
-		current_duplex = new_duplex;
-		e100_negotiate(dev);
-	}
-}
-
-static int
-e100_probe_transceiver(struct net_device* dev)
-{
-	unsigned int phyid_high;
-	unsigned int phyid_low;
-	unsigned int oui;
-	struct transceiver_ops* ops = NULL;
-
-	/* Probe MDIO physical address */
-	for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
-		if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 0xffff)
-			break;
-	}
-	if (mdio_phy_addr == 32)
-		 return -ENODEV;
-
-	/* Get manufacturer */
-	phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);
-	phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2);
-	oui = (phyid_high << 6) | (phyid_low >> 10);
-
-	for (ops = &transceivers[0]; ops->oui; ops++) {
-		if (ops->oui == oui)
-			break;
-	}
-	transceiver = ops;
-
-	return 0;
-}
-
-static int
-e100_get_mdio_reg(struct net_device *dev, int phy_id, int location)
-{
-	unsigned short cmd;    /* Data to be sent on MDIO port */
-	int data;   /* Data read from MDIO */
-	int bitCounter;
-	
-	/* Start of frame, OP Code, Physical Address, Register Address */
-	cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) |
-		(location << 2);
-	
-	e100_send_mdio_cmd(cmd, 0);
-	
-	data = 0;
-	
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		data |= (e100_receive_mdio_bit() << bitCounter);
-	}
-
-	return data;
-}
-
-static void
-e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value)
-{
-	int bitCounter;
-	unsigned short cmd;
-
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) |
-	      (location << 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, value));
-	}
-
-}
-
-static void
-e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
-{
-	int bitCounter;
-	unsigned char data = 0x2;
-	
-	/* Preamble */
-	for (bitCounter = 31; bitCounter>= 0; bitCounter--)
-		e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));
-
-	for (bitCounter = 15; bitCounter >= 2; bitCounter--)
-		e100_send_mdio_bit(GET_BIT(bitCounter, cmd));
-
-	/* Turnaround */
-	for (bitCounter = 1; bitCounter >= 0 ; bitCounter--)
-		if (write_cmd)
-			e100_send_mdio_bit(GET_BIT(bitCounter, data));
-		else
-			e100_receive_mdio_bit();
-}
-
-static void
-e100_send_mdio_bit(unsigned char bit)
-{
-	*R_NETWORK_MGM_CTRL =
-		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
-		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
-	udelay(1);
-	*R_NETWORK_MGM_CTRL =
-		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
-		IO_MASK(R_NETWORK_MGM_CTRL, mdck) |
-		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
-	udelay(1);
-}
-
-static unsigned char
-e100_receive_mdio_bit()
-{
-	unsigned char bit;
-	*R_NETWORK_MGM_CTRL = 0;
-	bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT);
-	udelay(1);
-	*R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck);
-	udelay(1);
-	return bit;
-}
-
-static void 
-e100_reset_transceiver(struct net_device* dev)
-{
-	unsigned short cmd;
-	unsigned short data;
-	int bitCounter;
-
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
-
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-	
-	data |= 0x8000;
-	
-	for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}
-}
-
-/* Called by upper layers if they decide it took too long to complete
- * sending a packet - we need to reset and stuff.
- */
-
-static void
-e100_tx_timeout(struct net_device *dev)
-{
-	struct net_local *np = (struct net_local *)dev->priv;
-	unsigned long flags;
-
-	spin_lock_irqsave(&np->lock, flags);
-
-	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
-	       tx_done(dev) ? "IRQ problem" : "network cable problem");
-	
-	/* remember we got an error */
-	
-	np->stats.tx_errors++; 
-	
-	/* reset the TX DMA in case it has hung on something */
-	
-	RESET_DMA(NETWORK_TX_DMA_NBR);
-	WAIT_DMA(NETWORK_TX_DMA_NBR);
-	
-	/* Reset the transceiver. */
-	
-	e100_reset_transceiver(dev);
-	
-	/* and get rid of the packets that never got an interrupt */
-	while (myFirstTxDesc != myNextTxDesc)
-	{
-		dev_kfree_skb(myFirstTxDesc->skb);
-		myFirstTxDesc->skb = 0;
-		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
-	}
-
-	/* Set up transmit DMA channel so it can be restarted later */
-	*R_DMA_CH0_FIRST = 0;
-	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);	
-
-	/* tell the upper layers we're ok again */
-	
-	netif_wake_queue(dev);
-	spin_unlock_irqrestore(&np->lock, flags);
-}
-
-
-/* This will only be invoked if the driver is _not_ in XOFF state.
- * What this means is that we need not check it, and that this
- * invariant will hold if we make sure that the netif_*_queue()
- * calls are done at the proper times.
- */
-
-static int
-e100_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *np = (struct net_local *)dev->priv;
-	unsigned char *buf = skb->data;
-	unsigned long flags;
-	
-#ifdef ETHDEBUG
-	printk("send packet len %d\n", length);
-#endif
-	spin_lock_irqsave(&np->lock, flags);  /* protect from tx_interrupt and ourself */
-
-	myNextTxDesc->skb = skb;
-
-	dev->trans_start = jiffies;
-	
-	e100_hardware_send_packet(buf, skb->len);
-
-	myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
-
-	/* Stop queue if full */
-	if (myNextTxDesc == myFirstTxDesc) {
-		netif_stop_queue(dev);
-	}
-
-	spin_unlock_irqrestore(&np->lock, flags);
-
-	return 0;
-}
-
-/*
- * The typical workload of the driver:
- *   Handle the network interface interrupts.
- */
-
-static irqreturn_t
-e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct net_local *np = (struct net_local *)dev->priv;
-	unsigned long irqbits = *R_IRQ_MASK2_RD;
- 
-	/* Disable RX/TX IRQs to avoid reentrancy */
-	*R_IRQ_MASK2_CLR =
-	  IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
-	  IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
-
-	/* Handle received packets */
-	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
-		/* acknowledge the eop interrupt */
-
-		*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
-
-		/* check if one or more complete packets were indeed received */
-
-		while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) &&
-		       (myNextRxDesc != myLastRxDesc)) {
-			/* Take out the buffer and give it to the OS, then
-			 * allocate a new buffer to put a packet in.
-			 */
-			e100_rx(dev);
-			((struct net_local *)dev->priv)->stats.rx_packets++;
-			/* restart/continue on the channel, for safety */
-			*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
-			/* clear dma channel 1 eop/descr irq bits */
-			*R_DMA_CH1_CLR_INTR =
-				IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) |
-				IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do);
-			
-			/* now, we might have gotten another packet
-			   so we have to loop back and check if so */
-		}
-	}
-
-	/* Report any packets that have been sent */
-	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-	       myFirstTxDesc != myNextTxDesc)
-	{
-		np->stats.tx_bytes += myFirstTxDesc->skb->len;
-		np->stats.tx_packets++;
-
-		/* dma is ready with the transmission of the data in tx_skb, so now
-		   we can release the skb memory */
-		dev_kfree_skb_irq(myFirstTxDesc->skb);
-		myFirstTxDesc->skb = 0;
-		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
-	}
-
-	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-		/* acknowledge the eop interrupt and wake up queue */
-		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-		netif_wake_queue(dev);
-	}
-
-	/* Enable RX/TX IRQs again */
-	*R_IRQ_MASK2_SET =
-	  IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t
-e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct net_local *np = (struct net_local *)dev->priv;
-	unsigned long irqbits = *R_IRQ_MASK0_RD;
-
-	/* check for underrun irq */
-	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { 
-		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
-		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
-		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
-		np->stats.tx_errors++;
-		D(printk("ethernet receiver underrun!\n"));
-	}
-
-	/* check for overrun irq */
-	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { 
-		update_rx_stats(&np->stats); /* this will ack the irq */
-		D(printk("ethernet receiver overrun!\n"));
-	}
-	/* check for excessive collision irq */
-	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { 
-		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
-		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
-		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
-		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
-		np->stats.tx_errors++;
-		D(printk("ethernet excessive collisions!\n"));
-	}
-	return IRQ_HANDLED;
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-e100_rx(struct net_device *dev)
-{
-	struct sk_buff *skb;
-	int length = 0;
-	struct net_local *np = (struct net_local *)dev->priv;
-	unsigned char *skb_data_ptr;
-#ifdef ETHDEBUG
-	int i;
-#endif
-
-	if (!led_active && time_after(jiffies, led_next_time)) {
-		/* light the network leds depending on the current speed. */
-		e100_set_network_leds(NETWORK_ACTIVITY);
-
-		/* Set the earliest time we may clear the LED */
-		led_next_time = jiffies + NET_FLASH_TIME;
-		led_active = 1;
-		mod_timer(&clear_led_timer, jiffies + HZ/10);
-	}
-
-	length = myNextRxDesc->descr.hw_len - 4;
-	((struct net_local *)dev->priv)->stats.rx_bytes += length;
-
-#ifdef ETHDEBUG
-	printk("Got a packet of length %d:\n", length);
-	/* dump the first bytes in the packet */
-	skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf);
-	for (i = 0; i < 8; i++) {
-		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
-		       skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
-		       skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
-		skb_data_ptr += 8;
-	}
-#endif
-
-	if (length < RX_COPYBREAK) {
-		/* Small packet, copy data */
-		skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
-		if (!skb) {
-			np->stats.rx_errors++;
-			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-			return;
-		}
-
-		skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
-		skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
-
-#ifdef ETHDEBUG
-		printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
-		  skb->head, skb->data, skb->tail, skb->end);
-		printk("copying packet to 0x%x.\n", skb_data_ptr);
-#endif
-          
-		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
-	}
-	else {
-		/* Large packet, send directly to upper layers and allocate new 
-		 * memory (aligned to cache line boundary to avoid bug).
-		 * Before sending the skb to upper layers we must make sure that 
-		 * skb->data points to the aligned start of the packet. 
-		 */
-		int align;  
-		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
-		if (!new_skb) {
-			np->stats.rx_errors++;
-			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-			return;
-		}
-		skb = myNextRxDesc->skb;
-		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;	
-		skb_put(skb, length + align); 
-		skb_pull(skb, align); /* Remove alignment bytes */
-		myNextRxDesc->skb = new_skb;
-		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
-	}
-
-	skb->dev = dev;
-	skb->protocol = eth_type_trans(skb, dev);
-
-	/* Send the packet to the upper layers */
-	netif_rx(skb);
-
-	/* Prepare for next packet */
-	myNextRxDesc->descr.status = 0;
-	myPrevRxDesc = myNextRxDesc;
-	myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
-
-	rx_queue_len++;
-
-	/* Check if descriptors should be returned */
-	if (rx_queue_len == RX_QUEUE_THRESHOLD) {
-		flush_etrax_cache();
-		myPrevRxDesc->descr.ctrl |= d_eol;
-		myLastRxDesc->descr.ctrl &= ~d_eol;
-		myLastRxDesc = myPrevRxDesc;
-		rx_queue_len = 0;
-	}
-}
-
-/* The inverse routine to net_open(). */
-static int
-e100_close(struct net_device *dev)
-{
-	struct net_local *np = (struct net_local *)dev->priv;
-
-	printk(KERN_INFO "Closing %s.\n", dev->name);
-
-	netif_stop_queue(dev);
-
-	*R_IRQ_MASK0_CLR =
-		IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
-		IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
-		IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
-	
-	*R_IRQ_MASK2_CLR =
-		IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
-		IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
-		IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
-		IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
-
-	/* Stop the receiver and the transmitter */
-
-	RESET_DMA(NETWORK_TX_DMA_NBR);
-	RESET_DMA(NETWORK_RX_DMA_NBR);
-
-	/* Flush the Tx and disable Rx here. */
-
-	free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
-	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
-	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
-
-	/* Update the statistics here. */
-
-	update_rx_stats(&np->stats);
-	update_tx_stats(&np->stats);
-
-	/* Stop speed/duplex timers */
-	del_timer(&speed_timer);
-	del_timer(&duplex_timer);
-
-	return 0;
-}
-
-static int
-e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct mii_ioctl_data *data = if_mii(ifr);
-	struct net_local *np = netdev_priv(dev);
-
-	spin_lock(&np->lock); /* Preempt protection */
-	switch (cmd) {
-		case SIOCETHTOOL:
-			return e100_ethtool_ioctl(dev,ifr);
-		case SIOCGMIIPHY: /* Get PHY address */
-			data->phy_id = mdio_phy_addr;
-			break;
-		case SIOCGMIIREG: /* Read MII register */
-			data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num);
-			break;
-		case SIOCSMIIREG: /* Write MII register */
-			e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in);
-			break;
-		/* The ioctls below should be considered obsolete but are */
-		/* still present for compatability with old scripts/apps  */	
-		case SET_ETH_SPEED_10:                  /* 10 Mbps */
-			e100_set_speed(dev, 10);
-			break;
-		case SET_ETH_SPEED_100:                /* 100 Mbps */
-			e100_set_speed(dev, 100);
-			break;
-		case SET_ETH_SPEED_AUTO:              /* Auto negotiate speed */
-			e100_set_speed(dev, 0);
-			break;
-		case SET_ETH_DUPLEX_HALF:              /* Half duplex. */
-			e100_set_duplex(dev, half);
-			break;
-		case SET_ETH_DUPLEX_FULL:              /* Full duplex. */
-			e100_set_duplex(dev, full);
-			break;
-		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
-			e100_set_duplex(dev, autoneg);
-			break;
-		default:
-			return -EINVAL;
-	}
-	spin_unlock(&np->lock);
-	return 0;
-}
-
-static int
-e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
-{
-	struct ethtool_cmd ecmd;
-
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
-		return -EFAULT;
-
-	switch (ecmd.cmd) {
-		case ETHTOOL_GSET:
-		{
-			memset((void *) &ecmd, 0, sizeof (ecmd));
-			ecmd.supported =
-			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
-			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
-			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
-			ecmd.port = PORT_TP;
-			ecmd.transceiver = XCVR_EXTERNAL;
-			ecmd.phy_address = mdio_phy_addr;
-			ecmd.speed = current_speed;
-			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-			ecmd.advertising = ADVERTISED_TP;
-			if (current_duplex == autoneg && current_speed_selection == 0)
-				ecmd.advertising |= ADVERTISED_Autoneg;
-			else {
-				ecmd.advertising |=
-				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
-				if (current_speed_selection == 10)
-					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
-				else if (current_speed_selection == 100)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
-				if (current_duplex == half)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
-				else if (current_duplex == full)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
-			}
-			ecmd.autoneg = AUTONEG_ENABLE;
-			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
-				return -EFAULT;
-		}
-		break;
-		case ETHTOOL_SSET:
-		{
-			if (!capable(CAP_NET_ADMIN)) {
-				return -EPERM;
-			}
-			if (ecmd.autoneg == AUTONEG_ENABLE) {
-				e100_set_duplex(dev, autoneg);
-				e100_set_speed(dev, 0);
-			} else {
-				e100_set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
-				e100_set_speed(dev, ecmd.speed == SPEED_10 ? 10: 100);
-			}
-		}
-		break;
-		case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info;
-			memset((void *) &info, 0, sizeof (info));
-			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
-			strncpy(info.version, "$Revision: 1.31 $", sizeof(info.version) - 1);
-			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
-			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
-			info.regdump_len = 0;
-			info.eedump_len = 0;
-			info.testinfo_len = 0;
-			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-				return -EFAULT;
-		}
-		break;
-		case ETHTOOL_NWAY_RST:
-			if (current_duplex == autoneg && current_speed_selection == 0)
-				e100_negotiate(dev);
-		break;
-		default:
-			return -EOPNOTSUPP;
-		break;
-	}
-	return 0;
-}
-
-static int
-e100_set_config(struct net_device *dev, struct ifmap *map)
-{
-	struct net_local *np = (struct net_local *)dev->priv;
-	spin_lock(&np->lock); /* Preempt protection */
-	
-	switch(map->port) {
-		case IF_PORT_UNKNOWN:
-			/* Use autoneg */
-			e100_set_speed(dev, 0);
-			e100_set_duplex(dev, autoneg);
-			break;
-		case IF_PORT_10BASET:
-			e100_set_speed(dev, 10);
-			e100_set_duplex(dev, autoneg);
-			break;
-		case IF_PORT_100BASET:
-		case IF_PORT_100BASETX:
-			e100_set_speed(dev, 100);
-			e100_set_duplex(dev, autoneg);
-			break;
-		case IF_PORT_100BASEFX:
-		case IF_PORT_10BASE2:
-		case IF_PORT_AUI:
-			spin_unlock(&np->lock);
-			return -EOPNOTSUPP;
-			break;
-		default:
-			printk(KERN_ERR "%s: Invalid media selected", dev->name);
-			spin_unlock(&np->lock);
-			return -EINVAL;
-	}
-	spin_unlock(&np->lock);
-	return 0;
-}
-
-static void
-update_rx_stats(struct net_device_stats *es)
-{
-	unsigned long r = *R_REC_COUNTERS;
-	/* update stats relevant to reception errors */
-	es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r);
-	es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r);
-	es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r);
-	es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r);
-}
-
-static void
-update_tx_stats(struct net_device_stats *es)
-{
-	unsigned long r = *R_TR_COUNTERS;
-	/* update stats relevant to transmission errors */
-	es->collisions +=
-		IO_EXTRACT(R_TR_COUNTERS, single_col, r) +
-		IO_EXTRACT(R_TR_COUNTERS, multiple_col, r);
-	es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);
-}
-
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *
-e100_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = (struct net_local *)dev->priv;
-	unsigned long flags;
-	spin_lock_irqsave(&lp->lock, flags);
-
-	update_rx_stats(&lp->stats);
-	update_tx_stats(&lp->stats);
-	
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return &lp->stats;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
-	struct net_local *lp = (struct net_local *)dev->priv;
-	int num_addr = dev->mc_count;
-	unsigned long int lo_bits;
-	unsigned long int hi_bits;
-	spin_lock(&lp->lock);
-	if (dev->flags & IFF_PROMISC)
-	{
-		/* promiscuous mode */
-		lo_bits = 0xfffffffful;
-		hi_bits = 0xfffffffful;
-
-		/* Enable individual receive */
-		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive);
-		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
-	} else if (dev->flags & IFF_ALLMULTI) {
-		/* enable all multicasts */
-		lo_bits = 0xfffffffful;
-		hi_bits = 0xfffffffful;
-
-		/* Disable individual receive */
-		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
-		*R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
-	} else if (num_addr == 0) {
-		/* Normal, clear the mc list */
-		lo_bits = 0x00000000ul;
-		hi_bits = 0x00000000ul;
-
-		/* Disable individual receive */
-		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
-		*R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
-	} else {
-		/* MC mode, receive normal and MC packets */
-		char hash_ix;
-		struct dev_mc_list *dmi = dev->mc_list;
-		int i;
-		char *baddr;
-		lo_bits = 0x00000000ul;
-		hi_bits = 0x00000000ul;
-		for (i=0; i<num_addr; i++) {
-			/* Calculate the hash index for the GA registers */
-			
-			hash_ix = 0;
-			baddr = dmi->dmi_addr;
-			hash_ix ^= (*baddr) & 0x3f;
-			hash_ix ^= ((*baddr) >> 6) & 0x03;
-			++baddr;
-			hash_ix ^= ((*baddr) << 2) & 0x03c;
-			hash_ix ^= ((*baddr) >> 4) & 0xf;
-			++baddr;
-			hash_ix ^= ((*baddr) << 4) & 0x30;
-			hash_ix ^= ((*baddr) >> 2) & 0x3f;
-			++baddr;
-			hash_ix ^= (*baddr) & 0x3f;
-			hash_ix ^= ((*baddr) >> 6) & 0x03;
-			++baddr;
-			hash_ix ^= ((*baddr) << 2) & 0x03c;
-			hash_ix ^= ((*baddr) >> 4) & 0xf;
-			++baddr;
-			hash_ix ^= ((*baddr) << 4) & 0x30;
-			hash_ix ^= ((*baddr) >> 2) & 0x3f;
-			
-			hash_ix &= 0x3f;
-			
-			if (hash_ix >= 32) {
-				hi_bits |= (1 << (hash_ix-32));
-			}
-			else {
-				lo_bits |= (1 << hash_ix);
-			}
-			dmi = dmi->next;
-		}
-		/* Disable individual receive */
-		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
-		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
-	}
-	*R_NETWORK_GA_0 = lo_bits;
-	*R_NETWORK_GA_1 = hi_bits;
-	spin_unlock(&lp->lock);
-}
-
-void
-e100_hardware_send_packet(char *buf, int length)
-{
-	D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
-
-	if (!led_active && time_after(jiffies, led_next_time)) {
-		/* light the network leds depending on the current speed. */
-		e100_set_network_leds(NETWORK_ACTIVITY);
-
-		/* Set the earliest time we may clear the LED */
-		led_next_time = jiffies + NET_FLASH_TIME;
-		led_active = 1;
-		mod_timer(&clear_led_timer, jiffies + HZ/10);
-	}
-
-	/* configure the tx dma descriptor */
-	myNextTxDesc->descr.sw_len = length;
-	myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait;
-	myNextTxDesc->descr.buf = virt_to_phys(buf);
-
-        /* Move end of list */
-        myLastTxDesc->descr.ctrl &= ~d_eol;
-        myLastTxDesc = myNextTxDesc;
-
-	/* Restart DMA channel */
-	*R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart);
-}
-
-static void
-e100_clear_network_leds(unsigned long dummy)
-{
-	if (led_active && time_after(jiffies, led_next_time)) {
-		e100_set_network_leds(NO_NETWORK_ACTIVITY);
-
-		/* Set the earliest time we may set the LED */
-		led_next_time = jiffies + NET_FLASH_PAUSE;
-		led_active = 0;
-	}
-}
-
-static void
-e100_set_network_leds(int active)
-{
-#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
-	int light_leds = (active == NO_NETWORK_ACTIVITY);
-#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
-	int light_leds = (active == NETWORK_ACTIVITY);
-#else
-#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
-#endif
-
-	if (!current_speed) {
-		/* Make LED red, link is down */
-#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
-		LED_NETWORK_SET(LED_RED);
-#else
-		LED_NETWORK_SET(LED_OFF);
-#endif
-	}
-	else if (light_leds) {
-		if (current_speed == 10) {
-			LED_NETWORK_SET(LED_ORANGE);
-		} else {
-			LED_NETWORK_SET(LED_GREEN);
-		}
-	}
-	else {
-		LED_NETWORK_SET(LED_OFF);
-	}
-}
-
-static int
-etrax_init_module(void)
-{
-	return etrax_ethernet_init();
-}
-
-static int __init
-e100_boot_setup(char* str)
-{
-	struct sockaddr sa = {0};
-	int i;
-
-	/* Parse the colon separated Ethernet station address */
-	for (i = 0; i <  ETH_ALEN; i++) {
-		unsigned int tmp;
-		if (sscanf(str + 3*i, "%2x", &tmp) != 1) {
-			printk(KERN_WARNING "Malformed station address");
-			return 0;
-		}
-		sa.sa_data[i] = (char)tmp;
-	}
-
-	default_mac = sa;
-	return 1;
-}
-
-__setup("etrax100_eth=", e100_boot_setup);
-
-module_init(etrax_init_module);
diff -L arch/cris/arch-v10/drivers/ide.c -puN arch/cris/arch-v10/drivers/ide.c~cris-architecture-update-move-drivers /dev/null
--- 25/arch/cris/arch-v10/drivers/ide.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,940 +0,0 @@
-/* $Id: ide.c,v 1.4 2004/10/12 07:55:48 starvik Exp $
- *
- * Etrax specific IDE functions, like init and PIO-mode setting etc.
- * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
- * Copyright (c) 2000-2004 Axis Communications AB
- *
- * Authors:    Bjorn Wesen        (initial version)
- *             Mikael Starvik     (pio setup stuff, Linux 2.6 port)
- */
-
-/* Regarding DMA:
- *
- * There are two forms of DMA - "DMA handshaking" between the interface and the drive,
- * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
- * something built-in in the Etrax. However only some drives support the DMA-mode handshaking
- * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
- * device can't do DMA handshaking for some stupid reason. We don't need to do that.
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/arch/svinto.h>
-#include <asm/dma.h>
-
-/* number of Etrax DMA descriptors */
-#define MAX_DMA_DESCRS 64
-
-/* number of times to retry busy-flags when reading/writing IDE-registers
- * this can't be too high because a hung harddisk might cause the watchdog
- * to trigger (sometimes INB and OUTB are called with irq's disabled)
- */
-
-#define IDE_REGISTER_TIMEOUT 300
-
-static int e100_read_command = 0;
-
-#define LOWDB(x)
-#define D(x)
-
-void
-etrax100_ide_outw(unsigned short data, unsigned long reg) {
-	int timeleft;
-	LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
-
-	/* note the lack of handling any timeouts. we stop waiting, but we don't
-	 * really notify anybody.
-	 */
-
-	timeleft = IDE_REGISTER_TIMEOUT;
-	/* wait for busy flag */
-	while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
-		timeleft--;
-
-	/*
-	 * Fall through at a timeout, so the ongoing command will be
-	 * aborted by the write below, which is expected to be a dummy
-	 * command to the command register.  This happens when a faulty
-	 * drive times out on a command.  See comment on timeout in
-	 * INB.
-	 */
-	if(!timeleft)
-		printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
-
-	*R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
-
-	timeleft = IDE_REGISTER_TIMEOUT;
-	/* wait for transmitter ready */
-	while(timeleft && !(*R_ATA_STATUS_DATA &
-			    IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
-		timeleft--;
-}
-
-void
-etrax100_ide_outb(unsigned char data, unsigned long reg)
-{
-	etrax100_ide_outw(data, reg);
-}
-
-void
-etrax100_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
-{
-	etrax100_ide_outw(addr, port);
-}
-
-unsigned short
-etrax100_ide_inw(unsigned long reg) {
-	int status;
-	int timeleft;
-
-	timeleft = IDE_REGISTER_TIMEOUT;
-	/* wait for busy flag */
-	while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
-		timeleft--;
-
-	if(!timeleft) {
-		/*
-		 * If we're asked to read the status register, like for
-		 * example when a command does not complete for an
-		 * extended time, but the ATA interface is stuck in a
-		 * busy state at the *ETRAX* ATA interface level (as has
-		 * happened repeatedly with at least one bad disk), then
-		 * the best thing to do is to pretend that we read
-		 * "busy" in the status register, so the IDE driver will
-		 * time-out, abort the ongoing command and perform a
-		 * reset sequence.  Note that the subsequent OUT_BYTE
-		 * call will also timeout on busy, but as long as the
-		 * write is still performed, everything will be fine.
-		 */
-		if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr))
-		    == IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET))
-			return BUSY_STAT;
-		else
-			/* For other rare cases we assume 0 is good enough.  */
-			return 0;
-	}
-
-	*R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
-
-	timeleft = IDE_REGISTER_TIMEOUT;
-	/* wait for available */
-	while(timeleft && !((status = *R_ATA_STATUS_DATA) &
-			    IO_MASK(R_ATA_STATUS_DATA, dav)))
-		timeleft--;
-
-	if(!timeleft)
-		return 0;
-
-	LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
-
-        return (unsigned short)status;
-}
-
-unsigned char
-etrax100_ide_inb(unsigned long reg)
-{
-	return (unsigned char)etrax100_ide_inw(reg);
-}
-
-/* PIO timing (in R_ATA_CONFIG)
- *
- *                        _____________________________
- * ADDRESS :     ________/
- *
- *                            _______________
- * DIOR    :     ____________/               \__________
- *
- *                               _______________
- * DATA    :     XXXXXXXXXXXXXXXX_______________XXXXXXXX
- *
- *
- * DIOR is unbuffered while address and data is buffered.
- * This creates two problems:
- * 1. The DIOR pulse is to early (because it is unbuffered)
- * 2. The rise time of DIOR is long
- *
- * There are at least three different plausible solutions
- * 1. Use a pad capable of larger currents in Etrax
- * 2. Use an external buffer
- * 3. Make the strobe pulse longer
- *
- * Some of the strobe timings below are modified to compensate
- * for this. This implies a slight performance decrease.
- *
- * THIS SHOULD NEVER BE CHANGED!
- *
- * TODO: Is this true for the latest LX boards still ?
- */
-
-#define ATA_DMA2_STROBE  4
-#define ATA_DMA2_HOLD    0
-#define ATA_DMA1_STROBE  4
-#define ATA_DMA1_HOLD    1
-#define ATA_DMA0_STROBE 12
-#define ATA_DMA0_HOLD    9
-#define ATA_PIO4_SETUP   1
-#define ATA_PIO4_STROBE  5
-#define ATA_PIO4_HOLD    0
-#define ATA_PIO3_SETUP   1
-#define ATA_PIO3_STROBE  5
-#define ATA_PIO3_HOLD    1
-#define ATA_PIO2_SETUP   1
-#define ATA_PIO2_STROBE  6
-#define ATA_PIO2_HOLD    2
-#define ATA_PIO1_SETUP   2
-#define ATA_PIO1_STROBE 11
-#define ATA_PIO1_HOLD    4
-#define ATA_PIO0_SETUP   4
-#define ATA_PIO0_STROBE 19
-#define ATA_PIO0_HOLD    4
-
-static int e100_dma_check (ide_drive_t *drive);
-static int e100_dma_begin (ide_drive_t *drive);
-static int e100_dma_end (ide_drive_t *drive);
-static int e100_dma_read (ide_drive_t *drive);
-static int e100_dma_write (ide_drive_t *drive);
-static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int);
-static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int);
-static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
-static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
-static int e100_dma_off (ide_drive_t *drive);
-static int e100_dma_verbose (ide_drive_t *drive);
-
-
-/*
- * good_dma_drives() lists the model names (from "hdparm -i")
- * of drives which do not support mword2 DMA but which are
- * known to work fine with this interface under Linux.
- */
-
-const char *good_dma_drives[] = {"Micropolis 2112A",
-				 "CONNER CTMA 4000",
-				 "CONNER CTT8000-A",
-				 NULL};
-
-static void tune_e100_ide(ide_drive_t *drive, byte pio)
-{
-	pio = 4;
-	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
-
-	/* set pio mode! */
-
-	switch(pio) {
-		case 0:
-			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO0_SETUP ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO0_HOLD ) );
-			break;
-		case 1:
-			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO1_SETUP ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO1_HOLD ) );
-			break;
-		case 2:
-			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO2_SETUP ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO2_HOLD ) );
-			break;
-		case 3:
-			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO3_SETUP ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO3_HOLD ) );
-			break;
-		case 4:
-			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO4_SETUP ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
-					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
-			break;
-	}
-}
-
-void __init
-init_e100_ide (void)
-{
-	volatile unsigned int dummy;
-	int h;
-
-	printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
-
-	/* first fill in some stuff in the ide_hwifs fields */
-
-	for(h = 0; h < MAX_HWIFS; h++) {
-		ide_hwif_t *hwif = &ide_hwifs[h];
-		hwif->mmio = 2;
-		hwif->chipset = ide_etrax100;
-		hwif->tuneproc = &tune_e100_ide;
-                hwif->ata_input_data = &e100_ide_input_data;
-                hwif->ata_output_data = &e100_ide_output_data;
-                hwif->atapi_input_bytes = &e100_atapi_input_bytes;
-                hwif->atapi_output_bytes = &e100_atapi_output_bytes;
-                hwif->ide_dma_check = &e100_dma_check;
-                hwif->ide_dma_end = &e100_dma_end;
-		hwif->ide_dma_write = &e100_dma_write;
-		hwif->ide_dma_read = &e100_dma_read;
-		hwif->ide_dma_begin = &e100_dma_begin;
-		hwif->OUTB = &etrax100_ide_outb;
-		hwif->OUTW = &etrax100_ide_outw;
-		hwif->OUTBSYNC = &etrax100_ide_outbsync;
-		hwif->INB = &etrax100_ide_inb;
-		hwif->INW = &etrax100_ide_inw;
-		hwif->ide_dma_off_quietly = &e100_dma_off;
-		hwif->ide_dma_verbose = &e100_dma_verbose;
-		hwif->sg_table =
-		  kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL);
-	}
-
-	/* actually reset and configure the etrax100 ide/ata interface */
-
-	*R_ATA_CTRL_DATA = 0;
-	*R_ATA_TRANSFER_CNT = 0;
-	*R_ATA_CONFIG = 0;
-
-	genconfig_shadow = (genconfig_shadow &
-			    ~IO_MASK(R_GEN_CONFIG, dma2) &
-			    ~IO_MASK(R_GEN_CONFIG, dma3) &
-			    ~IO_MASK(R_GEN_CONFIG, ata)) |
-		( IO_STATE( R_GEN_CONFIG, dma3, ata    ) |
-		  IO_STATE( R_GEN_CONFIG, dma2, ata    ) |
-		  IO_STATE( R_GEN_CONFIG, ata,  select ) );
-
-	*R_GEN_CONFIG = genconfig_shadow;
-
-        /* pull the chosen /reset-line low */
-
-#ifdef CONFIG_ETRAX_IDE_G27_RESET
-        REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-        REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
-        REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
-#endif
-#ifdef CONFIG_ETRAX_IDE_PB7_RESET
-	port_pb_dir_shadow = port_pb_dir_shadow |
-		IO_STATE(R_PORT_PB_DIR, dir7, output);
-	*R_PORT_PB_DIR = port_pb_dir_shadow;
-	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
-#endif
-
-	/* wait some */
-
-	udelay(25);
-
-	/* de-assert bus-reset */
-
-#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-	REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
-	REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
-#endif
-#ifdef CONFIG_ETRAX_IDE_G27_RESET
-	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1);
-#endif
-
-	/* make a dummy read to set the ata controller in a proper state */
-	dummy = *R_ATA_STATUS_DATA;
-
-	*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
-			  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
-			  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
-			  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO4_SETUP ) |
-			  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
-			  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
-
-	*R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw,   read) |
-			     IO_FIELD( R_ATA_CTRL_DATA, addr, 1   ) );
-
-	while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
-
-	*R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
-			     IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
-			     IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
-			     IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
-
-	printk("ide: waiting %d seconds for drives to regain consciousness\n",
-	       CONFIG_ETRAX_IDE_DELAY);
-
-	h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
-	while(time_before(jiffies, h)) /* nothing */ ;
-
-	/* reset the dma channels we will use */
-
-	RESET_DMA(ATA_TX_DMA_NBR);
-	RESET_DMA(ATA_RX_DMA_NBR);
-	WAIT_DMA(ATA_TX_DMA_NBR);
-	WAIT_DMA(ATA_RX_DMA_NBR);
-
-}
-
-static int e100_dma_off (ide_drive_t *drive)
-{
-	return 0;
-}
-
-static int e100_dma_verbose (ide_drive_t *drive)
-{
-	printk(", DMA(mode 2)");
-	return 0;
-}
-
-static etrax_dma_descr mydescr;
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-static void
-e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	unsigned long data_reg = IDE_DATA_REG;
-
-	D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
-		 data_reg, buffer, bytecount));
-
-	if(bytecount & 1) {
-		printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
-		bytecount++; /* to round off */
-	}
-
-	/* make sure the DMA channel is available */
-	RESET_DMA(ATA_RX_DMA_NBR);
-	WAIT_DMA(ATA_RX_DMA_NBR);
-
-	/* setup DMA descriptor */
-
-	mydescr.sw_len = bytecount;
-	mydescr.ctrl   = d_eol;
-	mydescr.buf    = virt_to_phys(buffer);
-
-	/* start the dma channel */
-
-	*R_DMA_CH3_FIRST = virt_to_phys(&mydescr);
-	*R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);
-
-	/* initiate a multi word dma read using PIO handshaking */
-
-	*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
-
-	*R_ATA_CTRL_DATA = data_reg |
-		IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
-		IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
-		IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
-		IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-
-	/* wait for completion */
-
-	LED_DISK_READ(1);
-	WAIT_DMA(ATA_RX_DMA_NBR);
-	LED_DISK_READ(0);
-
-#if 0
-        /* old polled transfer code
-	 * this should be moved into a new function that can do polled
-	 * transfers if DMA is not available
-	 */
-
-        /* initiate a multi word read */
-
-        *R_ATA_TRANSFER_CNT = wcount << 1;
-
-        *R_ATA_CTRL_DATA = data_reg |
-                IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
-                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
-                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
-                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-
-        /* svinto has a latency until the busy bit actually is set */
-
-        nop(); nop();
-        nop(); nop();
-        nop(); nop();
-        nop(); nop();
-        nop(); nop();
-
-        /* unit should be busy during multi transfer */
-        while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
-                while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
-                        status = *R_ATA_STATUS_DATA;
-                *ptr++ = (unsigned short)(status & 0xffff);
-        }
-#endif
-}
-
-static void
-e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	unsigned long data_reg = IDE_DATA_REG;
-
-	D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
-		 data_reg, buffer, bytecount));
-
-	if(bytecount & 1) {
-		printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
-		bytecount++;
-	}
-
-	/* make sure the DMA channel is available */
-	RESET_DMA(ATA_TX_DMA_NBR);
-	WAIT_DMA(ATA_TX_DMA_NBR);
-
-	/* setup DMA descriptor */
-
-	mydescr.sw_len = bytecount;
-	mydescr.ctrl   = d_eol;
-	mydescr.buf    = virt_to_phys(buffer);
-
-	/* start the dma channel */
-
-	*R_DMA_CH2_FIRST = virt_to_phys(&mydescr);
-	*R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
-
-	/* initiate a multi word dma write using PIO handshaking */
-
-	*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
-
-	*R_ATA_CTRL_DATA = data_reg |
-		IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
-		IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
-		IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
-		IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-
-	/* wait for completion */
-
-	LED_DISK_WRITE(1);
-	WAIT_DMA(ATA_TX_DMA_NBR);
-	LED_DISK_WRITE(0);
-
-#if 0
-        /* old polled write code - see comment in input_bytes */
-
-	/* wait for busy flag */
-        while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
-
-        /* initiate a multi word write */
-
-        *R_ATA_TRANSFER_CNT = bytecount >> 1;
-
-        ctrl = data_reg |
-                IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
-                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
-                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
-                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-
-        LED_DISK_WRITE(1);
-
-        /* Etrax will set busy = 1 until the multi pio transfer has finished
-         * and tr_rdy = 1 after each successful word transfer.
-         * When the last byte has been transferred Etrax will first set tr_tdy = 1
-         * and then busy = 0 (not in the same cycle). If we read busy before it
-         * has been set to 0 we will think that we should transfer more bytes
-         * and then tr_rdy would be 0 forever. This is solved by checking busy
-         * in the inner loop.
-         */
-
-        do {
-                *R_ATA_CTRL_DATA = ctrl | *ptr++;
-                while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
-                      (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
-        } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
-
-        LED_DISK_WRITE(0);
-#endif
-
-}
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-static void
-e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	e100_atapi_input_bytes(drive, buffer, wcount << 2);
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-static void
-e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	e100_atapi_output_bytes(drive, buffer, wcount << 2);
-}
-
-/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
-static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
-static unsigned int ata_tot_size;
-
-/*
- * e100_ide_build_dmatable() prepares a dma request.
- * Returns 0 if all went okay, returns 1 otherwise.
- */
-static int e100_ide_build_dmatable (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct scatterlist* sg;
-	struct request *rq  = HWGROUP(drive)->rq;
-	unsigned long size, addr;
-	unsigned int count = 0;
-	int i = 0;
-
-	sg = hwif->sg_table;
-
-	ata_tot_size = 0;
-
-	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
-		u8 *virt_addr = rq->buffer;
-		int sector_count = rq->nr_sectors;
-		memset(&sg[0], 0, sizeof(*sg));
-		sg[0].page = virt_to_page(virt_addr);
-		sg[0].offset = offset_in_page(virt_addr);
-		sg[0].length =  sector_count  * SECTOR_SIZE;
-		hwif->sg_nents = i = 1;
-	}
-	else
-	{
-		hwif->sg_nents = i = blk_rq_map_sg(drive->queue, rq, hwif->sg_table);
-	}
-
-
-	while(i) {
-		/*
-		 * Determine addr and size of next buffer area.  We assume that
-		 * individual virtual buffers are always composed linearly in
-		 * physical memory.  For example, we assume that any 8kB buffer
-		 * is always composed of two adjacent physical 4kB pages rather
-		 * than two possibly non-adjacent physical 4kB pages.
-		 */
-		/* group sequential buffers into one large buffer */
-		addr = page_to_phys(sg->page) + sg->offset;
-		size = sg_dma_len(sg);
-		while (sg++, --i) {
-			if ((addr + size) != page_to_phys(sg->page) + sg->offset)
-				break;
-			size += sg_dma_len(sg);
-		}
-
-		/* did we run out of descriptors? */
-
-		if(count >= MAX_DMA_DESCRS) {
-			printk("%s: too few DMA descriptors\n", drive->name);
-			return 1;
-		}
-
-		/* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
-		   than 65536 words per transfer, so in that case we need to either
-		   1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
-		      the descriptors, or
-		   2) simply do the request here, and get dma_intr to only ide_end_request on
-		      those blocks that were actually set-up for transfer.
-		*/
-
-		if(ata_tot_size + size > 131072) {
-			printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
-			return 1;
-		}
-
-		/* If size > 65536 it has to be splitted into new descriptors. Since we don't handle
-                   size > 131072 only one split is necessary */
-
-		if(size > 65536) {
- 		        /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
-                        ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
-                        ata_descrs[count].ctrl = 0;
-                        ata_descrs[count].buf = addr;
-                        ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
-                        count++;
-                        ata_tot_size += 65536;
-                        /* size and addr should refere to not handled data */
-                        size -= 65536;
-                        addr += 65536;
-                }
-		/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
-                if(size == 65536) {
-			ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
-                } else {
-			ata_descrs[count].sw_len = size;
-                }
-		ata_descrs[count].ctrl = 0;
-		ata_descrs[count].buf = addr;
-		ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
-		count++;
-		ata_tot_size += size;
-	}
-
-	if (count) {
-		/* set the end-of-list flag on the last descriptor */
-		ata_descrs[count - 1].ctrl |= d_eol;
-		/* return and say all is ok */
-		return 0;
-	}
-
-	printk("%s: empty DMA table?\n", drive->name);
-	return 1;	/* let the PIO routines handle this weirdness */
-}
-
-static int config_drive_for_dma (ide_drive_t *drive)
-{
-        const char **list;
-        struct hd_driveid *id = drive->id;
-
-        if (id && (id->capability & 1)) {
-                /* Enable DMA on any drive that supports mword2 DMA */
-                if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
-                        drive->using_dma = 1;
-                        return 0;               /* DMA enabled */
-                }
-
-                /* Consult the list of known "good" drives */
-                list = good_dma_drives;
-                while (*list) {
-                        if (!strcmp(*list++,id->model)) {
-                                drive->using_dma = 1;
-                                return 0;       /* DMA enabled */
-                        }
-                }
-        }
-        return 1;       /* DMA not enabled */
-}
-
-/*
- * etrax_dma_intr() is the handler for disk read/write DMA interrupts
- */
-static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
-{
-	int i, dma_stat;
-	byte stat;
-
-	LED_DISK_READ(0);
-	LED_DISK_WRITE(0);
-
-	dma_stat = HWIF(drive)->ide_dma_end(drive);
-	stat = HWIF(drive)->INB(IDE_STATUS_REG);		/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if (!dma_stat) {
-			struct request *rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
-			}
-			return ide_stopped;
-		}
-		printk("%s: bad DMA status\n", drive->name);
-	}
-	return DRIVER(drive)->error(drive, "dma_intr", stat);
-}
-
-/*
- * Functions below initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * ide_dma_begin afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- */
-
-static int e100_dma_check(ide_drive_t *drive)
-{
-	return config_drive_for_dma (drive);
-}
-
-static int e100_dma_end(ide_drive_t *drive)
-{
-	/* TODO: check if something went wrong with the DMA */
-	return 0;
-}
-
-static int e100_start_dma(ide_drive_t *drive, int atapi, int reading)
-{
-	if(reading) {
-
-		RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
-		WAIT_DMA(ATA_RX_DMA_NBR);
-
-		/* set up the Etrax DMA descriptors */
-
-		if(e100_ide_build_dmatable (drive))
-			return 1;
-
-		if(!atapi) {
-			/* set the irq handler which will finish the request when DMA is done */
-
-			ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
-
-			/* issue cmd to drive */
-                        if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
-			    (drive->addressing == 1)) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing) {
-				etrax100_ide_outb(WIN_READDMA_EXT, IDE_COMMAND_REG);
-			} else {
-				etrax100_ide_outb(WIN_READDMA, IDE_COMMAND_REG);
-			}
-		}
-
-		/* begin DMA */
-
-		/* need to do this before RX DMA due to a chip bug
-		 * it is enough to just flush the part of the cache that
-		 * corresponds to the buffers we start, but since HD transfers
-		 * usually are more than 8 kB, it is easier to optimize for the
-		 * normal case and just flush the entire cache. its the only
-		 * way to be sure! (OB movie quote)
-		 */
-		flush_etrax_cache();
-		*R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
-		*R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);
-
-		/* initiate a multi word dma read using DMA handshaking */
-
-		*R_ATA_TRANSFER_CNT =
-			IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
-
-		*R_ATA_CTRL_DATA =
-			IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
-			IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
-			IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma)  |
-			IO_STATE(R_ATA_CTRL_DATA, handsh,   dma)  |
-			IO_STATE(R_ATA_CTRL_DATA, multi,    on)   |
-			IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-
-		LED_DISK_READ(1);
-
-		D(printk("dma read of %d bytes.\n", ata_tot_size));
-
-	} else {
-		/* writing */
-
-		RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
-		WAIT_DMA(ATA_TX_DMA_NBR);
-
-		/* set up the Etrax DMA descriptors */
-
-		if(e100_ide_build_dmatable (drive))
-			return 1;
-
-		if(!atapi) {
-			/* set the irq handler which will finish the request when DMA is done */
-
-			ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
-
-			/* issue cmd to drive */
-			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
-			    (drive->addressing == 1)) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing) {
-				etrax100_ide_outb(WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-			} else {
-				etrax100_ide_outb(WIN_WRITEDMA, IDE_COMMAND_REG);
-			}
-		}
-
-		/* begin DMA */
-
-		*R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
-		*R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
-
-		/* initiate a multi word dma write using DMA handshaking */
-
-		*R_ATA_TRANSFER_CNT =
-			IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
-
-		*R_ATA_CTRL_DATA =
-			IO_FIELD(R_ATA_CTRL_DATA, data,     IDE_DATA_REG) |
-			IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
-			IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
-			IO_STATE(R_ATA_CTRL_DATA, handsh,   dma) |
-			IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
-			IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-
-		LED_DISK_WRITE(1);
-
-		D(printk("dma write of %d bytes.\n", ata_tot_size));
-	}
-	return 0;
-}
-
-static int e100_dma_write(ide_drive_t *drive)
-{
-	e100_read_command = 0;
-	/* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
-	 * then they call ide_dma_begin after they have issued the appropriate drive command
-	 * themselves to actually start the chipset DMA. so we just return here if we're
-	 * not a diskdrive.
-	 */
-	if (drive->media != ide_disk)
-                return 0;
-	return e100_start_dma(drive, 0, 0);
-}
-
-static int e100_dma_read(ide_drive_t *drive)
-{
-	e100_read_command = 1;
-	/* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
-	 * then they call ide_dma_begin after they have issued the appropriate drive command
-	 * themselves to actually start the chipset DMA. so we just return here if we're
-	 * not a diskdrive.
-	 */
-	if (drive->media != ide_disk)
-                return 0;
-	return e100_start_dma(drive, 0, 1);
-}
-
-static int e100_dma_begin(ide_drive_t *drive)
-{
-	/* begin DMA, used by ATAPI devices which want to issue the
-	 * appropriate IDE command themselves.
-	 *
-	 * they have already called ide_dma_read/write to set the
-	 * static reading flag, now they call ide_dma_begin to do
-	 * the real stuff. we tell our code below not to issue
-	 * any IDE commands itself and jump into it.
-	 */
-	 return e100_start_dma(drive, 1, e100_read_command);
-}
diff -L arch/cris/arch-v10/drivers/serial.c -puN arch/cris/arch-v10/drivers/serial.c~cris-architecture-update-move-drivers /dev/null
--- 25/arch/cris/arch-v10/drivers/serial.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,5061 +0,0 @@
-/* $Id: serial.c,v 1.25 2004/09/29 10:33:49 starvik Exp $
- *
- * Serial port driver for the ETRAX 100LX chip
- *
- *    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Axis Communications AB
- *
- *    Many, many authors. Based once upon a time on serial.c for 16x50.
- *
- * $Log: serial.c,v $
- * Revision 1.25  2004/09/29 10:33:49  starvik
- * Resolved a dealock when printing debug from kernel.
- *
- * Revision 1.24  2004/08/27 23:25:59  johana
- * rs_set_termios() must call change_speed() if c_iflag has changed or
- * automatic XOFF handling will be enabled and transmitter will stop
- * if 0x13 is received.
- *
- * Revision 1.23  2004/08/24 06:57:13  starvik
- * More whitespace cleanup
- *
- * Revision 1.22  2004/08/24 06:12:20  starvik
- * Whitespace cleanup
- *
- * Revision 1.20  2004/05/24 12:00:20  starvik
- * Big merge of stuff from Linux 2.4 (e.g. manual mode for the serial port).
- *
- * Revision 1.19  2004/05/17 13:12:15  starvik
- * Kernel console hook
- * Big merge from Linux 2.4 still pending.
- *
- * Revision 1.18  2003/10/28 07:18:30  starvik
- * Compiles with debug info
- *
- * Revision 1.17  2003/07/04 08:27:37  starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.16  2003/06/13 10:05:19  johana
- * Help the user to avoid trouble by:
- * Forcing mixed mode for status/control lines if not all pins are used.
- *
- * Revision 1.15  2003/06/13 09:43:01  johana
- * Merged in the following changes from os/linux/arch/cris/drivers/serial.c
- * + some minor changes to reduce diff.
- *
- * Revision 1.49  2003/05/30 11:31:54  johana
- * Merged in change-branch--serial9bit that adds CMSPAR support for sticky
- * parity (mark/space)
- *
- * Revision 1.48  2003/05/30 11:03:57  johana
- * Implemented rs_send_xchar() by disabling the DMA and writing manually.
- * Added e100_disable_txdma_channel() and e100_enable_txdma_channel().
- * Fixed rs_throttle() and rs_unthrottle() to properly call rs_send_xchar
- * instead of setting info->x_char and check the CRTSCTS flag before
- * controlling the rts pin.
- *
- * Revision 1.14  2003/04/09 08:12:44  pkj
- * Corrected typo changes made upstream.
- *
- * Revision 1.13  2003/04/09 05:20:47  starvik
- * Merge of Linux 2.5.67
- *
- * Revision 1.11  2003/01/22 06:48:37  starvik
- * Fixed warnings issued by GCC 3.2.1
- *
- * Revision 1.9  2002/12/13 09:07:47  starvik
- * Alert user that RX_TIMEOUT_TICKS==0 doesn't work
- *
- * Revision 1.8  2002/12/11 13:13:57  starvik
- * Added arch/ to v10 specific includes
- * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
- *
- * Revision 1.7  2002/12/06 07:13:57  starvik
- * Corrected work queue stuff
- * Removed CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
- *
- * Revision 1.6  2002/11/21 07:17:46  starvik
- * Change static inline to extern inline where otherwise outlined with gcc-3.2
- *
- * Revision 1.5  2002/11/14 15:59:49  starvik
- * Linux 2.5 port of the latest serial driver from 2.4. The work queue stuff
- * probably doesn't work yet.
- *
- * Revision 1.42  2002/11/05 09:08:47  johana
- * Better implementation of rs_stop() and rs_start() that uses the XOFF
- * register to start/stop transmission.
- * change_speed() also initilises XOFF register correctly so that
- * auto_xoff is enabled when IXON flag is set by user.
- * This gives fast XOFF response times.
- *
- * Revision 1.41  2002/11/04 18:40:57  johana
- * Implemented rs_stop() and rs_start().
- * Simple tests using hwtestserial indicates that this should be enough
- * to make it work.
- *
- * Revision 1.40  2002/10/14 05:33:18  starvik
- * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
- *
- * Revision 1.39  2002/09/30 21:00:57  johana
- * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
- * control pins can be mixed between PA and PB.
- * If no serial port uses MIXED old solution is used
- * (saves a few bytes and cycles).
- * control_pins struct uses masks instead of bit numbers.
- * Corrected dummy values and polarity in line_info() so
- * /proc/tty/driver/serial is now correct.
- * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
- *
- * Revision 1.38  2002/08/23 11:01:36  starvik
- * Check that serial port is enabled in all interrupt handlers to avoid
- * restarts of DMA channels not assigned to serial ports
- *
- * Revision 1.37  2002/08/13 13:02:37  bjornw
- * Removed some warnings because of unused code
- *
- * Revision 1.36  2002/08/08 12:50:01  starvik
- * Serial interrupt is shared with synchronous serial port driver
- *
- * Revision 1.35  2002/06/03 10:40:49  starvik
- * Increased RS-485 RTS toggle timer to 2 characters
- *
- * Revision 1.34  2002/05/28 18:59:36  johana
- * Whitespace and comment fixing to be more like etrax100ser.c 1.71.
- *
- * Revision 1.33  2002/05/28 17:55:43  johana
- * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time)
- * timer from tranismit_chars (interrupt context).
- * The timer toggles RTS in interrupt context when expired giving minimum
- * latencies.
- *
- * Revision 1.32  2002/05/22 13:58:00  johana
- * Renamed rs_write() to raw_write() and made it inline.
- * New rs_write() handles RS-485 if configured and enabled
- * (moved code from e100_write_rs485()).
- * RS-485 ioctl's uses copy_from_user() instead of verify_area().
- *
- * Revision 1.31  2002/04/22 11:20:03  johana
- * Updated copyright years.
- *
- * Revision 1.30  2002/04/22 09:39:12  johana
- * RS-485 support compiles.
- *
- * Revision 1.29  2002/01/14 16:10:01  pkj
- * Allocate the receive buffers dynamically. The static 4kB buffer was
- * too small for the peaks. This means that we can get rid of the extra
- * buffer and the copying to it. It also means we require less memory
- * under normal operations, but can use more when needed (there is a
- * cap at 64kB for safety reasons). If there is no memory available
- * we panic(), and die a horrible death...
- *
- * Revision 1.28  2001/12/18 15:04:53  johana
- * Cleaned up write_rs485() - now it works correctly without padding extra
- * char.
- * Added sane default initialisation of rs485.
- * Added #ifdef around dummy variables.
- *
- * Revision 1.27  2001/11/29 17:00:41  pkj
- * 2kB seems to be too small a buffer when using 921600 bps,
- * so increase it to 4kB (this was already done for the elinux
- * version of the serial driver).
- *
- * Revision 1.26  2001/11/19 14:20:41  pkj
- * Minor changes to comments and unused code.
- *
- * Revision 1.25  2001/11/12 20:03:43  pkj
- * Fixed compiler warnings.
- *
- * Revision 1.24  2001/11/12 15:10:05  pkj
- * Total redesign of the receiving part of the serial driver.
- * Uses eight chained descriptors to write to a 4kB buffer.
- * This data is then serialised into a 2kB buffer. From there it
- * is copied into the TTY's flip buffers when they become available.
- * A lot of copying, and the sizes of the buffers might need to be
- * tweaked, but all in all it should work better than the previous
- * version, without the need to modify the TTY code in any way.
- * Also note that erroneous bytes are now correctly marked in the
- * flag buffers (instead of always marking the first byte).
- *
- * Revision 1.23  2001/10/30 17:53:26  pkj
- * * Set info->uses_dma to 0 when a port is closed.
- * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT).
- * * Call start_flush_timer() in start_receive() if
- *   CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is defined.
- *
- * Revision 1.22  2001/10/30 17:44:03  pkj
- * Use %lu for received and transmitted counters in line_info().
- *
- * Revision 1.21  2001/10/30 17:40:34  pkj
- * Clean-up. The only change to functionality is that
- * CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS(=5) is used instead of
- * MAX_FLUSH_TIME(=8).
- *
- * Revision 1.20  2001/10/30 15:24:49  johana
- * Added char_time stuff from 2.0 driver.
- *
- * Revision 1.19  2001/10/30 15:23:03  johana
- * Merged with 1.13.2 branch + fixed indentation
- * and changed CONFIG_ETRAX100_XYS to CONFIG_ETRAX_XYZ
- *
- * Revision 1.18  2001/09/24 09:27:22  pkj
- * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud().
- *
- * Revision 1.17  2001/08/24 11:32:49  ronny
- * More fixes for the CONFIG_ETRAX_SERIAL_PORT0 define.
- *
- * Revision 1.16  2001/08/24 07:56:22  ronny
- * Added config ifdefs around ser0 irq requests.
- *
- * Revision 1.15  2001/08/16 09:10:31  bjarne
- * serial.c - corrected the initialization of rs_table, the wrong defines
- *            where used.
- *            Corrected a test in timed_flush_handler.
- *            Changed configured to enabled.
- * serial.h - Changed configured to enabled.
- *
- * Revision 1.14  2001/08/15 07:31:23  bjarne
- * Introduced two new members to the e100_serial struct.
- * configured - Will be set to 1 if the port has been configured in .config
- * uses_dma   - Should be set to 1 if the port uses DMA. Currently it is set 
- *              to 1
- *              when a port is opened. This is used to limit the DMA interrupt
- *              routines to only manipulate DMA channels actually used by the
- *              serial driver.
- *
- * Revision 1.13.2.2  2001/10/17 13:57:13  starvik
- * Receiver was broken by the break fixes
- *
- * Revision 1.13.2.1  2001/07/20 13:57:39  ronny
- * Merge with new stuff from etrax100ser.c. Works but haven't checked stuff
- * like break handling.
- *
- * Revision 1.13  2001/05/09 12:40:31  johana
- * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
- *
- * Revision 1.12  2001/04/19 12:23:07  bjornw
- * CONFIG_RS485 -> CONFIG_ETRAX_RS485
- *
- * Revision 1.11  2001/04/05 14:29:48  markusl
- * Updated according to review remarks i.e.
- * -Use correct types in port structure to avoid compiler warnings
- * -Try to use IO_* macros whenever possible
- * -Open should never return -EBUSY
- *
- * Revision 1.10  2001/03/05 13:14:07  bjornw
- * Another spelling fix
- *
- * Revision 1.9  2001/02/23 13:46:38  bjornw
- * Spellling check
- *
- * Revision 1.8  2001/01/23 14:56:35  markusl
- * Made use of ser1 optional
- * Needed by USB
- *
- * Revision 1.7  2001/01/19 16:14:48  perf
- * Added kernel options for serial ports 234.
- * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ.
- *
- * Revision 1.6  2000/11/22 16:36:09  bjornw
- * Please marketing by using the correct case when spelling Etrax.
- *
- * Revision 1.5  2000/11/21 16:43:37  bjornw
- * Fixed so it compiles under CONFIG_SVINTO_SIM
- *
- * Revision 1.4  2000/11/15 17:34:12  bjornw
- * Added a timeout timer for flushing input channels. The interrupt-based
- * fast flush system should be easy to merge with this later (works the same
- * way, only with an irq instead of a system timer_list)
- *
- * Revision 1.3  2000/11/13 17:19:57  bjornw
- * * Incredibly, this almost complete rewrite of serial.c worked (at least
- *   for output) the first time.
- *
- *   Items worth noticing:
- *
- *      No Etrax100 port 1 workarounds (does only compile on 2.4 anyway now)
- *      RS485 is not ported (why can't it be done in userspace as on x86 ?)
- *      Statistics done through async_icount - if any more stats are needed,
- *      that's the place to put them or in an arch-dep version of it.
- *      timeout_interrupt and the other fast timeout stuff not ported yet
- *      There be dragons in this 3k+ line driver
- *
- * Revision 1.2  2000/11/10 16:50:28  bjornw
- * First shot at a 2.4 port, does not compile totally yet
- *
- * Revision 1.1  2000/11/10 16:47:32  bjornw
- * Added verbatim copy of rev 1.49 etrax100ser.c from elinux
- *
- * Revision 1.49  2000/10/30 15:47:14  tobiasa
- * Changed version number.
- *
- * Revision 1.48  2000/10/25 11:02:43  johana
- * Changed %ul to %lu in printf's
- *
- * Revision 1.47  2000/10/18 15:06:53  pkj
- * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and
- * CONFIG_ETRAX_SERIAL_PROC_ENTRY together.
- * Some clean-up of the /proc/serial file.
- *
- * Revision 1.46  2000/10/16 12:59:40  johana
- * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info.
- *
- * Revision 1.45  2000/10/13 17:10:59  pkj
- * Do not flush DMAs while flipping TTY buffers.
- *
- * Revision 1.44  2000/10/13 16:34:29  pkj
- * Added a delay in ser_interrupt() for 2.3ms when an error is detected.
- * We do not know why this delay is required yet, but without it the
- * irmaflash program does not work (this was the program that needed
- * the ser_interrupt() to be needed in the first place). This should not
- * affect normal use of the serial ports.
- *
- * Revision 1.43  2000/10/13 16:30:44  pkj
- * New version of the fast flush of serial buffers code. This time
- * it is localized to the serial driver and uses a fast timer to
- * do the work.
- *
- * Revision 1.42  2000/10/13 14:54:26  bennyo
- * Fix for switching RTS when using rs485
- *
- * Revision 1.41  2000/10/12 11:43:44  pkj
- * Cleaned up a number of comments.
- *
- * Revision 1.40  2000/10/10 11:58:39  johana
- * Made RS485 support generic for all ports.
- * Toggle rts in interrupt if no delay wanted.
- * WARNING: No true transmitter empty check??
- * Set d_wait bit when sending data so interrupt is delayed until
- * fifo flushed. (Fix tcdrain() problem)
- *
- * Revision 1.39  2000/10/04 16:08:02  bjornw
- * * Use virt_to_phys etc. for DMA addresses
- * * Removed CONFIG_FLUSH_DMA_FAST hacks
- * * Indentation fix
- *
- * Revision 1.38  2000/10/02 12:27:10  mattias
- * * added variable used when using fast flush on serial dma.
- *   (CONFIG_FLUSH_DMA_FAST)
- *
- * Revision 1.37  2000/09/27 09:44:24  pkj
- * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
- *
- * Revision 1.36  2000/09/20 13:12:52  johana
- * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS:
- *   Number of timer ticks between flush of receive fifo (1 tick = 10ms).
- *   Try 0-3 for low latency applications. Approx 5 for high load
- *   applications (e.g. PPP). Maybe this should be more adaptive some day...
- *
- * Revision 1.35  2000/09/20 10:36:08  johana
- * Typo in get_lsr_info()
- *
- * Revision 1.34  2000/09/20 10:29:59  johana
- * Let rs_chars_in_buffer() check fifo content as well.
- * get_lsr_info() might work now (not tested).
- * Easier to change the port to debug.
- *
- * Revision 1.33  2000/09/13 07:52:11  torbjore
- * Support RS485
- *
- * Revision 1.32  2000/08/31 14:45:37  bjornw
- * After sending a break we need to reset the transmit DMA channel
- *
- * Revision 1.31  2000/06/21 12:13:29  johana
- * Fixed wait for all chars sent when closing port.
- * (Used to always take 1 second!)
- * Added shadows for directions of status/ctrl signals.
- *
- * Revision 1.30  2000/05/29 16:27:55  bjornw
- * Simulator ifdef moved a bit
- *
- * Revision 1.29  2000/05/09 09:40:30  mattias
- * * Added description of dma registers used in timeout_interrupt
- * * Removed old code
- *
- * Revision 1.28  2000/05/08 16:38:58  mattias
- * * Bugfix for flushing fifo in timeout_interrupt
- *   Problem occurs when bluetooth stack waits for a small number of bytes
- *   containing an event acknowledging free buffers in bluetooth HW
- *   As before, data was stuck in fifo until more data came on uart and
- *   flushed it up to the stack.
- *
- * Revision 1.27  2000/05/02 09:52:28  jonasd
- * Added fix for peculiar etrax behaviour when eop is forced on an empty
- * fifo. This is used when flashing the IRMA chip. Disabled by default.
- *
- * Revision 1.26  2000/03/29 15:32:02  bjornw
- * 2.0.34 updates
- *
- * Revision 1.25  2000/02/16 16:59:36  bjornw
- * * Receive DMA directly into the flip-buffer, eliminating an intermediary
- *   receive buffer and a memcpy. Will avoid some overruns.
- * * Error message on debug port if an overrun or flip buffer overrun occurs.
- * * Just use the first byte in the flag flip buffer for errors.
- * * Check for timeout on the serial ports only each 5/100 s, not 1/100.
- *
- * Revision 1.24  2000/02/09 18:02:28  bjornw
- * * Clear serial errors (overrun, framing, parity) correctly. Before, the
- *   receiver would get stuck if an error occurred and we did not restart
- *   the input DMA.
- * * Cosmetics (indentation, some code made into inlines)
- * * Some more debug options
- * * Actually shut down the serial port (DMA irq, DMA reset, receiver stop)
- *   when the last open is closed. Corresponding fixes in startup().
- * * rs_close() "tx FIFO wait" code moved into right place, bug & -> && fixed
- *   and make a special case out of port 1 (R_DMA_CHx_STATUS is broken for that)
- * * e100_disable_rx/enable_rx just disables/enables the receiver, not RTS
- *
- * Revision 1.23  2000/01/24 17:46:19  johana
- * Wait for flush of DMA/FIFO when closing port.
- *
- * Revision 1.22  2000/01/20 18:10:23  johana
- * Added TIOCMGET ioctl to return modem status.
- * Implemented modem status/control that works with the extra signals
- * (DTR, DSR, RI,CD) as well.
- * 3 different modes supported:
- * ser0 on PB (Bundy), ser1 on PB (Lisa) and ser2 on PA (Bundy)
- * Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when
- * closing the last filehandle, NASTY!.
- * Added break generation, not tested though!
- * Use SA_SHIRQ when request_irq() for ser2 and ser3 (shared with) par0 and par1.
- * You can't use them at the same time (yet..), but you can hopefully switch
- * between ser2/par0, ser3/par1 with the same kernel config.
- * Replaced some magic constants with defines
- *
- *
- */
-
-static char *serial_version = "$Revision: 1.25 $";
-
-#include <linux/config.h>
-#include <linux/version.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <linux/kernel.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/arch/svinto.h>
-
-/* non-arch dependent serial structures are in linux/serial.h */
-#include <linux/serial.h>
-/* while we keep our own stuff (struct e100_serial) in a local .h file */
-#include "serial.h"
-#include <asm/fasttimer.h>
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-#ifndef CONFIG_ETRAX_FAST_TIMER
-#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
-#endif
-#endif
-
-#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
-           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
-#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
-#endif
-
-#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
-#endif
-
-/*
- * All of the compatibilty code so we can compile serial.c against
- * older kernels is hidden in serial_compat.h
- */
-#if defined(LOCAL_HEADERS)
-#include "serial_compat.h"
-#endif
-
-#define _INLINE_ inline
-
-struct tty_driver *serial_driver;
-
-/* serial subtype definitions */
-#ifndef SERIAL_TYPE_NORMAL
-#define SERIAL_TYPE_NORMAL	1
-#endif
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-//#define SERIAL_DEBUG_INTR
-//#define SERIAL_DEBUG_OPEN 
-//#define SERIAL_DEBUG_FLOW
-//#define SERIAL_DEBUG_DATA
-//#define SERIAL_DEBUG_THROTTLE
-//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
-//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
-
-/* Enable this to use serial interrupts to handle when you
-   expect the first received event on the serial port to
-   be an error, break or similar. Used to be able to flash IRMA
-   from eLinux */
-#define SERIAL_HANDLE_EARLY_ERRORS
-
-/* Defined and used in n_tty.c, but we need it here as well */
-#define TTY_THRESHOLD_THROTTLE 128
-
-/* Due to buffersizes and threshold values, our SERIAL_DESCR_BUF_SIZE
- * must not be to high or flow control won't work if we leave it to the tty
- * layer so we have our own throttling in flush_to_flip
- * TTY_FLIPBUF_SIZE=512,
- * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128
- * BUF_SIZE can't be > 128
- */
-/* Currently 16 descriptors x 128 bytes = 2048 bytes */
-#define SERIAL_DESCR_BUF_SIZE 256
-
-#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
-#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
-
-/* We don't want to load the system with massive fast timer interrupt
- * on high baudrates so limit it to 250 us (4kHz) */
-#define MIN_FLUSH_TIME_USEC 250
-
-/* Add an x here to log a lot of timer stuff */
-#define TIMERD(x)
-/* Debug details of interrupt handling */
-#define DINTR1(x)  /* irq on/off, errors */
-#define DINTR2(x)    /* tx and rx */
-/* Debug flip buffer stuff */
-#define DFLIP(x)
-/* Debug flow control and overview of data flow */
-#define DFLOW(x)
-#define DBAUD(x)
-#define DLOG_INT_TRIG(x)
-
-//#define DEBUG_LOG_INCLUDED
-#ifndef DEBUG_LOG_INCLUDED
-#define DEBUG_LOG(line, string, value)
-#else
-struct debug_log_info
-{
-	unsigned long time;
-	unsigned long timer_data;
-//  int line;
-	const char *string;
-	int value;
-};
-#define DEBUG_LOG_SIZE 4096
-
-struct debug_log_info debug_log[DEBUG_LOG_SIZE];
-int debug_log_pos = 0;
-
-#define DEBUG_LOG(_line, _string, _value) do { \
-  if ((_line) == SERIAL_DEBUG_LINE) {\
-    debug_log_func(_line, _string, _value); \
-  }\
-}while(0)
-
-void debug_log_func(int line, const char *string, int value)
-{
-	if (debug_log_pos < DEBUG_LOG_SIZE) {
-		debug_log[debug_log_pos].time = jiffies;
-		debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
-//    debug_log[debug_log_pos].line = line;
-		debug_log[debug_log_pos].string = string;
-		debug_log[debug_log_pos].value = value;
-		debug_log_pos++;
-	}
-	/*printk(string, value);*/
-}
-#endif
-
-#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
-/* Default number of timer ticks before flushing rx fifo 
- * When using "little data, low latency applications: use 0
- * When using "much data applications (PPP)" use ~5
- */
-#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 
-#endif
-
-unsigned long timer_data_to_ns(unsigned long timer_data);
-
-static void change_speed(struct e100_serial *info);
-static void rs_throttle(struct tty_struct * tty);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int rs_write(struct tty_struct * tty, int from_user,
-                    const unsigned char *buf, int count);
-extern _INLINE_ int rs_raw_write(struct tty_struct * tty, int from_user,
-                            const unsigned char *buf, int count);
-#ifdef CONFIG_ETRAX_RS485
-static int e100_write_rs485(struct tty_struct * tty, int from_user,
-                            const unsigned char *buf, int count);
-#endif
-static int get_lsr_info(struct e100_serial * info, unsigned int *value);
-
-
-#define DEF_BAUD 115200   /* 115.2 kbit/s */
-#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
-/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
-#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
-
-/* offsets from R_SERIALx_CTRL */
-
-#define REG_DATA 0
-#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
-#define REG_TR_DATA 0
-#define REG_STATUS 1
-#define REG_TR_CTRL 1
-#define REG_REC_CTRL 2
-#define REG_BAUD 3
-#define REG_XOFF 4  /* this is a 32 bit register */
-
-/* The bitfields are the same for all serial ports */
-#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
-#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
-#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
-#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
-#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
-
-#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
-
-/* Values for info->errorcode */
-#define ERRCODE_SET_BREAK    (TTY_BREAK)
-#define ERRCODE_INSERT        0x100
-#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
-
-#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
-
-/*
- * General note regarding the use of IO_* macros in this file: 
- *
- * We will use the bits defined for DMA channel 6 when using various
- * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
- * the same for all channels (which of course they are).
- *
- * We will also use the bits defined for serial port 0 when writing commands
- * to the different ports, as these bits too are the same for all ports.
- */
-
-
-/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
-static const unsigned long e100_ser_int_mask = 0
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
-#endif
-;
-unsigned long r_alt_ser_baudrate_shadow = 0;
-
-/* this is the data for the four serial ports in the etrax100 */
-/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
-/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
-
-static struct e100_serial rs_table[] = {
-	{ .baud        = DEF_BAUD,
-	  .port        = (unsigned char *)R_SERIAL0_CTRL,
-	  .irq         = 1U << 12, /* uses DMA 6 and 7 */
-	  .oclrintradr = R_DMA_CH6_CLR_INTR,
-	  .ofirstadr   = R_DMA_CH6_FIRST,
-	  .ocmdadr     = R_DMA_CH6_CMD,
-	  .ostatusadr  = R_DMA_CH6_STATUS,
-	  .iclrintradr = R_DMA_CH7_CLR_INTR,
-	  .ifirstadr   = R_DMA_CH7_FIRST,
-	  .icmdadr     = R_DMA_CH7_CMD,
-	  .idescradr   = R_DMA_CH7_DESCR,
-	  .flags       = STD_FLAGS,
-	  .rx_ctrl     = DEF_RX,
-	  .tx_ctrl     = DEF_TX,
-	  .iseteop     = 2,
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-          .enabled  = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
-	  .dma_out_enabled = 1,
-#else
-	  .dma_out_enabled = 0,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
-	  .dma_in_enabled = 1,
-#else
-	  .dma_in_enabled = 0
-#endif
-#else
-          .enabled  = 0,
-	  .dma_out_enabled = 0,
-	  .dma_in_enabled = 0
-#endif
-
-},  /* ttyS0 */
-#ifndef CONFIG_SVINTO_SIM
-	{ .baud        = DEF_BAUD,
-	  .port        = (unsigned char *)R_SERIAL1_CTRL,
-	  .irq         = 1U << 16, /* uses DMA 8 and 9 */
-	  .oclrintradr = R_DMA_CH8_CLR_INTR,
-	  .ofirstadr   = R_DMA_CH8_FIRST,
-	  .ocmdadr     = R_DMA_CH8_CMD,
-	  .ostatusadr  = R_DMA_CH8_STATUS,
-	  .iclrintradr = R_DMA_CH9_CLR_INTR,
-	  .ifirstadr   = R_DMA_CH9_FIRST,
-	  .icmdadr     = R_DMA_CH9_CMD,
-	  .idescradr   = R_DMA_CH9_DESCR,
-	  .flags       = STD_FLAGS,
-	  .rx_ctrl     = DEF_RX,
-	  .tx_ctrl     = DEF_TX,
-	  .iseteop     = 3,
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-          .enabled  = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
-	  .dma_out_enabled = 1,
-#else
-	  .dma_out_enabled = 0,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
-	  .dma_in_enabled = 1,
-#else
-	  .dma_in_enabled = 0
-#endif
-#else
-          .enabled  = 0,
-	  .dma_out_enabled = 0,
-	  .dma_in_enabled = 0
-#endif
-},  /* ttyS1 */
-
-	{ .baud        = DEF_BAUD,
-	  .port        = (unsigned char *)R_SERIAL2_CTRL,
-	  .irq         = 1U << 4,  /* uses DMA 2 and 3 */
-	  .oclrintradr = R_DMA_CH2_CLR_INTR,
-	  .ofirstadr   = R_DMA_CH2_FIRST,
-	  .ocmdadr     = R_DMA_CH2_CMD,
-	  .ostatusadr  = R_DMA_CH2_STATUS,
-	  .iclrintradr = R_DMA_CH3_CLR_INTR,
-	  .ifirstadr   = R_DMA_CH3_FIRST,
-	  .icmdadr     = R_DMA_CH3_CMD,
-	  .idescradr   = R_DMA_CH3_DESCR,
-	  .flags       = STD_FLAGS,
-	  .rx_ctrl     = DEF_RX,
-	  .tx_ctrl     = DEF_TX,
-	  .iseteop     = 0,
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-          .enabled  = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
-	  .dma_out_enabled = 1,
-#else
-	  .dma_out_enabled = 0,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
-	  .dma_in_enabled = 1,
-#else
-	  .dma_in_enabled = 0
-#endif
-#else
-          .enabled  = 0,
-	  .dma_out_enabled = 0,
-	  .dma_in_enabled = 0
-#endif
- },  /* ttyS2 */
-
-	{ .baud        = DEF_BAUD,
-	  .port        = (unsigned char *)R_SERIAL3_CTRL,
-	  .irq         = 1U << 8,  /* uses DMA 4 and 5 */
-	  .oclrintradr = R_DMA_CH4_CLR_INTR,
-	  .ofirstadr   = R_DMA_CH4_FIRST,
-	  .ocmdadr     = R_DMA_CH4_CMD,
-	  .ostatusadr  = R_DMA_CH4_STATUS,
-	  .iclrintradr = R_DMA_CH5_CLR_INTR,
-	  .ifirstadr   = R_DMA_CH5_FIRST,
-	  .icmdadr     = R_DMA_CH5_CMD,
-	  .idescradr   = R_DMA_CH5_DESCR,
-	  .flags       = STD_FLAGS,
-	  .rx_ctrl     = DEF_RX,
-	  .tx_ctrl     = DEF_TX,
-	  .iseteop     = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-          .enabled  = 1,
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
-	  .dma_out_enabled = 1,
-#else
-	  .dma_out_enabled = 0,
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
-	  .dma_in_enabled = 1,
-#else
-	  .dma_in_enabled = 0
-#endif
-#else
-          .enabled  = 0,
-	  .dma_out_enabled = 0,
-	  .dma_in_enabled = 0
-#endif
- }   /* ttyS3 */
-#endif
-};
-
-
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
-
-static struct termios *serial_termios[NR_PORTS];
-static struct termios *serial_termios_locked[NR_PORTS];
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static struct fast_timer fast_timers[NR_PORTS];
-#endif
-
-#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
-#define PROCSTAT(x) x
-struct ser_statistics_type {
-	int overrun_cnt;
-	int early_errors_cnt;
-	int ser_ints_ok_cnt;
-	int errors_cnt;
-	unsigned long int processing_flip;
-	unsigned long processing_flip_still_room;
-	unsigned long int timeout_flush_cnt;
-	int rx_dma_ints;
-	int tx_dma_ints;
-	int rx_tot;
-	int tx_tot;
-};
-
-static struct ser_statistics_type ser_stat[NR_PORTS];
-
-#else
-
-#define PROCSTAT(x)
-
-#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
-
-/* RS-485 */
-#if defined(CONFIG_ETRAX_RS485)
-#ifdef CONFIG_ETRAX_FAST_TIMER
-static struct fast_timer fast_timers_rs485[NR_PORTS];
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
-#endif
-#endif
-
-/* Info and macros needed for each ports extra control/status signals. */
-#define E100_STRUCT_PORT(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-		(R_PORT_PA_DATA): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-		(R_PORT_PB_DATA):&dummy_ser[line]))
-
-#define E100_STRUCT_SHADOW(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-		(&port_pa_data_shadow): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-		(&port_pb_data_shadow):&dummy_ser[line]))
-#define E100_STRUCT_MASK(line, pinname) \
- ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
-		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
- (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
-		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
-
-#define DUMMY_DTR_MASK 1
-#define DUMMY_RI_MASK  2
-#define DUMMY_DSR_MASK 4
-#define DUMMY_CD_MASK  8
-static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
-
-/* If not all status pins are used or disabled, use mixed mode */
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-
-#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
-
-#if SER0_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
-
-#if SER0_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT0 */
-
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-
-#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
-
-#if SER1_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
-
-#if SER1_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT1 */
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-
-#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
-
-#if SER2_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
-
-#if SER2_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT2 */
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-
-#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
-
-#if SER3_PA_BITSUM != -4
-#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
-#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
-
-#if SER3_PB_BITSUM != -4
-#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#   endif
-# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
-#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#   endif
-#  endif
-#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
-#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
-#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
-#    endif
-#  endif
-#endif
-
-#endif /* PORT3 */
-
-
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
-    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
-#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
-#endif
-
-#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
-/* The pins can be mixed on PA and PB */
-#define CONTROL_PINS_PORT_NOT_USED(line) \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  &dummy_ser[line], &dummy_ser[line], \
-  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
-    
-
-struct control_pins
-{
-	volatile unsigned char *dtr_port;
-	unsigned char          *dtr_shadow;
-	volatile unsigned char *ri_port;
-	unsigned char          *ri_shadow;
-	volatile unsigned char *dsr_port;
-	unsigned char          *dsr_shadow;
-	volatile unsigned char *cd_port;
-	unsigned char          *cd_shadow;
-
-	unsigned char dtr_mask;
-	unsigned char ri_mask;
-	unsigned char dsr_mask;
-	unsigned char cd_mask;
-};
-
-static const struct control_pins e100_modem_pins[NR_PORTS] = 
-{
-	/* Ser 0 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
-	E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
-	E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
-	E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
-	E100_STRUCT_MASK(0,DTR),
-	E100_STRUCT_MASK(0,RI),
-	E100_STRUCT_MASK(0,DSR),
-	E100_STRUCT_MASK(0,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(0)
-#endif	
-	},
-
-	/* Ser 1 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
-	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
-	E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
-	E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
-	E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
-	E100_STRUCT_MASK(1,DTR),
-	E100_STRUCT_MASK(1,RI),
-	E100_STRUCT_MASK(1,DSR),
-	E100_STRUCT_MASK(1,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(1)
-#endif		
-	},
-
-	/* Ser 2 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
-	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
-	E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
-	E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
-	E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
-	E100_STRUCT_MASK(2,DTR),
-	E100_STRUCT_MASK(2,RI),
-	E100_STRUCT_MASK(2,DSR),
-	E100_STRUCT_MASK(2,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(2)
-#endif		
-	},
-
-	/* Ser 3 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
-	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
-	E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
-	E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
-	E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
-	E100_STRUCT_MASK(3,DTR),
-	E100_STRUCT_MASK(3,RI),
-	E100_STRUCT_MASK(3,DSR),
-	E100_STRUCT_MASK(3,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(3)
-#endif		
-	}
-};
-#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
-
-/* All pins are on either PA or PB for each serial port */
-#define CONTROL_PINS_PORT_NOT_USED(line) \
-  &dummy_ser[line], &dummy_ser[line], \
-  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
-    
-
-struct control_pins
-{
-	volatile unsigned char *port;
-	unsigned char          *shadow;
-
-	unsigned char dtr_mask;
-	unsigned char ri_mask;
-	unsigned char dsr_mask;
-	unsigned char cd_mask;
-};
-
-#define dtr_port port
-#define dtr_shadow shadow
-#define ri_port port
-#define ri_shadow shadow
-#define dsr_port port
-#define dsr_shadow shadow
-#define cd_port port
-#define cd_shadow shadow
-
-static const struct control_pins e100_modem_pins[NR_PORTS] = 
-{
-	/* Ser 0 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
-	E100_STRUCT_MASK(0,DTR),
-	E100_STRUCT_MASK(0,RI),
-	E100_STRUCT_MASK(0,DSR),
-	E100_STRUCT_MASK(0,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(0)
-#endif	
-	},
-
-	/* Ser 1 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
-	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
-	E100_STRUCT_MASK(1,DTR),
-	E100_STRUCT_MASK(1,RI),
-	E100_STRUCT_MASK(1,DSR),
-	E100_STRUCT_MASK(1,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(1)
-#endif		
-	},
-
-	/* Ser 2 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
-	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
-	E100_STRUCT_MASK(2,DTR),
-	E100_STRUCT_MASK(2,RI),
-	E100_STRUCT_MASK(2,DSR),
-	E100_STRUCT_MASK(2,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(2)
-#endif		
-	},
-
-	/* Ser 3 */
-	{
-#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
-	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
-	E100_STRUCT_MASK(3,DTR),
-	E100_STRUCT_MASK(3,RI),
-	E100_STRUCT_MASK(3,DSR),
-	E100_STRUCT_MASK(3,CD)
-#else
-	CONTROL_PINS_PORT_NOT_USED(3)
-#endif		
-	}
-};
-#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
-
-#define E100_RTS_MASK 0x20
-#define E100_CTS_MASK 0x40
-
-/* All serial port signals are active low:
- * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
- * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
- *
- * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
- */
-
-/* Output */
-#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
-/* Input */
-#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK)
-
-/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
-/* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
-
-/* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
-
-/* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
-
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-#ifdef DECLARE_MUTEX
-static DECLARE_MUTEX(tmp_buf_sem);
-#else
-static struct semaphore tmp_buf_sem = MUTEX;
-#endif
-
-/* Calculate the chartime depending on baudrate, numbor of bits etc. */
-static void update_char_time(struct e100_serial * info)
-{
-	tcflag_t cflags = info->tty->termios->c_cflag;
-	int bits;
-
-	/* calc. number of bits / data byte */
-	/* databits + startbit and 1 stopbit */
-	if ((cflags & CSIZE) == CS7)
-		bits = 9;
-	else
-		bits = 10;  
-
-	if (cflags & CSTOPB)     /* 2 stopbits ? */
-		bits++;
-
-	if (cflags & PARENB)     /* parity bit ? */
-		bits++;
-
-	/* calc timeout */
-	info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
-	info->flush_time_usec = 4*info->char_time_usec;
-	if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
-		info->flush_time_usec = MIN_FLUSH_TIME_USEC;
-
-}
-
-/*
- * This function maps from the Bxxxx defines in asm/termbits.h into real
- * baud rates.
- */
-
-static int 
-cflag_to_baud(unsigned int cflag)
-{
-	static int baud_table[] = {
-		0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
-		4800, 9600, 19200, 38400 };
-
-	static int ext_baud_table[] = {
-		0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
-                0, 0, 0, 0, 0, 0, 0, 0 };
-
-	if (cflag & CBAUDEX)
-		return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
-	else 
-		return baud_table[cflag & CBAUD];
-}
-
-/* and this maps to an etrax100 hardware baud constant */
-
-static unsigned char 
-cflag_to_etrax_baud(unsigned int cflag)
-{
-	char retval;
-
-	static char baud_table[] = {
-		-1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
-
-	static char ext_baud_table[] = {
-		-1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
-
-	if (cflag & CBAUDEX)
-		retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
-	else 
-		retval = baud_table[cflag & CBAUD];
-
-	if (retval < 0) {
-		printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
-		retval = 5; /* choose default 9600 instead */
-	}
-
-	return retval | (retval << 4); /* choose same for both TX and RX */
-}
-
-
-/* Various static support functions */
-
-/* Functions to set or clear DTR/RTS on the requested line */
-/* It is complicated by the fact that RTS is a serial port register, while
- * DTR might not be implemented in the HW at all, and if it is, it can be on
- * any general port.
- */
-
-
-static inline void 
-e100_dtr(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-	unsigned char mask = e100_modem_pins[info->line].dtr_mask;
-
-#ifdef SERIAL_DEBUG_IO  
-	printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
-	printk("ser%i shadow before 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].dtr_shadow,
-	       E100_DTR_GET(info));
-#endif
-	/* DTR is active low */
-	{
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		*e100_modem_pins[info->line].dtr_shadow &= ~mask;
-		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
-		restore_flags(flags);
-	}
-	
-#ifdef SERIAL_DEBUG_IO
-	printk("ser%i shadow after 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].dtr_shadow, 
-	       E100_DTR_GET(info));
-#endif
-#endif
-}
-
-/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive  
- *                                          0=0V    , 1=3.3V
- */
-static inline void 
-e100_rts(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-	info->rx_ctrl &= ~E100_RTS_MASK;
-	info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
-	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	restore_flags(flags);
-#ifdef SERIAL_DEBUG_IO  
-	printk("ser%i rts %i\n", info->line, set);
-#endif
-#endif
-}
-
-
-/* If this behaves as a modem, RI and CD is an output */
-static inline void 
-e100_ri_out(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-	/* RI is active low */
-	{
-		unsigned char mask = e100_modem_pins[info->line].ri_mask;
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		*e100_modem_pins[info->line].ri_shadow &= ~mask;
-		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
-		restore_flags(flags);
-	}
-#endif
-}
-static inline void 
-e100_cd_out(struct e100_serial *info, int set)
-{
-#ifndef CONFIG_SVINTO_SIM
-	/* CD is active low */
-	{
-		unsigned char mask = e100_modem_pins[info->line].cd_mask;
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		*e100_modem_pins[info->line].cd_shadow &= ~mask;
-		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
-		restore_flags(flags);
-	}
-#endif
-}
-
-static inline void
-e100_disable_rx(struct e100_serial *info)
-{
-#ifndef CONFIG_SVINTO_SIM
-	/* disable the receiver */
-	info->port[REG_REC_CTRL] =
-		(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
-}
-
-static inline void 
-e100_enable_rx(struct e100_serial *info)
-{
-#ifndef CONFIG_SVINTO_SIM
-	/* enable the receiver */
-	info->port[REG_REC_CTRL] =
-		(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
-}
-
-/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
-
-static inline void
-e100_disable_rxdma_irq(struct e100_serial *info) 
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("rxdma_irq(%d): 0\n",info->line);
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
-	*R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
-}
-
-static inline void
-e100_enable_rxdma_irq(struct e100_serial *info) 
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("rxdma_irq(%d): 1\n",info->line);
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
-	*R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
-}
-
-/* the tx DMA uses only dma_descr interrupt */
-
-static _INLINE_ void
-e100_disable_txdma_irq(struct e100_serial *info) 
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("txdma_irq(%d): 0\n",info->line);
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
-	*R_IRQ_MASK2_CLR = info->irq;
-}
-
-static _INLINE_ void
-e100_enable_txdma_irq(struct e100_serial *info) 
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("txdma_irq(%d): 1\n",info->line);
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
-	*R_IRQ_MASK2_SET = info->irq;
-}
-
-static _INLINE_ void
-e100_disable_txdma_channel(struct e100_serial *info)
-{
-	unsigned long flags;
-  
-	/* Disable output DMA channel for the serial port in question
-	 * ( set to something other then serialX)
-	 */
-	save_flags(flags);
-	cli();
-	DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
-	if (info->line == 0) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
-		    IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
-		}
-	} else if (info->line == 1) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
-		    IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
-		}
-	} else if (info->line == 2) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
-		    IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
-		}
-	} else if (info->line == 3) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
-		    IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
-		}
-	}
-	*R_GEN_CONFIG = genconfig_shadow;
-	restore_flags(flags);
-}
-
-
-static _INLINE_ void
-e100_enable_txdma_channel(struct e100_serial *info)
-{
-	unsigned long flags;
-  
-	save_flags(flags);
-	cli();
-	DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
-	/* Enable output DMA channel for the serial port in question */
-	if (info->line == 0) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
-	} else if (info->line == 1) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
-	} else if (info->line == 2) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
-	} else if (info->line == 3) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
-	}
-	*R_GEN_CONFIG = genconfig_shadow;
-	restore_flags(flags);
-}
-
-static _INLINE_ void
-e100_disable_rxdma_channel(struct e100_serial *info)
-{
-	unsigned long flags;
-
-	/* Disable input DMA channel for the serial port in question
-	 * ( set to something other then serialX)
-	 */
-	save_flags(flags);
-	cli();
-	if (info->line == 0) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
-		    IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
-		}
-	} else if (info->line == 1) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
-		    IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
-		}
-	} else if (info->line == 2) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
-		    IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
-		}
-	} else if (info->line == 3) {
-		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
-		    IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
-			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
-			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
-		}
-	}
-	*R_GEN_CONFIG = genconfig_shadow;
-	restore_flags(flags);
-}
-
-
-static _INLINE_ void
-e100_enable_rxdma_channel(struct e100_serial *info)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	/* Enable input DMA channel for the serial port in question */
-	if (info->line == 0) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
-	} else if (info->line == 1) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
-	} else if (info->line == 2) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
-	} else if (info->line == 3) {
-		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
-		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
-	}
-	*R_GEN_CONFIG = genconfig_shadow;
-	restore_flags(flags);
-}
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-/* in order to detect and fix errors on the first byte
-   we have to use the serial interrupts as well. */
-
-static inline void
-e100_disable_serial_data_irq(struct e100_serial *info) 
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("ser_irq(%d): 0\n",info->line);
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
-	*R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
-}
-
-static inline void
-e100_enable_serial_data_irq(struct e100_serial *info) 
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("ser_irq(%d): 1\n",info->line);
-	printk("**** %d = %d\n",
-	       (8+2*info->line),
-	       (1U << (8+2*info->line)));
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
-	*R_IRQ_MASK1_SET = (1U << (8+2*info->line));
-}
-#endif
-
-static inline void
-e100_disable_serial_tx_ready_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("ser_tx_irq(%d): 0\n",info->line);
-#endif
-	DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
-	*R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
-}
-
-static inline void
-e100_enable_serial_tx_ready_irq(struct e100_serial *info)
-{
-#ifdef SERIAL_DEBUG_INTR
-	printk("ser_tx_irq(%d): 1\n",info->line);
-	printk("**** %d = %d\n",
-	       (8+1+2*info->line),
-	       (1U << (8+1+2*info->line)));
-#endif
-	DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
-	*R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
-}
-
-static inline void e100_enable_rx_irq(struct e100_serial *info)
-{
-	if (info->uses_dma_in)
-		e100_enable_rxdma_irq(info);
-	else
-		e100_enable_serial_data_irq(info);
-}
-static inline void e100_disable_rx_irq(struct e100_serial *info)
-{
-	if (info->uses_dma_in)
-		e100_disable_rxdma_irq(info);
-	else
-		e100_disable_serial_data_irq(info);
-}
-
-#if defined(CONFIG_ETRAX_RS485)
-/* Enable RS-485 mode on selected port. This is UGLY. */
-static int
-e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
-{
-	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-
-#if defined(CONFIG_ETRAX_RS485_ON_PA)	
-	*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-	REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
-		       rs485_port_g_bit, 1);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
-	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-		       CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
-	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-		       CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
-#endif
-
-	info->rs485.rts_on_send = 0x01 & r->rts_on_send;
-	info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
-	if (r->delay_rts_before_send >= 1000)
-		info->rs485.delay_rts_before_send = 1000;
-	else
-		info->rs485.delay_rts_before_send = r->delay_rts_before_send;
-	info->rs485.enabled = r->enabled;
-/*	printk("rts: on send = %i, after = %i, enabled = %i",
-		    info->rs485.rts_on_send,
-		    info->rs485.rts_after_sent,
-		    info->rs485.enabled
-	);
-*/		
-	return 0;
-}
-
-static int
-e100_write_rs485(struct tty_struct *tty, int from_user,
-                 const unsigned char *buf, int count)
-{
-	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-	int old_enabled = info->rs485.enabled;
-
-	/* rs485 is always implicitly enabled if we're using the ioctl() 
-	 * but it doesn't have to be set in the rs485_control
-	 * (to be backward compatible with old apps)
-	 * So we store, set and restore it.
-	 */
-	info->rs485.enabled = 1;
-	/* rs_write now deals with RS485 if enabled */
-	count = rs_write(tty, from_user, buf, count);
-	info->rs485.enabled = old_enabled;
-	return count;
-}
-
-#ifdef CONFIG_ETRAX_FAST_TIMER
-/* Timer function to toggle RTS when using FAST_TIMER */
-static void rs485_toggle_rts_timer_function(unsigned long data)
-{
-	struct e100_serial *info = (struct e100_serial *)data;
-
-	fast_timers_rs485[info->line].function = NULL;
-	e100_rts(info, info->rs485.rts_after_sent);
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-	e100_enable_rx(info);
-	e100_enable_rx_irq(info);
-#endif
-}
-#endif
-#endif /* CONFIG_ETRAX_RS485 */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter using the XOFF registers, as necessary.
- * ------------------------------------------------------------
- */
-
-static void 
-rs_stop(struct tty_struct *tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	if (info) {
-		unsigned long flags;
-		unsigned long xoff;
-
-		save_flags(flags); cli();
-		DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
-				CIRC_CNT(info->xmit.head,
-					 info->xmit.tail,SERIAL_XMIT_SIZE)));
-
-		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
-		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
-		if (tty->termios->c_iflag & IXON ) {
-			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-		}
-	
-		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
-		restore_flags(flags);
-	}
-}
-
-static void 
-rs_start(struct tty_struct *tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	if (info) {
-		unsigned long flags;
-		unsigned long xoff;
-
-		save_flags(flags); cli();
-		DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
-				CIRC_CNT(info->xmit.head,
-					 info->xmit.tail,SERIAL_XMIT_SIZE)));
-		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
-		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-		if (tty->termios->c_iflag & IXON ) {
-			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-		}
-	
-		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
-		if (!info->uses_dma_out &&
-		    info->xmit.head != info->xmit.tail && info->xmit.buf)
-			e100_enable_serial_tx_ready_irq(info);
-		
-		restore_flags(flags);
-	}
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static _INLINE_ void 
-rs_sched_event(struct e100_serial *info,
-				    int event)
-{
-	if (info->event & (1 << event))
-		return;
-	info->event |= 1 << event;
-	schedule_work(&info->work);
-}
-
-/* The output DMA channel is free - use it to send as many chars as possible
- * NOTES:
- *   We don't pay attention to info->x_char, which means if the TTY wants to
- *   use XON/XOFF it will set info->x_char but we won't send any X char!
- * 
- *   To implement this, we'd just start a DMA send of 1 byte pointing at a
- *   buffer containing the X char, and skip updating xmit. We'd also have to
- *   check if the last sent char was the X char when we enter this function
- *   the next time, to avoid updating xmit with the sent X value.
- */
-
-static void 
-transmit_chars_dma(struct e100_serial *info)
-{
-	unsigned int c, sentl;
-	struct etrax_dma_descr *descr;
-
-#ifdef CONFIG_SVINTO_SIM
-	/* This will output too little if tail is not 0 always since
-	 * we don't reloop to send the other part. Anyway this SHOULD be a
-	 * no-op - transmit_chars_dma would never really be called during sim
-	 * since rs_write does not write into the xmit buffer then.
-	 */
-	if (info->xmit.tail)
-		printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
-	if (info->xmit.head != info->xmit.tail) {
-		SIMCOUT(info->xmit.buf + info->xmit.tail,
-			CIRC_CNT(info->xmit.head,
-				 info->xmit.tail,
-				 SERIAL_XMIT_SIZE));
-		info->xmit.head = info->xmit.tail;  /* move back head */
-		info->tr_running = 0;
-	}
-	return;
-#endif
-	/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
-	*info->oclrintradr =
-		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
-#ifdef SERIAL_DEBUG_INTR
-	if (info->line == SERIAL_DEBUG_LINE)
-		printk("tc\n");
-#endif
-	if (!info->tr_running) {
-		/* weirdo... we shouldn't get here! */
-		printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
-		return;
-	}
-
-	descr = &info->tr_descr;
-
-	/* first get the amount of bytes sent during the last DMA transfer,
-	   and update xmit accordingly */
-
-	/* if the stop bit was not set, all data has been sent */
-	if (!(descr->status & d_stop)) {
-		sentl = descr->sw_len;
-	} else 
-		/* otherwise we find the amount of data sent here */
-		sentl = descr->hw_len;
-
-	DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
-
-	/* update stats */
-	info->icount.tx += sentl;
-
-	/* update xmit buffer */
-	info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
-
-	/* if there is only a few chars left in the buf, wake up the blocked
-	   write if any */
-	if (CIRC_CNT(info->xmit.head,
-		     info->xmit.tail,
-		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-	/* find out the largest amount of consecutive bytes we want to send now */
-
-	c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-
-	/* Don't send all in one DMA transfer - divide it so we wake up
-	 * application before all is sent
-	 */
-
-	if (c >= 4*WAKEUP_CHARS)
-		c = c/2;
-
-	if (c <= 0) {
-		/* our job here is done, don't schedule any new DMA transfer */
-		info->tr_running = 0;
-
-#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
-		if (info->rs485.enabled) {
-			/* Set a short timer to toggle RTS */
-			start_one_shot_timer(&fast_timers_rs485[info->line],
-			                     rs485_toggle_rts_timer_function,
-			                     (unsigned long)info,
-			                     info->char_time_usec*2,
-			                     "RS-485");
-		}
-#endif /* RS485 */
-		return;
-	}
-
-	/* ok we can schedule a dma send of c chars starting at info->xmit.tail */
-	/* set up the descriptor correctly for output */
-	DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
-	descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
-	descr->sw_len = c;
-	descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
-	descr->status = 0;
-
-	*info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
-	*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-	
-	/* DMA is now running (hopefully) */
-} /* transmit_chars_dma */
-
-static void 
-start_transmit(struct e100_serial *info)
-{
-#if 0
-	if (info->line == SERIAL_DEBUG_LINE)
-		printk("x\n");
-#endif
-
-	info->tr_descr.sw_len = 0;
-	info->tr_descr.hw_len = 0;
-	info->tr_descr.status = 0;
-	info->tr_running = 1;
-	if (info->uses_dma_out)
-		transmit_chars_dma(info);
-	else
-		e100_enable_serial_tx_ready_irq(info);
-} /* start_transmit */
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static int serial_fast_timer_started = 0;
-static int serial_fast_timer_expired = 0;
-static void flush_timeout_function(unsigned long data);
-#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
-  unsigned long timer_flags; \
-  save_flags(timer_flags); \
-  cli(); \
-  if (fast_timers[info->line].function == NULL) { \
-    serial_fast_timer_started++; \
-    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
-    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
-    start_one_shot_timer(&fast_timers[info->line], \
-                         flush_timeout_function, \
-                         (unsigned long)info, \
-                         (usec), \
-                         string); \
-  } \
-  else { \
-    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
-  } \
-  restore_flags(timer_flags); \
-}
-#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
-
-#else
-#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
-#define START_FLUSH_FAST_TIMER(info, string)
-#endif
-
-static struct etrax_recv_buffer *
-alloc_recv_buffer(unsigned int size)
-{
-	struct etrax_recv_buffer *buffer;
-
-	if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
-		return NULL;
-
-	buffer->next = NULL;
-	buffer->length = 0;
-	buffer->error = TTY_NORMAL;
-
-	return buffer;
-}
-
-static void
-append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	if (!info->first_recv_buffer)
-		info->first_recv_buffer = buffer;
-	else
-		info->last_recv_buffer->next = buffer;
-
-	info->last_recv_buffer = buffer;
-
-	info->recv_cnt += buffer->length;
-	if (info->recv_cnt > info->max_recv_cnt)
-		info->max_recv_cnt = info->recv_cnt;
-
-	restore_flags(flags);
-}
-
-static int
-add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
-{
-	struct etrax_recv_buffer *buffer;
-	if (info->uses_dma_in) {
-		if (!(buffer = alloc_recv_buffer(4)))
-			return 0;
-
-		buffer->length = 1;
-		buffer->error = flag;
-		buffer->buffer[0] = data;
-	
-		append_recv_buffer(info, buffer);
-
-		info->icount.rx++;
-	} else {
-		struct tty_struct *tty = info->tty;
-		*tty->flip.char_buf_ptr = data;
-		*tty->flip.flag_buf_ptr = flag;
-		tty->flip.flag_buf_ptr++;
-		tty->flip.char_buf_ptr++;
-		tty->flip.count++;
-		info->icount.rx++;
-	}
-
-	return 1;
-}
-
-extern _INLINE_ unsigned int
-handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
-{
-	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
-
-	if (info->recv_cnt + recvl > 65536) {
-		printk(KERN_CRIT
-		       "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl);
-		return 0;
-	}
-
-	buffer->length = recvl;
-
-	if (info->errorcode == ERRCODE_SET_BREAK)
-		buffer->error = TTY_BREAK;
-	info->errorcode = 0;
-
-	append_recv_buffer(info, buffer);
-
-	if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
-		panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
-
-	descr->buf = virt_to_phys(buffer->buffer);
-	
-	return recvl;
-}
-
-static _INLINE_ unsigned int
-handle_all_descr_data(struct e100_serial *info)
-{
-	struct etrax_dma_descr *descr;
-	unsigned int recvl;
-	unsigned int ret = 0;
-
-	while (1)
-	{
-		descr = &info->rec_descr[info->cur_rec_descr];
-
-		if (descr == phys_to_virt(*info->idescradr))
-			break;
-
-		if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
-			info->cur_rec_descr = 0;
-	
-		/* find out how many bytes were read */
-
-		/* if the eop bit was not set, all data has been received */
-		if (!(descr->status & d_eop)) {
-			recvl = descr->sw_len;
-		} else {
-			/* otherwise we find the amount of data received here */
-			recvl = descr->hw_len;
-		}
-
-		/* Reset the status information */
-		descr->status = 0;
-
-		DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
-			if (info->tty->stopped) {
-				unsigned char *buf = phys_to_virt(descr->buf);
-				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
-				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
-				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
-			}
-			);
-
-		/* update stats */
-		info->icount.rx += recvl;
-
-		ret += handle_descr_data(info, descr, recvl);
-	}
-
-	return ret;
-}
-
-static _INLINE_ void 
-receive_chars_dma(struct e100_serial *info)
-{
-	struct tty_struct *tty;
-	unsigned char rstat;
-
-#ifdef CONFIG_SVINTO_SIM
-	/* No receive in the simulator.  Will probably be when the rest of
-	 * the serial interface works, and this piece will just be removed.
-	 */
-	return;
-#endif
-
-	/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
-	*info->iclrintradr =
-		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-
-	tty = info->tty;
-	if (!tty) /* Something wrong... */
-		return;
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-	if (info->uses_dma_in)
-		e100_enable_serial_data_irq(info);
-#endif	
-
-	if (info->errorcode == ERRCODE_INSERT_BREAK)
-		add_char_and_flag(info, '\0', TTY_BREAK);
-
-	handle_all_descr_data(info);
-
-	/* Read the status register to detect errors */
-	rstat = info->port[REG_STATUS];
-	if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
-		DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
-	}
-
-	if (rstat & SER_ERROR_MASK) {
-		/* If we got an error, we must reset it by reading the
-		 * data_in field
-		 */
-		unsigned char data = info->port[REG_DATA];
-
-		PROCSTAT(ser_stat[info->line].errors_cnt++);
-		DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
-			  ((rstat & SER_ERROR_MASK) << 8) | data);
-
-		if (rstat & SER_PAR_ERR_MASK)
-			add_char_and_flag(info, data, TTY_PARITY);
-		else if (rstat & SER_OVERRUN_MASK)
-			add_char_and_flag(info, data, TTY_OVERRUN);
-		else if (rstat & SER_FRAMING_ERR_MASK)
-			add_char_and_flag(info, data, TTY_FRAME);
-	}
-
-	START_FLUSH_FAST_TIMER(info, "receive_chars");
-
-	/* Restart the receiving DMA */
-	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
-}
-
-static _INLINE_ int
-start_recv_dma(struct e100_serial *info)
-{
-	struct etrax_dma_descr *descr = info->rec_descr;
-	struct etrax_recv_buffer *buffer;
-        int i;
-
-	/* Set up the receiving descriptors */
-	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
-		if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
-			panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
-
-		descr[i].ctrl = d_int;
-		descr[i].buf = virt_to_phys(buffer->buffer);
-		descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
-		descr[i].hw_len = 0;
-		descr[i].status = 0;
-		descr[i].next = virt_to_phys(&descr[i+1]);
-	}
-
-	/* Link the last descriptor to the first */
-	descr[i-1].next = virt_to_phys(&descr[0]);
-
-	/* Start with the first descriptor in the list */
-	info->cur_rec_descr = 0;
-
-	/* Start the DMA */
-	*info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
-	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
-
-	/* Input DMA should be running now */
-	return 1;
-}
-
-static void 
-start_receive(struct e100_serial *info)
-{
-#ifdef CONFIG_SVINTO_SIM
-	/* No receive in the simulator.  Will probably be when the rest of
-	 * the serial interface works, and this piece will just be removed.
-	 */
-	return;
-#endif
-	info->tty->flip.count = 0;
-	if (info->uses_dma_in) {
-		/* reset the input dma channel to be sure it works */
-
-		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-		start_recv_dma(info);
-	}
-}
-
-
-static _INLINE_ void 
-status_handle(struct e100_serial *info, unsigned short status)
-{
-}
-
-/* the bits in the MASK2 register are laid out like this:
-   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
-   where I is the input channel and O is the output channel for the port.
-   info->irq is the bit number for the DMAO_DESCR so to check the others we
-   shift info->irq to the left.
-*/
-
-/* dma output channel interrupt handler
-   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
-   DMA8(ser1) when they have finished a descriptor with the intr flag set.
-*/
-
-static irqreturn_t
-tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct e100_serial *info;
-	unsigned long ireg;
-	int i;
-	int handled = 0;
-        
-#ifdef CONFIG_SVINTO_SIM
-	/* No receive in the simulator.  Will probably be when the rest of
-	 * the serial interface works, and this piece will just be removed.
-	 */
-	{
-		const char *s = "What? tr_interrupt in simulator??\n";
-		SIMCOUT(s,strlen(s));
-	}
-	return IRQ_HANDLED;
-#endif
-	
-	/* find out the line that caused this irq and get it from rs_table */
-	
-	ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
-	
-	for (i = 0; i < NR_PORTS; i++) {
-		info = rs_table + i;
-		if (!info->enabled || !info->uses_dma_out)
-			continue; 
-		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
-		if (ireg & info->irq) {  
-			handled = 1;
-			/* we can send a new dma bunch. make it so. */
-			DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
-			/* Read jiffies_usec first, 
-			 * we want this time to be as late as possible
-			 */
- 			PROCSTAT(ser_stat[info->line].tx_dma_ints++);
-			info->last_tx_active_usec = GET_JIFFIES_USEC();
-			info->last_tx_active = jiffies;
-			transmit_chars_dma(info);
-		}
-		
-		/* FIXME: here we should really check for a change in the
-		   status lines and if so call status_handle(info) */
-	}
-	return IRQ_RETVAL(handled);
-} /* tr_interrupt */
-
-/* dma input channel interrupt handler */
-
-static irqreturn_t
-rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct e100_serial *info;
-	unsigned long ireg;
-	int i;
-	int handled = 0;
-
-#ifdef CONFIG_SVINTO_SIM
-	/* No receive in the simulator.  Will probably be when the rest of
-	 * the serial interface works, and this piece will just be removed.
-	 */
-	{
-		const char *s = "What? rec_interrupt in simulator??\n";
-		SIMCOUT(s,strlen(s));
-	}
-	return IRQ_HANDLED;
-#endif
-	
-	/* find out the line that caused this irq and get it from rs_table */
-	
-	ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
-	
-	for (i = 0; i < NR_PORTS; i++) {
-		info = rs_table + i;
-		if (!info->enabled || !info->uses_dma_in)
-			continue; 
-		/* check for both dma_eop and dma_descr for the input dma channel */
-		if (ireg & ((info->irq << 2) | (info->irq << 3))) {
-			handled = 1; 
-			/* we have received something */
-			receive_chars_dma(info);
-		}
-		
-		/* FIXME: here we should really check for a change in the
-		   status lines and if so call status_handle(info) */
-	}
-	return IRQ_RETVAL(handled);
-} /* rec_interrupt */
-
-static _INLINE_ int
-force_eop_if_needed(struct e100_serial *info)
-{
-	/* We check data_avail bit to determine if data has 
-	 * arrived since last time
-	 */ 
-	unsigned char rstat = info->port[REG_STATUS];
-
-	/* error or datavail? */
-	if (rstat & SER_ERROR_MASK) { 
-		/* Some error has occurred. If there has been valid data, an
-		 * EOP interrupt will be made automatically. If no data, the
-		 * normal ser_interrupt should be enabled and handle it.
-		 * So do nothing!
-		 */
-		DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
-		          rstat | (info->line << 8));
-		return 0;
-	}
-
-	if (rstat & SER_DATA_AVAIL_MASK) { 
-		/* Ok data, no error, count it */
-		TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
-		          rstat | (info->line << 8)));
-		/* Read data to clear status flags */
-		(void)info->port[REG_DATA];
-
-		info->forced_eop = 0;
-		START_FLUSH_FAST_TIMER(info, "magic");
-		return 0;
-	}
-
-	/* hit the timeout, force an EOP for the input
-	 * dma channel if we haven't already
-	 */
-	if (!info->forced_eop) {
-		info->forced_eop = 1;
-		PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
-		TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
-		FORCE_EOP(info);
-	}
-
-	return 1;
-}
-
-extern _INLINE_ void
-flush_to_flip_buffer(struct e100_serial *info)
-{
-	struct tty_struct *tty;
-	struct etrax_recv_buffer *buffer;
-	unsigned int length;
-	unsigned long flags;
-	int max_flip_size;
-
-	if (!info->first_recv_buffer)
-		return;
-
-	save_flags(flags);
-	cli();
-
-	if (!(tty = info->tty)) {
-		restore_flags(flags);
-		return;
-	}
-
-	length = tty->flip.count;
-	/* Don't flip more than the ldisc has room for.
-	 * The return value from ldisc.receive_room(tty) - might not be up to
-	 * date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the
-	 * processed and not accounted for yet.
-	 * Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way.
-	 * Lets buffer data here and let flow control take care of it.
-	 * Since we normally flip large chunks, the ldisc don't react
-	 * with throttle until too late if we flip to much.
-	 */
-	max_flip_size = tty->ldisc.receive_room(tty);
-	if (max_flip_size < 0)
-		max_flip_size = 0;
-	if (max_flip_size <= (TTY_FLIPBUF_SIZE +         /* Maybe not accounted for */
-			      length + info->recv_cnt +  /* We have this queued */
-			      2*SERIAL_DESCR_BUF_SIZE +    /* This could be on the way */
-			      TTY_THRESHOLD_THROTTLE)) { /* Some slack */
-		/* check TTY_THROTTLED first so it indicates our state */
-		if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
-			DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size));
-			rs_throttle(tty);
-		}
-#if 0
-		else if (max_flip_size <= (TTY_FLIPBUF_SIZE +         /* Maybe not accounted for */
-					   length + info->recv_cnt +  /* We have this queued */
-					   SERIAL_DESCR_BUF_SIZE +    /* This could be on the way */
-					   TTY_THRESHOLD_THROTTLE)) { /* Some slack */
-			DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size));
-			rs_throttle(tty);
-		}
-#endif
-	}
-
-	if (max_flip_size > TTY_FLIPBUF_SIZE)
-		max_flip_size = TTY_FLIPBUF_SIZE;
-
-	while ((buffer = info->first_recv_buffer) && length < max_flip_size) {
-		unsigned int count = buffer->length;
-
-		if (length + count > max_flip_size)
-			count = max_flip_size - length;
-
-		memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count);
-		memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count);
-		tty->flip.flag_buf_ptr[length] = buffer->error;
-
-		length += count;
-		info->recv_cnt -= count;
-		DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length));
-
-		if (count == buffer->length) {
-			info->first_recv_buffer = buffer->next;
-			kfree(buffer);
-		} else {
-			buffer->length -= count;
-			memmove(buffer->buffer, buffer->buffer + count, buffer->length);
-			buffer->error = TTY_NORMAL;
-		}
-	}
-
-	if (!info->first_recv_buffer)
-		info->last_recv_buffer = NULL;
-
-	tty->flip.count = length;
-	DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) {
-		DEBUG_LOG(info->line, "ldisc %lu\n",
-			  tty->ldisc.chars_in_buffer(tty));
-		DEBUG_LOG(info->line, "flip.count %lu\n",
-			  tty->flip.count);
-	      }
-	      );
-	restore_flags(flags);
-
-	DFLIP(
-	  if (1) {
-
-		  if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-			  DEBUG_LOG(info->line, "*** TTY_DONT_FLIP set flip.count %i ***\n", tty->flip.count);
-			  DEBUG_LOG(info->line, "*** recv_cnt %i\n", info->recv_cnt);
-		  } else {
-		  }
-		  DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
-		  DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
-		  DEBUG_LOG(info->line, "room  %lu\n", tty->ldisc.receive_room(tty));
-	  }
-
-	);
-
-	/* this includes a check for low-latency */
-	tty_flip_buffer_push(tty);
-}
-
-static _INLINE_ void
-check_flush_timeout(struct e100_serial *info)
-{
-	/* Flip what we've got (if we can) */
-	flush_to_flip_buffer(info);
-
-	/* We might need to flip later, but not to fast
-	 * since the system is busy processing input... */
-	if (info->first_recv_buffer)
-		START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
-
-	/* Force eop last, since data might have come while we're processing
-	 * and if we started the slow timer above, we won't start a fast
-	 * below.
-	 */
-	force_eop_if_needed(info);
-}
-
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-static void flush_timeout_function(unsigned long data)
-{
-	struct e100_serial *info = (struct e100_serial *)data;
-
-	fast_timers[info->line].function = NULL;
-	serial_fast_timer_expired++;
-	TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
-	TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
-	check_flush_timeout(info);
-}
-
-#else
-
-/* dma fifo/buffer timeout handler
-   forces an end-of-packet for the dma input channel if no chars 
-   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
-*/
-
-static struct timer_list flush_timer;
-
-static void 
-timed_flush_handler(unsigned long ptr)
-{
-	struct e100_serial *info;
-	int i;
-
-#ifdef CONFIG_SVINTO_SIM
-	return;
-#endif
-	
-	for (i = 0; i < NR_PORTS; i++) {
-		info = rs_table + i;
-		if (info->uses_dma_in)
-			check_flush_timeout(info);
-	}
-
-	/* restart flush timer */
-	mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
-}
-#endif
-
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-
-/* If there is an error (ie break) when the DMA is running and
- * there are no bytes in the fifo the DMA is stopped and we get no
- * eop interrupt. Thus we have to monitor the first bytes on a DMA
- * transfer, and if it is without error we can turn the serial
- * interrupts off.
- */
-
-/*
-BREAK handling on ETRAX 100:
-ETRAX will generate interrupt although there is no stop bit between the
-characters.
-
-Depending on how long the break sequence is, the end of the breaksequence
-will look differently:
-| indicates start/end of a character.
-
-B= Break character (0x00) with framing error.
-E= Error byte with parity error received after B characters.
-F= "Faked" valid byte received immediately after B characters.
-V= Valid byte
-
-1.
-    B          BL         ___________________________ V
-.._|__________|__________|                           |valid data |
-
-Multiple frame errors with data == 0x00 (B),
-the timing matches up "perfectly" so no extra ending char is detected.
-The RXD pin is 1 in the last interrupt, in that case
-we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
-know if another byte will come and this really is case 2. below 
-(e.g F=0xFF or 0xFE)
-If RXD pin is 0 we can expect another character (see 2. below).
-
-
-2.
-
-    B          B          E or F__________________..__ V
-.._|__________|__________|______    |                 |valid data
-                          "valid" or 
-                          parity error
-
-Multiple frame errors with data == 0x00 (B),
-but the part of the break trigs is interpreted as a start bit (and possibly
-some 0 bits followed by a number of 1 bits and a stop bit).
-Depending on parity settings etc. this last character can be either
-a fake "valid" char (F) or have a parity error (E).
-
-If the character is valid it will be put in the buffer,
-we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
-will set the flags so the tty will handle it,
-if it's an error byte it will not be put in the buffer
-and we set info->errorcode = ERRCODE_INSERT_BREAK.
-
-To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
-of the last faulty char (B) and compares it with the current time:
-If the time elapsed time is less then 2*char_time_usec we will assume
-it's a faked F char and not a Valid char and set 
-info->errorcode = ERRCODE_SET_BREAK. 
-
-Flaws in the above solution:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We use the timer to distinguish a F character from a V character,
-if a V character is to close after the break we might make the wrong decision.
-
-TODO: The break will be delayed until an F or V character is received.
-
-*/
-
-extern _INLINE_
-struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
-{
-	unsigned long data_read;
-	struct tty_struct *tty = info->tty;
-
-	if (!tty) {
-		printk("!NO TTY!\n");
-		return info;
-	}
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) {
-		/* check TTY_THROTTLED first so it indicates our state */
-		if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
-			DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count));
-			rs_throttle(tty);
-		}
-	}
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-		DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count);
-		tty->flip.work.func((void *) tty);
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-			DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count);
-			return info;		/* if TTY_DONT_FLIP is set */
-		}
-	}
-	/* Read data and status at the same time */
-	data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
-more_data:
-	if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
-		DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
-	}
-	DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
-
-	if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
-			  IO_MASK(R_SERIAL0_READ, par_err) |
-			  IO_MASK(R_SERIAL0_READ, overrun) )) {
-		/* An error */
-		info->last_rx_active_usec = GET_JIFFIES_USEC();
-		info->last_rx_active = jiffies;
-		DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
-		DLOG_INT_TRIG(
-		if (!log_int_trig1_pos) {
-			log_int_trig1_pos = log_int_pos;
-			log_int(rdpc(), 0, 0);
-		}
-		);
-
-
-		if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
-		     (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
-			/* Most likely a break, but we get interrupts over and
-			 * over again.
-			 */
-
-			if (!info->break_detected_cnt) {
-				DEBUG_LOG(info->line, "#BRK start\n", 0);
-			}
-			if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
-				/* The RX pin is high now, so the break
-				 * must be over, but....
-				 * we can't really know if we will get another
-				 * last byte ending the break or not.
-				 * And we don't know if the byte (if any) will
-				 * have an error or look valid.
-				 */
-				DEBUG_LOG(info->line, "# BL BRK\n", 0);
-				info->errorcode = ERRCODE_INSERT_BREAK;
-			}
-			info->break_detected_cnt++;
-		} else {
-			/* The error does not look like a break, but could be
-			 * the end of one
-			 */
-			if (info->break_detected_cnt) {
-				DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
-				info->errorcode = ERRCODE_INSERT_BREAK;
-			} else {
-				if (info->errorcode == ERRCODE_INSERT_BREAK) {
-					info->icount.brk++;
-					*tty->flip.char_buf_ptr = 0;
-					*tty->flip.flag_buf_ptr = TTY_BREAK;
-					tty->flip.flag_buf_ptr++;
-					tty->flip.char_buf_ptr++;
-					tty->flip.count++;
-					info->icount.rx++;
-				}
-				*tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
-
-				if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
-					info->icount.parity++;
-					*tty->flip.flag_buf_ptr = TTY_PARITY;
-				} else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
-					info->icount.overrun++;
-					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
-				} else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
-					info->icount.frame++;
-					*tty->flip.flag_buf_ptr = TTY_FRAME;
-				}
-				info->errorcode = 0;
-			}
-			info->break_detected_cnt = 0;
-		}
-	} else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
-		/* No error */
-		DLOG_INT_TRIG(
-		if (!log_int_trig1_pos) {
-			if (log_int_pos >= log_int_size) {
-				log_int_pos = 0;
-			}
-			log_int_trig0_pos = log_int_pos;
-			log_int(rdpc(), 0, 0);
-		}
-		);
-		*tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
-		*tty->flip.flag_buf_ptr = 0;
-	} else {
-		DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
-	}
-
-
-	tty->flip.flag_buf_ptr++;
-	tty->flip.char_buf_ptr++;
-	tty->flip.count++;
-	info->icount.rx++;
-	data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
-	if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
-		DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
-		goto more_data;
-	}
-
-	tty_flip_buffer_push(info->tty);
-	return info;
-}
-
-extern _INLINE_
-struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
-{
-	unsigned char rstat;
-
-#ifdef SERIAL_DEBUG_INTR
-	printk("Interrupt from serport %d\n", i);
-#endif
-/*	DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
-	if (!info->uses_dma_in) {
-		return handle_ser_rx_interrupt_no_dma(info);
-	}
-	/* DMA is used */
-	rstat = info->port[REG_STATUS];
-	if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
-		DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
-	}
-
-	if (rstat & SER_ERROR_MASK) {
-		unsigned char data;
-
-		info->last_rx_active_usec = GET_JIFFIES_USEC();
-		info->last_rx_active = jiffies;
-		/* If we got an error, we must reset it by reading the
-		 * data_in field
-		 */
-		data = info->port[REG_DATA];
-		DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
-		DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
-		if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
-			/* Most likely a break, but we get interrupts over and
-			 * over again.
-			 */
-
-			if (!info->break_detected_cnt) {
-				DEBUG_LOG(info->line, "#BRK start\n", 0);
-			}
-			if (rstat & SER_RXD_MASK) {
-				/* The RX pin is high now, so the break
-				 * must be over, but....
-				 * we can't really know if we will get another
-				 * last byte ending the break or not. 
-				 * And we don't know if the byte (if any) will 
-				 * have an error or look valid.
-				 */
-				DEBUG_LOG(info->line, "# BL BRK\n", 0);
-				info->errorcode = ERRCODE_INSERT_BREAK;
-			}
-			info->break_detected_cnt++;
-		} else {
-			/* The error does not look like a break, but could be
-			 * the end of one
-			 */
-			if (info->break_detected_cnt) {
-				DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
-				info->errorcode = ERRCODE_INSERT_BREAK;
-			} else {
-				if (info->errorcode == ERRCODE_INSERT_BREAK) {
-					info->icount.brk++;
-					add_char_and_flag(info, '\0', TTY_BREAK);
-				}
-
-				if (rstat & SER_PAR_ERR_MASK) {
-					info->icount.parity++;
-					add_char_and_flag(info, data, TTY_PARITY);
-				} else if (rstat & SER_OVERRUN_MASK) {
-					info->icount.overrun++;
-					add_char_and_flag(info, data, TTY_OVERRUN);
-				} else if (rstat & SER_FRAMING_ERR_MASK) {
-					info->icount.frame++;
-					add_char_and_flag(info, data, TTY_FRAME);
-				}
-
-				info->errorcode = 0;
-			}
-			info->break_detected_cnt = 0;
-			DEBUG_LOG(info->line, "#iERR s d %04X\n",
-			          ((rstat & SER_ERROR_MASK) << 8) | data);
-		}
-		PROCSTAT(ser_stat[info->line].early_errors_cnt++);
-	} else { /* It was a valid byte, now let the DMA do the rest */
-		unsigned long curr_time_u = GET_JIFFIES_USEC();
-		unsigned long curr_time = jiffies;
-		
-		if (info->break_detected_cnt) {
-			/* Detect if this character is a new valid char or the
-			 * last char in a break sequence: If LSBits are 0 and
-			 * MSBits are high AND the time is close to the
-			 * previous interrupt we should discard it.
-			 */
-			long elapsed_usec = 
-			  (curr_time - info->last_rx_active) * (1000000/HZ) + 
-			  curr_time_u - info->last_rx_active_usec;
-			if (elapsed_usec < 2*info->char_time_usec) {
-				DEBUG_LOG(info->line, "FBRK %i\n", info->line);
-				/* Report as BREAK (error) and let
-				 * receive_chars_dma() handle it
-				 */
-				info->errorcode = ERRCODE_SET_BREAK;
-			} else {
-				DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
-			}
-			DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
-		}
-
-#ifdef SERIAL_DEBUG_INTR
-		printk("** OK, disabling ser_interrupts\n");
-#endif
-		e100_disable_serial_data_irq(info);
-		DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
-		info->break_detected_cnt = 0;
-
-		PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
-	}
-	/* Restarting the DMA never hurts */
-	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
-	START_FLUSH_FAST_TIMER(info, "ser_int");
-	return info;
-} /* handle_ser_rx_interrupt */
-
-extern _INLINE_ void handle_ser_tx_interrupt(struct e100_serial *info)
-{
-	unsigned long flags;
-
-	if (info->x_char) {
-		unsigned char rstat;
-		DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
-		save_flags(flags); cli();
-		rstat = info->port[REG_STATUS];
-		DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
-
-		info->port[REG_TR_DATA] = info->x_char;
-		info->icount.tx++;
-		info->x_char = 0;
-		/* We must enable since it is disabled in ser_interrupt */
-		e100_enable_serial_tx_ready_irq(info);
-		restore_flags(flags);
-		return;
-	}
-	if (info->uses_dma_out) {
-		unsigned char rstat;
-		int i;
-		/* We only use normal tx interrupt when sending x_char */
-		DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
-		save_flags(flags); cli();
-		rstat = info->port[REG_STATUS];
-		DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
-		e100_disable_serial_tx_ready_irq(info);
-		if (info->tty->stopped)
-			rs_stop(info->tty);
-		/* Enable the DMA channel and tell it to continue */
-		e100_enable_txdma_channel(info);
-		/* Wait 12 cycles before doing the DMA command */
-		for(i = 6;  i > 0; i--)
-			nop();
-
-		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
-		restore_flags(flags);
-		return;
-	}
-	/* Normal char-by-char interrupt */
-	if (info->xmit.head == info->xmit.tail
-	    || info->tty->stopped
-	    || info->tty->hw_stopped) {
-		DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", info->tty->stopped));
-		e100_disable_serial_tx_ready_irq(info);
-		info->tr_running = 0;
-		return;
-	}
-	DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
-	/* Send a byte, rs485 timing is critical so turn of ints */
-	save_flags(flags); cli();
-	info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
-	info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
-	info->icount.tx++;
-	if (info->xmit.head == info->xmit.tail) {
-#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
-		if (info->rs485.enabled) {
-			/* Set a short timer to toggle RTS */
-			start_one_shot_timer(&fast_timers_rs485[info->line],
-			                     rs485_toggle_rts_timer_function,
-			                     (unsigned long)info,
-			                     info->char_time_usec*2,
-			                     "RS-485");
-		}
-#endif /* RS485 */
-		info->last_tx_active_usec = GET_JIFFIES_USEC();
-		info->last_tx_active = jiffies;
-		e100_disable_serial_tx_ready_irq(info);
-		info->tr_running = 0;
-		DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
-	} else {
-		/* We must enable since it is disabled in ser_interrupt */
-		e100_enable_serial_tx_ready_irq(info);
-	}
-	restore_flags(flags);
-
-	if (CIRC_CNT(info->xmit.head,
-		     info->xmit.tail,
-		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-} /* handle_ser_tx_interrupt */
-
-/* result of time measurements:
- * RX duration 54-60 us when doing something, otherwise 6-9 us
- * ser_int duration: just sending: 8-15 us normally, up to 73 us
- */
-static irqreturn_t
-ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	static volatile int tx_started = 0;
-	struct e100_serial *info;
-	int i;
-	unsigned long flags;
-	unsigned long irq_mask1_rd;
-	unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
-	int handled = 0;
-	static volatile unsigned long reentered_ready_mask = 0;
-
-	save_flags(flags); cli();
-	irq_mask1_rd = *R_IRQ_MASK1_RD;
-	/* First handle all rx interrupts with ints disabled */
-	info = rs_table;
-	irq_mask1_rd &= e100_ser_int_mask;
-	for (i = 0; i < NR_PORTS; i++) {
-		/* Which line caused the data irq? */
-		if (irq_mask1_rd & data_mask) {
-			handled = 1;
-			handle_ser_rx_interrupt(info);
-		}
-		info += 1;
-		data_mask <<= 2;
-	}
-	/* Handle tx interrupts with interrupts enabled so we
-	 * can take care of new data interrupts while transmitting
-	 * We protect the tx part with the tx_started flag.
-	 * We disable the tr_ready interrupts we are about to handle and
-	 * unblock the serial interrupt so new serial interrupts may come.
-	 *
-	 * If we get a new interrupt:
-	 *  - it migth be due to synchronous serial ports.
-	 *  - serial irq will be blocked by general irq handler.
-	 *  - async data will be handled above (sync will be ignored).
-	 *  - tx_started flag will prevent us from trying to send again and
-	 *    we will exit fast - no need to unblock serial irq.
-	 *  - Next (sync) serial interrupt handler will be runned with
-	 *    disabled interrupt due to restore_flags() at end of function,
-	 *    so sync handler will not be preempted or reentered.
-	 */
-	if (!tx_started) {
-		unsigned long ready_mask;
-		unsigned long
-		tx_started = 1;
-		/* Only the tr_ready interrupts left */
-		irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
-				 IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
-				 IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
-				 IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
-		while (irq_mask1_rd) {
-			/* Disable those we are about to handle */
-			*R_IRQ_MASK1_CLR = irq_mask1_rd;
-			/* Unblock the serial interrupt */
-			*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
-
-			sti();
-			ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
-			info = rs_table;
-			for (i = 0; i < NR_PORTS; i++) {
-				/* Which line caused the ready irq? */
-				if (irq_mask1_rd & ready_mask) {
-					handled = 1;
-					handle_ser_tx_interrupt(info);
-				}
-				info += 1;
-				ready_mask <<= 2;
-			}
-			/* handle_ser_tx_interrupt enables tr_ready interrupts */
-			cli();
-			/* Handle reentered TX interrupt */
-			irq_mask1_rd = reentered_ready_mask;
-		}
-		cli();
-		tx_started = 0;
-	} else {
-		unsigned long ready_mask;
-		ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
-					     IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
-					     IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
-					     IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
-		if (ready_mask) {
-			reentered_ready_mask |= ready_mask;
-			/* Disable those we are about to handle */
-			*R_IRQ_MASK1_CLR = ready_mask;
-			DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
-		}
-	}
-
-	restore_flags(flags);
-	return IRQ_RETVAL(handled);
-} /* ser_interrupt */
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-static void 
-do_softint(void *private_)
-{
-	struct e100_serial	*info = (struct e100_serial *) private_;
-	struct tty_struct	*tty;
-	
-	tty = info->tty;
-	if (!tty)
-		return;
-	
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
-	}
-}
-
-static int 
-startup(struct e100_serial * info)
-{
-	unsigned long flags;
-	unsigned long xmit_page;
-	int i;
-
-	xmit_page = get_zeroed_page(GFP_KERNEL);
-	if (!xmit_page)
-		return -ENOMEM;
-
-	save_flags(flags); 
-	cli();
-
-	/* if it was already initialized, skip this */
-
-	if (info->flags & ASYNC_INITIALIZED) {
-		restore_flags(flags);
-		free_page(xmit_page);
-		return 0;
-	}
-
-	if (info->xmit.buf)
-		free_page(xmit_page);
-	else
-		info->xmit.buf = (unsigned char *) xmit_page;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
-#endif
-
-#ifdef CONFIG_SVINTO_SIM
-	/* Bits and pieces collected from below.  Better to have them
-	   in one ifdef:ed clause than to mix in a lot of ifdefs,
-	   right? */
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	info->xmit.head = info->xmit.tail = 0;
-	info->first_recv_buffer = info->last_recv_buffer = NULL;
-	info->recv_cnt = info->max_recv_cnt = 0;
-
-	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-		info->rec_descr[i].buf = NULL;
-
-	/* No real action in the simulator, but may set info important
-	   to ioctl. */
-	change_speed(info);
-#else
-
-	/*
-	 * Clear the FIFO buffers and disable them
-	 * (they will be reenabled in change_speed())
-	 */
-
-	/*
-	 * Reset the DMA channels and make sure their interrupts are cleared
-	 */
-
-	if (info->dma_in_enabled) {
-		info->uses_dma_in = 1;
-		e100_enable_rxdma_channel(info);
-
-		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-
-		/* Wait until reset cycle is complete */
-		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
-		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-		/* Make sure the irqs are cleared */
-		*info->iclrintradr =
-			IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-			IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-	} else {
-		e100_disable_rxdma_channel(info);
-	}
-
-	if (info->dma_out_enabled) {
-		info->uses_dma_out = 1;
-		e100_enable_txdma_channel(info);
-		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-
-		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
-		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
-
-		/* Make sure the irqs are cleared */
-		*info->oclrintradr =
-			IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
-			IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
-	} else {
-		e100_disable_txdma_channel(info);
-	}
-
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	info->xmit.head = info->xmit.tail = 0;
-	info->first_recv_buffer = info->last_recv_buffer = NULL;
-	info->recv_cnt = info->max_recv_cnt = 0;
-	
-	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-		info->rec_descr[i].buf = 0;
-
-	/*
-	 * and set the speed and other flags of the serial port
-	 * this will start the rx/tx as well
-	 */
-#ifdef SERIAL_HANDLE_EARLY_ERRORS
-	e100_enable_serial_data_irq(info);
-#endif	
-	change_speed(info);
-
-	/* dummy read to reset any serial errors */
-
-	(void)info->port[REG_DATA];
-
-	/* enable the interrupts */
-	if (info->uses_dma_out)
-		e100_enable_txdma_irq(info);
-
-	e100_enable_rx_irq(info);
-
-	info->tr_running = 0; /* to be sure we don't lock up the transmitter */
-
-	/* setup the dma input descriptor and start dma */
-	
-	start_receive(info);
-	
-	/* for safety, make sure the descriptors last result is 0 bytes written */
-	
-	info->tr_descr.sw_len = 0;
-	info->tr_descr.hw_len = 0;
-	info->tr_descr.status = 0;
-
-	/* enable RTS/DTR last */
-
-	e100_rts(info, 1);
-	e100_dtr(info, 1);
-		
-#endif /* CONFIG_SVINTO_SIM */
-	
-	info->flags |= ASYNC_INITIALIZED;
-	
-	restore_flags(flags);
-	return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void 
-shutdown(struct e100_serial * info)
-{
-	unsigned long flags;
-	struct etrax_dma_descr *descr = info->rec_descr;
-	struct etrax_recv_buffer *buffer;
-	int i;
-
-#ifndef CONFIG_SVINTO_SIM	
-	/* shut down the transmitter and receiver */
-	DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
-	e100_disable_rx(info);
-	info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
-
-	/* disable interrupts, reset dma channels */
-	if (info->uses_dma_in) {
-		e100_disable_rxdma_irq(info);
-		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-		info->uses_dma_in = 0;
-	} else {
-		e100_disable_serial_data_irq(info);
-	}
-
-	if (info->uses_dma_out) {
-		e100_disable_txdma_irq(info);
-		info->tr_running = 0;
-		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
-		info->uses_dma_out = 0;
-	} else {
-		e100_disable_serial_tx_ready_irq(info);
-		info->tr_running = 0;
-	}
-
-#endif /* CONFIG_SVINTO_SIM */
-
-	if (!(info->flags & ASYNC_INITIALIZED))
-		return;
-	
-#ifdef SERIAL_DEBUG_OPEN
-	printk("Shutting down serial port %d (irq %d)....\n", info->line,
-	       info->irq);
-#endif
-	
-	save_flags(flags);
-	cli(); /* Disable interrupts */
-	
-	if (info->xmit.buf) {
-		free_page((unsigned long)info->xmit.buf);
-		info->xmit.buf = NULL;
-	}
-
-	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
-		if (descr[i].buf) {
-			buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
-			kfree(buffer);
-			descr[i].buf = 0;
-		}
-
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
-		/* hang up DTR and RTS if HUPCL is enabled */
-		e100_dtr(info, 0);
-		e100_rts(info, 0); /* could check CRTSCTS before doing this */
-	}
-
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
-	
-	info->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
-}
-
-
-/* change baud rate and other assorted parameters */
-
-static void 
-change_speed(struct e100_serial *info)
-{
-	unsigned int cflag;
-	unsigned long xoff;
-	unsigned long flags;
-	/* first some safety checks */
-	
-	if (!info->tty || !info->tty->termios)
-		return;
-	if (!info->port)
-		return;
-	
-	cflag = info->tty->termios->c_cflag;
-
-	/* possibly, the tx/rx should be disabled first to do this safely */
-	
-	/* change baud-rate and write it to the hardware */
-	if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
-		/* Special baudrate */
-		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
-		unsigned long alt_source =
-				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
-				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
-		/* R_ALT_SER_BAUDRATE selects the source */
-		DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
-		       (unsigned long)info->baud_base, info->custom_divisor));
-		if (info->baud_base == SERIAL_PRESCALE_BASE) {
-			/* 0, 2-65535 (0=65536) */
-			u16 divisor = info->custom_divisor;
-			/* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
-			/* baudrate is 3.125MHz/custom_divisor */
-			alt_source =
-				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
-				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
-			alt_source = 0x11;
-			DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
-			*R_SERIAL_PRESCALE = divisor;
-			info->baud = SERIAL_PRESCALE_BASE/divisor;
-		}
-#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
-		else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
-			  info->custom_divisor == 1) ||
-			 (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
-			  info->custom_divisor == 8)) {
-				/* ext_clk selected */
-				alt_source =
-					IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
-					IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
-				DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
-				info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
-			}
-		}
-#endif
-		else
-		{
-			/* Bad baudbase, we don't support using timer0
-			 * for baudrate.
-			 */
-			printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
-			       (unsigned long)info->baud_base, info->custom_divisor);
-		}
-		r_alt_ser_baudrate_shadow &= ~mask;
-		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-	} else {
-		/* Normal baudrate */
-		/* Make sure we use normal baudrate */
-		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
-		unsigned long alt_source =
-			IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
-			IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
-		r_alt_ser_baudrate_shadow &= ~mask;
-		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-#ifndef CONFIG_SVINTO_SIM
-		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-#endif /* CONFIG_SVINTO_SIM */
-
-		info->baud = cflag_to_baud(cflag);
-#ifndef CONFIG_SVINTO_SIM
-		info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
-#endif /* CONFIG_SVINTO_SIM */
-	}
-	
-#ifndef CONFIG_SVINTO_SIM
-	/* start with default settings and then fill in changes */
-	save_flags(flags);
-	cli();
-	/* 8 bit, no/even parity */
-	info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
-			   IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
-			   IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
-
-	/* 8 bit, no/even parity, 1 stop bit, no cts */
-	info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
-			   IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
-			   IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
-			   IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
-			   IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
-	
-	if ((cflag & CSIZE) == CS7) {
-		/* set 7 bit mode */
-		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
-		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
-	}
-	
-	if (cflag & CSTOPB) {
-		/* set 2 stop bit mode */
-		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
-	}	  
-	
-	if (cflag & PARENB) {
-		/* enable parity */
-		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
-		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
-	}
-	
-	if (cflag & CMSPAR) {
-		/* enable stick parity, PARODD mean Mark which matches ETRAX */
-		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
-		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
-	}
-	if (cflag & PARODD) {
-		/* set odd parity (or Mark if CMSPAR) */
-		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
-		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
-	}
-	
-	if (cflag & CRTSCTS) {
-		/* enable automatic CTS handling */
-		DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
-		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
-	}
-	
-	/* make sure the tx and rx are enabled */
-	
-	info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
-	info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
-
-	/* actually write the control regs to the hardware */
-	
-	info->port[REG_TR_CTRL] = info->tx_ctrl;
-	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
-	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-	if (info->tty->termios->c_iflag & IXON ) {
-		DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->tty)));
-		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
-	}
-	
-	*((unsigned long *)&info->port[REG_XOFF]) = xoff;
-	restore_flags(flags);
-#endif /* !CONFIG_SVINTO_SIM */
-
-	update_char_time(info);
-
-} /* change_speed */
-
-/* start transmitting chars NOW */
-
-static void 
-rs_flush_chars(struct tty_struct *tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (info->tr_running ||
-	    info->xmit.head == info->xmit.tail ||
-	    tty->stopped ||
-	    tty->hw_stopped ||
-	    !info->xmit.buf)
-		return;
-
-#ifdef SERIAL_DEBUG_FLOW
-	printk("rs_flush_chars\n");
-#endif
-	
-	/* this protection might not exactly be necessary here */
-	
-	save_flags(flags);
-	cli();
-	start_transmit(info);
-	restore_flags(flags);
-}
-
-extern _INLINE_ int
-rs_raw_write(struct tty_struct * tty, int from_user,
-	  const unsigned char *buf, int count)
-{
-	int	c, ret = 0;
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	unsigned long flags;
-	
-	/* first some sanity checks */
-	
-	if (!tty || !info->xmit.buf || !tmp_buf)
-		return 0;
-	
-#ifdef SERIAL_DEBUG_DATA
-	if (info->line == SERIAL_DEBUG_LINE)
-		printk("rs_raw_write (%d), status %d\n",
-		       count, info->port[REG_STATUS]);
-#endif
-
-#ifdef CONFIG_SVINTO_SIM
-	/* Really simple.  The output is here and now. */
-	SIMCOUT(buf, count);
-	return count;
-#endif
-	save_flags(flags);
-	DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
-	DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
-
-	
-	/* the cli/restore_flags pairs below are needed because the
-	 * DMA interrupt handler moves the info->xmit values. the memcpy
-	 * needs to be in the critical region unfortunately, because we
-	 * need to read xmit values, memcpy, write xmit values in one
-	 * atomic operation... this could perhaps be avoided by more clever
-	 * design.
-	 */
-	if (from_user) {
-		down(&tmp_buf_sem);
-		while (1) {
-			int c1;
-			c = CIRC_SPACE_TO_END(info->xmit.head,
-					      info->xmit.tail,
-					      SERIAL_XMIT_SIZE);
-			if (count < c)
-				c = count;
-			if (c <= 0)
-				break;
-
-			c -= copy_from_user(tmp_buf, buf, c);
-			if (!c) {
-				if (!ret)
-					ret = -EFAULT;
-				break;
-			}
-			cli();
-			c1 = CIRC_SPACE_TO_END(info->xmit.head,
-					       info->xmit.tail,
-					       SERIAL_XMIT_SIZE);
-			if (c1 < c)
-				c = c1;
-			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
-			info->xmit.head = ((info->xmit.head + c) &
-					   (SERIAL_XMIT_SIZE-1));
-			restore_flags(flags);
-			buf += c;
-			count -= c;
-			ret += c;
-		}
-		up(&tmp_buf_sem);
-	} else {
-		cli();
-		while (count) {
-			c = CIRC_SPACE_TO_END(info->xmit.head,
-					      info->xmit.tail,
-					      SERIAL_XMIT_SIZE);
-
-			if (count < c)
-				c = count;
-			if (c <= 0)
-				break;
-		
-			memcpy(info->xmit.buf + info->xmit.head, buf, c);
-			info->xmit.head = (info->xmit.head + c) &
-				(SERIAL_XMIT_SIZE-1);
-			buf += c;
-			count -= c;
-			ret += c;
-		}
-		restore_flags(flags);
-	}
-	
-	/* enable transmitter if not running, unless the tty is stopped
-	 * this does not need IRQ protection since if tr_running == 0
-	 * the IRQ's are not running anyway for this port.
-	 */
-	DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
-	
-	if (info->xmit.head != info->xmit.tail &&
-	    !tty->stopped &&
-	    !tty->hw_stopped &&
-	    !info->tr_running) {
-		start_transmit(info);
-	}
- 	
-	return ret;
-} /* raw_raw_write() */
-
-static int 
-rs_write(struct tty_struct * tty, int from_user,
-	 const unsigned char *buf, int count)
-{
-#if defined(CONFIG_ETRAX_RS485)
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-	if (info->rs485.enabled)
-	{
-		/* If we are in RS-485 mode, we need to toggle RTS and disable
-		 * the receiver before initiating a DMA transfer
-		 */
-#ifdef CONFIG_ETRAX_FAST_TIMER
-		/* Abort any started timer */
-		fast_timers_rs485[info->line].function = NULL;
-		del_fast_timer(&fast_timers_rs485[info->line]);
-#endif
-		e100_rts(info, info->rs485.rts_on_send);
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-		e100_disable_rx(info);
-		e100_enable_rx_irq(info);
-#endif
-
-		if (info->rs485.delay_rts_before_send > 0) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000);
-		}
-	}
-#endif /* CONFIG_ETRAX_RS485 */
-
-	count = rs_raw_write(tty, from_user, buf, count);
-
-#if defined(CONFIG_ETRAX_RS485)
-	if (info->rs485.enabled)
-	{
-		unsigned int val;
-		/* If we are in RS-485 mode the following has to be done:
-		 * wait until DMA is ready
-		 * wait on transmit shift register
-		 * toggle RTS
-		 * enable the receiver
-		 */	
-
-		/* Sleep until all sent */
-		tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_FAST_TIMER
-		/* Now sleep a little more so that shift register is empty */
-		schedule_usleep(info->char_time_usec * 2);
-#endif
-		/* wait on transmit shift register */
-		do{
-			get_lsr_info(info, &val);
-		}while (!(val & TIOCSER_TEMT));
-
-		e100_rts(info, info->rs485.rts_after_sent);
-	
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-		e100_enable_rx(info);
-		e100_enable_rxdma_irq(info);
-#endif
-	}
-#endif /* CONFIG_ETRAX_RS485 */
-
-	return count;
-} /* rs_write */
-
-
-/* how much space is available in the xmit buffer? */
-
-static int 
-rs_write_room(struct tty_struct *tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	
-	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-/* How many chars are in the xmit buffer?
- * This does not include any chars in the transmitter FIFO.
- * Use wait_until_sent for waiting for FIFO drain.
- */
-
-static int 
-rs_chars_in_buffer(struct tty_struct *tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-/* discard everything in the xmit buffer */
-
-static void 
-rs_flush_buffer(struct tty_struct *tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
-	info->xmit.head = info->xmit.tail = 0;
-	restore_flags(flags);
-
-	wake_up_interruptible(&tty->write_wait);
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- *
- * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
- * but we do it in handle_ser_tx_interrupt().
- * We disable DMA channel and enable tx ready interrupt and write the
- * character when possible.
- */
-static void rs_send_xchar(struct tty_struct *tty, char ch)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	unsigned long flags;
-	save_flags(flags); cli();
-	if (info->uses_dma_out) {
-		/* Put the DMA on hold and disable the channel */
-		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
-		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
-		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
-		e100_disable_txdma_channel(info);
-	}
-
-	/* Must make sure transmitter is not stopped before we can transmit */
-	if (tty->stopped)
-		rs_start(tty);
-
-	/* Enable manual transmit interrupt and send from there */
-	DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
-	info->x_char = ch;
-	e100_enable_serial_tx_ready_irq(info);
-	restore_flags(flags);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void 
-rs_throttle(struct tty_struct * tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-
-	printk("throttle %s: %lu....\n", tty_name(tty, buf),
-	       (unsigned long)tty->ldisc.chars_in_buffer(tty));
-#endif
-	DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
-
-	/* Do RTS before XOFF since XOFF might take some time */
-	if (tty->termios->c_cflag & CRTSCTS) {
-		/* Turn off RTS line */
-		e100_rts(info, 0);
-	}
-	if (I_IXOFF(tty))
-		rs_send_xchar(tty, STOP_CHAR(tty));
-
-}
-
-static void 
-rs_unthrottle(struct tty_struct * tty)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-
-	printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
-	       (unsigned long)tty->ldisc.chars_in_buffer(tty));
-#endif
-	DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
-	DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
-	/* Do RTS before XOFF since XOFF might take some time */
-	if (tty->termios->c_cflag & CRTSCTS) {
-		/* Assert RTS line  */
-		e100_rts(info, 1);
-	}
-
-	if (I_IXOFF(tty)) {
-		if (info->x_char)
-			info->x_char = 0;
-		else
-			rs_send_xchar(tty, START_CHAR(tty));
-	}
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int 
-get_serial_info(struct e100_serial * info,
-		struct serial_struct * retinfo)
-{
-	struct serial_struct tmp;
-	
-	/* this is all probably wrong, there are a lot of fields
-	 * here that we don't have in e100_serial and maybe we
-	 * should set them to something else than 0.
-	 */
-
-	if (!retinfo)
-		return -EFAULT;
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.type = info->type;
-	tmp.line = info->line;
-	tmp.port = (int)info->port;
-	tmp.irq = info->irq;
-	tmp.flags = info->flags;
-	tmp.baud_base = info->baud_base;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
-	tmp.custom_divisor = info->custom_divisor;
-	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
-		return -EFAULT;
-	return 0;
-}
-
-static int
-set_serial_info(struct e100_serial *info,
-		struct serial_struct *new_info)
-{
-	struct serial_struct new_serial;
-	struct e100_serial old_info;
-	int retval = 0;
-
-	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
-		return -EFAULT;
-
-	old_info = *info;
-	
-	if (!capable(CAP_SYS_ADMIN)) {
-		if ((new_serial.type != info->type) ||
-		    (new_serial.close_delay != info->close_delay) ||
-		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (info->flags & ~ASYNC_USR_MASK)))
-			return -EPERM;
-		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-			       (new_serial.flags & ASYNC_USR_MASK));
-		goto check_and_exit;
-	}
-	
-	if (info->count > 1)
-		return -EBUSY;
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	info->baud_base = new_serial.baud_base;
-	info->flags = ((info->flags & ~ASYNC_FLAGS) |
-		       (new_serial.flags & ASYNC_FLAGS));
-	info->custom_divisor = new_serial.custom_divisor;
-	info->type = new_serial.type;
-	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-	if (info->flags & ASYNC_INITIALIZED) {
-		change_speed(info);
-	} else
-		retval = startup(info);
-	return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
- */
-static int 
-get_lsr_info(struct e100_serial * info, unsigned int *value)
-{
-	unsigned int result = TIOCSER_TEMT;
-#ifndef CONFIG_SVINTO_SIM
-	unsigned long curr_time = jiffies;
-	unsigned long curr_time_usec = GET_JIFFIES_USEC();
-	unsigned long elapsed_usec = 
-		(curr_time - info->last_tx_active) * 1000000/HZ + 
-		curr_time_usec - info->last_tx_active_usec;
-
-	if (info->xmit.head != info->xmit.tail || 
-	    elapsed_usec < 2*info->char_time_usec) {
-		result = 0;
-	}
-#endif
-
-	if (copy_to_user(value, &result, sizeof(int)))
-		return -EFAULT;
-	return 0;
-}
-
-#ifdef SERIAL_DEBUG_IO 
-struct state_str
-{
-	int state;
-	const char *str;
-};
-
-const struct state_str control_state_str[] = {
-	{TIOCM_DTR, "DTR" },
-	{TIOCM_RTS, "RTS"},
-	{TIOCM_ST, "ST?" },
-	{TIOCM_SR, "SR?" },
-	{TIOCM_CTS, "CTS" },
-	{TIOCM_CD, "CD" },
-	{TIOCM_RI, "RI" },
-	{TIOCM_DSR, "DSR" },
-	{0, NULL }
-};
-
-char *get_control_state_str(int MLines, char *s)
-{
-	int i = 0;
-
-	s[0]='\0';
-	while (control_state_str[i].str != NULL) {
-		if (MLines & control_state_str[i].state) {
-			if (s[0] != '\0') {
-				strcat(s, ", ");
-			}
-			strcat(s, control_state_str[i].str);
-		}
-		i++;
-	}
-	return s;
-}
-#endif
-
-static int 
-get_modem_info(struct e100_serial * info, unsigned int *value)
-{
-	unsigned int result;
-	/* Polarity isn't verified */
-#if 0 /*def SERIAL_DEBUG_IO  */
-
-	printk("get_modem_info: RTS: %i DTR: %i CD: %i RI: %i DSR: %i CTS: %i\n",
-	       E100_RTS_GET(info),
-	       E100_DTR_GET(info),
-	       E100_CD_GET(info),
-	       E100_RI_GET(info),
-	       E100_DSR_GET(info),
-	       E100_CTS_GET(info));
-#endif
-
-	result =  
-		(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
-		| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-		| (!E100_RI_GET(info) ? TIOCM_RNG : 0)
-		| (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
-		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
-		| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-
-#ifdef SERIAL_DEBUG_IO 
-	printk("e100ser: modem state: %i 0x%08X\n", result, result);
-	{
-		char s[100];
-		
-		get_control_state_str(result, s);
-		printk("state: %s\n", s);
-	}
-#endif  
-	if (copy_to_user(value, &result, sizeof(int)))
-		return -EFAULT;
-	return 0;
-}
-
-
-static int
-set_modem_info(struct e100_serial * info, unsigned int cmd,
-	       unsigned int *value)
-{
-	unsigned int arg;
-
-	if (copy_from_user(&arg, value, sizeof(int)))
-		return -EFAULT;
-
-	switch (cmd) {
-	case TIOCMBIS: 
-		if (arg & TIOCM_RTS) {
-			e100_rts(info, 1);
-		}
-		if (arg & TIOCM_DTR) {
-			e100_dtr(info, 1);
-		}
-		/* Handle FEMALE behaviour */
-		if (arg & TIOCM_RI) {
-			e100_ri_out(info, 1);
-		}
-		if (arg & TIOCM_CD) {
-			e100_cd_out(info, 1);
-		}
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS) {
-			e100_rts(info, 0);
-		}
-		if (arg & TIOCM_DTR) {
-			e100_dtr(info, 0);
-		}
-		/* Handle FEMALE behaviour */
-		if (arg & TIOCM_RI) {
-			e100_ri_out(info, 0);
-		}
-		if (arg & TIOCM_CD) {
-			e100_cd_out(info, 0);
-		}
-		break;
-	case TIOCMSET:
-		e100_rts(info, arg & TIOCM_RTS);
-		e100_dtr(info, arg & TIOCM_DTR);
-		/* Handle FEMALE behaviour */
-		e100_ri_out(info, arg & TIOCM_RI);
-		e100_cd_out(info, arg & TIOCM_CD);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-
-static void 
-rs_break(struct tty_struct *tty, int break_state)
-{
-	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (!info->port)
-		return;
-	
-	save_flags(flags);
-	cli();
-	if (break_state == -1) {
-		/* Go to manual mode and set the txd pin to 0 */
-		info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */
-	} else {
-		info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
-	}
-	info->port[REG_TR_CTRL] = info->tx_ctrl;
-	restore_flags(flags);
-}
-
-static int 
-rs_ioctl(struct tty_struct *tty, struct file * file,
-	 unsigned int cmd, unsigned long arg)
-{
-	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-	
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
-			return -EIO;
-	}
-	
-	switch (cmd) {
-		case TIOCMGET:
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
-		case TIOCGSERIAL:
-			return get_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSSERIAL:
-			return set_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSERGETLSR: /* Get line status register */
-			return get_lsr_info(info, (unsigned int *) arg);
-
-		case TIOCSERGSTRUCT:
-			if (copy_to_user((struct e100_serial *) arg,
-					 info, sizeof(struct e100_serial)))
-				return -EFAULT;
-			return 0;
-
-#if defined(CONFIG_ETRAX_RS485)
-		case TIOCSERSETRS485:
-		{
-			struct rs485_control rs485ctrl;
-			if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl)))
-				return -EFAULT;
-
-			return e100_enable_rs485(tty, &rs485ctrl);
-		}
-
-		case TIOCSERWRRS485:
-		{
-			struct rs485_write rs485wr;
-			if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr)))
-				return -EFAULT;
-
-			return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size);
-		}
-#endif
-			
-		default:
-			return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
-static void 
-rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-
-	if (tty->termios->c_cflag == old_termios->c_cflag &&
-	    tty->termios->c_iflag == old_termios->c_iflag)
-		return;
-
-	change_speed(info);
-
-	/* Handle turning off CRTSCTS */
-	if ((old_termios->c_cflag & CRTSCTS) &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = 0;
-		rs_start(tty);
-	}
-	
-}
-
-/* In debugport.c - register a console write function that uses the normal
- * serial driver
- */
-typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
-
-extern debugport_write_function debug_write_function;
-
-static int rs_debug_write_function(int i, const char *buf, unsigned int len)
-{
-	int cnt;
-	int written = 0;
-        struct tty_struct *tty;
-        static int recurse_cnt = 0;
-
-        tty = rs_table[i].tty;
-        if (tty)  {
-		unsigned long flags;
-		if (recurse_cnt > 5) /* We skip this debug output */
-			return 1;
-
-		local_irq_save(flags);
-		recurse_cnt++;
-		local_irq_restore(flags);
-                do {
-                        cnt = rs_write(tty, 0, buf + written, len);
-                        if (cnt >= 0) {
-				written += cnt;
-                                buf += cnt;
-                                len -= cnt;
-                        } else
-                                len = cnt;
-                } while(len > 0);
-		local_irq_save(flags);
-		recurse_cnt--;
-		local_irq_restore(flags);
-                return 1;
-        }
-        return 0;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void 
-rs_close(struct tty_struct *tty, struct file * filp)
-{
-	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (!info)
-		return;
-  
-	/* interrupts are disabled for this entire function */
-  
-	save_flags(flags); 
-	cli();
-  
-	if (tty_hung_up_p(filp)) {
-		restore_flags(flags);
-		return;
-	}
-  
-#ifdef SERIAL_DEBUG_OPEN
-	printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, 
-	       info->line, info->count);
-#endif
-	if ((tty->count == 1) && (info->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Info->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk(KERN_CRIT
-		       "rs_close: bad serial port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
-	}
-	if (--info->count < 0) {
-		printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
-	}
-	if (info->count) {
-		restore_flags(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-	/*
-	 * Save the termios structure, since this port may have
-	 * separate termios for callout and dialin.
-	 */
-	if (info->flags & ASYNC_NORMAL_ACTIVE)
-		info->normal_termios = *tty->termios;
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the serial receiver and the DMA receive interrupt.
-	 */
-#ifdef SERIAL_HANDLE_EARLY_ERRORS 
-	e100_disable_serial_data_irq(info);
-#endif
-
-#ifndef CONFIG_SVINTO_SIM
-	e100_disable_rx(info);
-	e100_disable_rx_irq(info);
-
-	if (info->flags & ASYNC_INITIALIZED) {
-		/*
-		 * Before we drop DTR, make sure the UART transmitter
-		 * has completely drained; this is especially
-		 * important as we have a transmit FIFO!
-		 */
-		rs_wait_until_sent(tty, HZ);
-	}
-#endif
-
-	shutdown(info);
-	if (tty->driver->flush_buffer)
-		tty->driver->flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-	tty->closing = 0;
-	info->event = 0;
-	info->tty = 0;
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(info->close_delay);
-		}
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-	restore_flags(flags);
-
-	/* port closed */
-
-#if defined(CONFIG_ETRAX_RS485)
-	if (info->rs485.enabled) {
-		info->rs485.enabled = 0;
-#if defined(CONFIG_ETRAX_RS485_ON_PA)
-		*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
-#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-		REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-			       rs485_port_g_bit, 0);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
-		REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-			       CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
-		REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
-			       CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
-#endif
-	}
-#endif
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	unsigned long orig_jiffies;
-	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
-	unsigned long curr_time = jiffies;
-	unsigned long curr_time_usec = GET_JIFFIES_USEC();
-	long elapsed_usec = 
-		(curr_time - info->last_tx_active) * (1000000/HZ) + 
-		curr_time_usec - info->last_tx_active_usec;
-
-	/*
-	 * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
-	 * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
-	 */
-	orig_jiffies = jiffies;
-	while (info->xmit.head != info->xmit.tail || /* More in send queue */
-	       (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
-	       (elapsed_usec < 2*info->char_time_usec)) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-		if (signal_pending(current))
-			break;
-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
-			break;
-		curr_time = jiffies;
-		curr_time_usec = GET_JIFFIES_USEC();
-		elapsed_usec = 
-			(curr_time - info->last_tx_active) * (1000000/HZ) + 
-			curr_time_usec - info->last_tx_active_usec;
-	}
-	set_current_state(TASK_RUNNING);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void 
-rs_hangup(struct tty_struct *tty)
-{
-	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-	
-	rs_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = 0;
-	wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int 
-block_til_ready(struct tty_struct *tty, struct file * filp,
-		struct e100_serial *info)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long	flags;
-	int		retval;
-	int		do_clocal = 0, extra_count = 0;
-	
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		if (info->flags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-	
-	if (tty->termios->c_cflag & CLOCAL) {
-			do_clocal = 1;
-	}
-	
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * rs_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttyS%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	save_flags(flags); 
-	cli();
-	if (!tty_hung_up_p(filp)) {
-		extra_count++;
-		info->count--;
-	}
-	restore_flags(flags);
-	info->blocked_open++;
-	while (1) {
-		save_flags(flags);
-		cli();
-		/* assert RTS and DTR */
-		e100_rts(info, 1);
-		e100_dtr(info, 1);
-		restore_flags(flags);
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ASYNC_CLOSING) && do_clocal)
-			/* && (do_clocal || DCD_IS_ASSERTED) */
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttyS%d, count = %d\n",
-		       info->line, info->count);
-#endif
-		schedule();
-	}
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
-	if (extra_count)
-		info->count++;
-	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return 0;
-}	
-
-/*
- * This routine is called whenever a serial port is opened. 
- * It performs the serial-specific initialization for the tty structure.
- */
-static int 
-rs_open(struct tty_struct *tty, struct file * filp)
-{
-	struct e100_serial	*info;
-	int 			retval, line;
-	unsigned long           page;
-
-	/* find which port we want to open */
-
-	line = tty->index;
-  
-	if (line < 0 || line >= NR_PORTS)
-		return -ENODEV;
-
-	/* find the corresponding e100_serial struct in the table */
-	info = rs_table + line;
-
-	/* don't allow the opening of ports that are not enabled in the HW config */
-	if (!info->enabled)
-		return -ENODEV; 
-  
-#ifdef SERIAL_DEBUG_OPEN
-        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
- 	       info->count);
-#endif
-
-	info->count++;
-	tty->driver_data = info;
-	info->tty = tty;
-
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			return -ENOMEM;
-		}
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-
-	/*
-	 * If the port is in the middle of closing, bail out now
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * Start up the serial port
-	 */
-
-	retval = startup(info);
-	if (retval)
-		return retval;
-  
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("rs_open returning after block_til_ready with %d\n",
-		       retval);
-#endif
-		return retval;
-	}
-
-	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		*tty->termios = info->normal_termios;
-		change_speed(info);
-	}
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open ttyS%d successful...\n", info->line);
-#endif
-	DLOG_INT_TRIG( log_int_pos = 0);
-
-	DFLIP(	if (info->line == SERIAL_DEBUG_LINE) {
-			info->icount.rx = 0;
-		} );
-
-	return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-extern _INLINE_ int line_info(char *buf, struct e100_serial *info)
-{
-	char	stat_buf[30];
-	int	ret;
-	unsigned long tmp;
-
-	ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
-		      info->line, (unsigned long)info->port, info->irq);
-
-	if (!info->port || (info->type == PORT_UNKNOWN)) {
-		ret += sprintf(buf+ret, "\n");
-		return ret;
-	}
-
-	stat_buf[0] = 0;
-	stat_buf[1] = 0;
-	if (!E100_RTS_GET(info))
-		strcat(stat_buf, "|RTS");
-	if (!E100_CTS_GET(info))
-		strcat(stat_buf, "|CTS");
-	if (!E100_DTR_GET(info))
-		strcat(stat_buf, "|DTR");
-	if (!E100_DSR_GET(info))
-		strcat(stat_buf, "|DSR");
-	if (!E100_CD_GET(info))
-		strcat(stat_buf, "|CD");
-	if (!E100_RI_GET(info))
-		strcat(stat_buf, "|RI");
-
-	ret += sprintf(buf+ret, " baud:%d", info->baud);
-
-	ret += sprintf(buf+ret, " tx:%lu rx:%lu",
-		       (unsigned long)info->icount.tx,
-		       (unsigned long)info->icount.rx);
-	tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-	if (tmp) {
-		ret += sprintf(buf+ret, " tx_pend:%lu/%lu",
-			       (unsigned long)tmp,
-			       (unsigned long)SERIAL_XMIT_SIZE);
-	}
-
-	ret += sprintf(buf+ret, " rx_pend:%lu/%lu",
-		       (unsigned long)info->recv_cnt,
-		       (unsigned long)info->max_recv_cnt);
-
-#if 1
-	if (info->tty) {
-
-		if (info->tty->stopped)
-			ret += sprintf(buf+ret, " stopped:%i",
-				       (int)info->tty->stopped);
-		if (info->tty->hw_stopped)
-			ret += sprintf(buf+ret, " hw_stopped:%i",
-				       (int)info->tty->hw_stopped);
-	}
-
-	{
-		unsigned char rstat = info->port[REG_STATUS];
-		if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) )
-			ret += sprintf(buf+ret, " xoff_detect:1");
-	}
-
-#endif
-
-
-
-
-	if (info->icount.frame)
-		ret += sprintf(buf+ret, " fe:%lu",
-			       (unsigned long)info->icount.frame);
-	
-	if (info->icount.parity)
-		ret += sprintf(buf+ret, " pe:%lu",
-			       (unsigned long)info->icount.parity);
-	
-	if (info->icount.brk)
-		ret += sprintf(buf+ret, " brk:%lu",
-			       (unsigned long)info->icount.brk);	
-
-	if (info->icount.overrun)
-		ret += sprintf(buf+ret, " oe:%lu",
-			       (unsigned long)info->icount.overrun);
-
-	/*
-	 * Last thing is the RS-232 status lines
-	 */
-	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-	return ret;
-}
-
-int rs_read_proc(char *page, char **start, off_t off, int count,
-		 int *eof, void *data)
-{
-	int i, len = 0, l;
-	off_t	begin = 0;
-
-	len += sprintf(page, "serinfo:1.0 driver:%s\n",
-		       serial_version);
-	for (i = 0; i < NR_PORTS && len < 4000; i++) {
-		if (!rs_table[i].enabled) 
-			continue; 
-		l = line_info(page + len, &rs_table[i]);
-		len += l;
-		if (len+begin > off+count)
-			goto done;
-		if (len+begin < off) {
-			begin += len;
-			len = 0;
-		}
-	}
-#ifdef DEBUG_LOG_INCLUDED
-	for (i = 0; i < debug_log_pos; i++) {
-		len += sprintf(page + len, "%-4i %lu.%lu ", i, debug_log[i].time, timer_data_to_ns(debug_log[i].timer_data));
-		len += sprintf(page + len, debug_log[i].string, debug_log[i].value);
-		if (len+begin > off+count)
-			goto done;
-		if (len+begin < off) {
-			begin += len;
-			len = 0;
-		}
-	}
-	len += sprintf(page + len, "debug_log %i/%i  %li bytes\n",
-		       i, DEBUG_LOG_SIZE, begin+len);
-	debug_log_pos = 0;
-#endif
-
-	*eof = 1;
-done:
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void 
-show_serial_version(void)
-{
-	printk(KERN_INFO
-	       "ETRAX 100LX serial-driver %s, (c) 2000-2004 Axis Communications AB\r\n",
-	       &serial_version[11]); /* "$Revision: x.yy" */
-}
-
-/* rs_init inits the driver at boot (using the module_init chain) */
-
-static struct tty_operations rs_ops = {
-	.open = rs_open,
-	.close = rs_close,
-	.write = rs_write,
-	.flush_chars = rs_flush_chars,
-	.write_room = rs_write_room,
-	.chars_in_buffer = rs_chars_in_buffer,
-	.flush_buffer = rs_flush_buffer,
-	.ioctl = rs_ioctl,
-	.throttle = rs_throttle,	
-        .unthrottle = rs_unthrottle,
-	.set_termios = rs_set_termios,
-	.stop = rs_stop,
-	.start = rs_start,
-	.hangup = rs_hangup,
-	.break_ctl = rs_break,
-	.send_xchar = rs_send_xchar,
-	.wait_until_sent = rs_wait_until_sent,
-	.read_proc = rs_read_proc,
-};
-
-static int __init
-rs_init(void)
-{
-	int i;
-	struct e100_serial *info;
-	struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
-
-	if (!driver)
-		return -ENOMEM;
-
-	show_serial_version();
-
-	/* Setup the timed flush handler system */
-
-#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
-	init_timer(&flush_timer);
-	flush_timer.function = timed_flush_handler;
-	mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
-#endif
-
-	/* Initialize the tty_driver structure */
-  
-	driver->driver_name = "serial";
-	driver->name = "ttyS";
-	driver->major = TTY_MAJOR;
-	driver->minor_start = 64;
-	driver->type = TTY_DRIVER_TYPE_SERIAL;
-	driver->subtype = SERIAL_TYPE_NORMAL;
-	driver->init_termios = tty_std_termios;
-	driver->init_termios.c_cflag =
-		B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
-	driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
-	driver->termios = serial_termios;
-	driver->termios_locked = serial_termios_locked;
-
-	tty_set_operations(driver, &rs_ops);
-        serial_driver = driver;
-	if (tty_register_driver(driver))
-		panic("Couldn't register serial driver\n");
-	/* do some initializing for the separate ports */
-  
-	for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
-		info->uses_dma_in = 0;
-		info->uses_dma_out = 0;
-		info->line = i;
-		info->tty = 0;
-		info->type = PORT_ETRAX;
-		info->tr_running = 0;
-		info->forced_eop = 0;
-		info->baud_base = DEF_BAUD_BASE;
-		info->custom_divisor = 0;
-		info->flags = 0;
-		info->close_delay = 5*HZ/10;
-		info->closing_wait = 30*HZ;
-		info->x_char = 0;
-		info->event = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		info->normal_termios = driver->init_termios;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
-		info->xmit.buf = NULL;
-		info->xmit.tail = info->xmit.head = 0;
-		info->first_recv_buffer = info->last_recv_buffer = NULL;
-		info->recv_cnt = info->max_recv_cnt = 0;
-		info->last_tx_active_usec = 0;
-		info->last_tx_active = 0;
-
-#if defined(CONFIG_ETRAX_RS485)
-		/* Set sane defaults */
-		info->rs485.rts_on_send = 0;
-		info->rs485.rts_after_sent = 1;
-		info->rs485.delay_rts_before_send = 0;
-		info->rs485.enabled = 0;
-#endif
-		INIT_WORK(&info->work, do_softint, info);
-
-		if (info->enabled) {
-			printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
-			       serial_driver->name, info->line, (unsigned int)info->port);
-		}
-	}
-#ifdef CONFIG_ETRAX_FAST_TIMER
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-	memset(fast_timers, 0, sizeof(fast_timers));
-#endif
-#ifdef CONFIG_ETRAX_RS485
-	memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
-#endif
-	fast_timer_init();
-#endif
-
-#ifndef CONFIG_SVINTO_SIM
-	/* Not needed in simulator.  May only complicate stuff. */
-	/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
-
-	if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
-		panic("irq8");
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
-	if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
-		panic("irq22");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
-	if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
-		panic("irq23");
-#endif
-#endif
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
-	if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
-		panic("irq24");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
-	if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
-		panic("irq25");
-#endif
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-	/* DMA Shared with par0 (and SCSI0 and ATA) */
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
-	if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma tr", NULL))
-		panic("irq18");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
-	if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma rec", NULL))
-		panic("irq19");
-#endif
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
-	/* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
-	if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma tr", NULL))
-		panic("irq20");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
-	if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma rec", NULL))
-		panic("irq21");
-#endif
-#endif
-
-#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
-	if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT,
-		       "fast serial dma timeout", NULL)) {
-		printk(KERN_CRIT "err: timer1 irq\n");
-	}
-#endif
-#endif /* CONFIG_SVINTO_SIM */
-	debug_write_function = rs_debug_write_function;
-	return 0;
-}
-
-/* this makes sure that rs_init is called during kernel boot */
-
-module_init(rs_init);
-
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-int 
-register_serial(struct serial_struct *req)
-{
-	return -1;
-}
-
-void unregister_serial(int line)
-{
-}
diff -L arch/cris/arch-v10/drivers/serial.h -puN arch/cris/arch-v10/drivers/serial.h~cris-architecture-update-move-drivers /dev/null
--- 25/arch/cris/arch-v10/drivers/serial.h
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,137 +0,0 @@
-/*
- * serial.h: Arch-dep definitions for the Etrax100 serial driver.
- *
- * Copyright (C) 1998, 1999, 2000 Axis Communications AB
- */
-
-#ifndef _ETRAX_SERIAL_H
-#define _ETRAX_SERIAL_H
-
-#include <linux/config.h>
-#include <linux/circ_buf.h>
-#include <asm/termios.h>
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-#define SERIAL_RECV_DESCRIPTORS 8
-
-struct etrax_recv_buffer {
-	struct etrax_recv_buffer *next;
-	unsigned short length;
-	unsigned char error;
-	unsigned char pad;
-
-	unsigned char buffer[0];
-};
-
-struct e100_serial {
-	int			baud;
-	volatile u8		*port; /* R_SERIALx_CTRL */
-	u32			irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
-	/* Output registers */
-	volatile u8		*oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
-	volatile u32		*ofirstadr;   /* adr to R_DMA_CHx_FIRST */
-	volatile u8		*ocmdadr;     /* adr to R_DMA_CHx_CMD */
-	const volatile u8	*ostatusadr;  /* adr to R_DMA_CHx_STATUS */
-
-	/* Input registers */
-	volatile u8		*iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
-	volatile u32		*ifirstadr;   /* adr to R_DMA_CHx_FIRST */
-	volatile u8		*icmdadr;     /* adr to R_DMA_CHx_CMD */
-	volatile u32		*idescradr;   /* adr to R_DMA_CHx_DESCR */
-
-	int			flags;	/* defined in tty.h */
-
-	u8			rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
-	u8			tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
-	u8			iseteop; /* bit number for R_SET_EOP for the input dma */
-	int			enabled; /* Set to 1 if the port is enabled in HW config */
-
-	u8		dma_out_enabled:1; /* Set to 1 if DMA should be used */
-	u8		dma_in_enabled:1;  /* Set to 1 if DMA should be used */
-
-	/* end of fields defined in rs_table[] in .c-file */
-	u8		uses_dma_in;  /* Set to 1 if DMA is used */
-	u8		uses_dma_out; /* Set to 1 if DMA is used */
-	u8		forced_eop;   /* a fifo eop has been forced */
-	int			baud_base;     /* For special baudrates */
-	int			custom_divisor; /* For special baudrates */
-	struct etrax_dma_descr	tr_descr;
-	struct etrax_dma_descr	rec_descr[SERIAL_RECV_DESCRIPTORS];
-	int			cur_rec_descr;
-
-	volatile int		tr_running; /* 1 if output is running */
-
-	struct tty_struct	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			type;  /* PORT_ETRAX */
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	struct circ_buf		xmit;
-	struct etrax_recv_buffer *first_recv_buffer;
-	struct etrax_recv_buffer *last_recv_buffer;
-	unsigned int		recv_cnt;
-	unsigned int		max_recv_cnt;
-
-	struct work_struct	work;
-	struct async_icount	icount;   /* error-statistics etc.*/
-	struct termios		normal_termios;
-	struct termios		callout_termios;
-#ifdef DECLARE_WAITQUEUE
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-#else
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-#endif  
-
-	unsigned long		char_time_usec;       /* The time for 1 char, in usecs */
-	unsigned long		flush_time_usec;      /* How often we should flush */
-	unsigned long		last_tx_active_usec;  /* Last tx usec in the jiffies */
-	unsigned long		last_tx_active;       /* Last tx time in jiffies */
-	unsigned long		last_rx_active_usec;  /* Last rx usec in the jiffies */
-	unsigned long		last_rx_active;       /* Last rx time in jiffies */
-
-	int			break_detected_cnt;
-	int			errorcode;
-
-#ifdef CONFIG_ETRAX_RS485
-	struct rs485_control	rs485;  /* RS-485 support */
-#endif
-};
-
-/* this PORT is not in the standard serial.h. it's not actually used for
- * anything since we only have one type of async serial-port anyway in this
- * system.
- */
-
-#define PORT_ETRAX 1
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-#endif /* __KERNEL__ */
-
-#endif /* !_ETRAX_SERIAL_H */
diff -L arch/cris/arch-v10/drivers/usb-host.c -puN arch/cris/arch-v10/drivers/usb-host.c~cris-architecture-update-move-drivers /dev/null
--- 25/arch/cris/arch-v10/drivers/usb-host.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,4574 +0,0 @@
-/*
- * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
- *
- * Copyright (c) 2002, 2003 Axis Communications AB.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/arch/svinto.h>
-
-#include <linux/usb.h>
-/* Ugly include because we don't live with the other host drivers. */
-#include <../drivers/usb/core/hcd.h>
-#include <../drivers/usb/core/usb.h>
-
-#include "usb-host.h"
-
-#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
-#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
-#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
-
-static const char *usb_hcd_version = "$Revision: 1.2 $";
-
-#undef KERN_DEBUG
-#define KERN_DEBUG ""
-
-
-#undef USB_DEBUG_RH
-#undef USB_DEBUG_EPID
-#undef USB_DEBUG_SB
-#undef USB_DEBUG_DESC
-#undef USB_DEBUG_URB
-#undef USB_DEBUG_TRACE
-#undef USB_DEBUG_BULK
-#undef USB_DEBUG_CTRL
-#undef USB_DEBUG_INTR
-#undef USB_DEBUG_ISOC
-
-#ifdef USB_DEBUG_RH
-#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
-#else
-#define dbg_rh(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_EPID
-#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)
-#else
-#define dbg_epid(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_SB
-#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)
-#else
-#define dbg_sb(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_CTRL
-#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
-#else
-#define dbg_ctrl(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_BULK
-#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
-#else
-#define dbg_bulk(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_INTR
-#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
-#else
-#define dbg_intr(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_ISOC
-#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)
-#else
-#define dbg_isoc(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_TRACE
-#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
-#define DBFEXIT  (printk(": Exiting:  %s\n", __FUNCTION__))
-#else
-#define DBFENTER do {} while (0)
-#define DBFEXIT  do {} while (0)
-#endif
-
-#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
-
-/*-------------------------------------------------------------------
- Virtual Root Hub
- -------------------------------------------------------------------*/
-
-static __u8 root_hub_dev_des[] =
-{
-	0x12,  /*  __u8  bLength; */
-	0x01,  /*  __u8  bDescriptorType; Device */
-	0x00,  /*  __u16 bcdUSB; v1.0 */
-	0x01,
-	0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,  /*  __u8  bDeviceSubClass; */
-	0x00,  /*  __u8  bDeviceProtocol; */
-	0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,  /*  __u16 idVendor; */
-	0x00,
-	0x00,  /*  __u16 idProduct; */
-	0x00,
-	0x00,  /*  __u16 bcdDevice; */
-	0x00,
-	0x00,  /*  __u8  iManufacturer; */
-	0x02,  /*  __u8  iProduct; */
-	0x01,  /*  __u8  iSerialNumber; */
-	0x01   /*  __u8  bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-	0x09,  /*  __u8  bLength; */
-	0x02,  /*  __u8  bDescriptorType; Configuration */
-	0x19,  /*  __u16 wTotalLength; */
-	0x00,
-	0x01,  /*  __u8  bNumInterfaces; */
-	0x01,  /*  __u8  bConfigurationValue; */
-	0x00,  /*  __u8  iConfiguration; */
-	0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */
-	0x00,  /*  __u8  MaxPower; */
-
-     /* interface */
-	0x09,  /*  __u8  if_bLength; */
-	0x04,  /*  __u8  if_bDescriptorType; Interface */
-	0x00,  /*  __u8  if_bInterfaceNumber; */
-	0x00,  /*  __u8  if_bAlternateSetting; */
-	0x01,  /*  __u8  if_bNumEndpoints; */
-	0x09,  /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,  /*  __u8  if_bInterfaceSubClass; */
-	0x00,  /*  __u8  if_bInterfaceProtocol; */
-	0x00,  /*  __u8  if_iInterface; */
-
-     /* endpoint */
-	0x07,  /*  __u8  ep_bLength; */
-	0x05,  /*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,  /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,  /*  __u8  ep_bmAttributes; Interrupt */
-	0x08,  /*  __u16 ep_wMaxPacketSize; 8 Bytes */
-	0x00,
-	0xff   /*  __u8  ep_bInterval; 255 ms */
-};
-
-static __u8 root_hub_hub_des[] =
-{
-	0x09,  /*  __u8  bLength; */
-	0x29,  /*  __u8  bDescriptorType; Hub-descriptor */
-	0x02,  /*  __u8  bNbrPorts; */
-	0x00,  /* __u16  wHubCharacteristics; */
-	0x00,
-	0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */
-	0x00,  /*  __u8  bHubContrCurrent; 0 mA */
-	0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */
-	0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0);
-static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0);
-
-/* We want the start timer to expire before the eot timer, because the former might start
-   traffic, thus making it unnecessary for the latter to time out. */
-#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */
-#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */
-
-#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break
-#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
-{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
-
-#define SLAB_FLAG     (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-
-/* Most helpful debugging aid */
-#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
-
-/* Alternative assert define which stops after a failed assert. */
-/*
-#define assert(expr)                                      \
-{                                                         \
-        if (!(expr)) {                                    \
-                err("assert failed at line %d",__LINE__); \
-                while (1);                                \
-        }                                                 \
-}
-*/
-
-
-/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?
-   To adjust it dynamically we would have to get an interrupt when we reach the end
-   of the rx descriptor list, or when we get close to the end, and then allocate more
-   descriptors. */
-
-#define NBR_OF_RX_DESC     512
-#define RX_DESC_BUF_SIZE   1024
-#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
-
-/* The number of epids is, among other things, used for pre-allocating
-   ctrl, bulk and isoc EP descriptors (one for each epid).
-   Assumed to be > 1 when initiating the DMA lists. */
-#define NBR_OF_EPIDS       32
-
-/* Support interrupt traffic intervals up to 128 ms. */
-#define MAX_INTR_INTERVAL 128
-
-/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table
-   must be "invalid". By this we mean that we shouldn't care about epid attentions
-   for this epid, or at least handle them differently from epid attentions for "valid"
-   epids. This define determines which one to use (don't change it). */
-#define INVALID_EPID     31
-/* A special epid for the bulk dummys. */
-#define DUMMY_EPID       30
-
-/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */
-static __u32 epid_usage_bitmask;
-
-/* A bitfield to keep information on in/out traffic is needed to uniquely identify
-   an endpoint on a device, since the most significant bit which indicates traffic
-   direction is lacking in the ep_id field (ETRAX epids can handle both in and
-   out traffic on endpoints that are otherwise identical). The USB framework, however,
-   relies on them to be handled separately.  For example, bulk IN and OUT urbs cannot
-   be queued in the same list, since they would block each other. */
-static __u32 epid_out_traffic;
-
-/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
-   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */
-static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
-static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
-
-/* Pointers into RxDescList. */
-static volatile USB_IN_Desc_t *myNextRxDesc;
-static volatile USB_IN_Desc_t *myLastRxDesc;
-static volatile USB_IN_Desc_t *myPrevRxDesc;
-
-/* EP descriptors must be 32-bit aligned. */
-static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
-static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
-/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,
-   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
-   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
-   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
-   in each frame. */
-static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
-
-static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
-static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));
-
-static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
-static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
-
-/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting
-   this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0
-   results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point
-   it to this buffer. */
-static int zout_buffer[4] __attribute__ ((aligned (4)));
-
-/* Cache for allocating new EP and SB descriptors. */
-static kmem_cache_t *usb_desc_cache;
-
-/* Cache for the registers allocated in the top half. */
-static kmem_cache_t *top_half_reg_cache;
-
-/* Cache for the data allocated in the isoc descr top half. */
-static kmem_cache_t *isoc_compl_cache;
-
-static struct usb_bus *etrax_usb_bus;
-
-/* This is a circular (double-linked) list of the active urbs for each epid.
-   The head is never removed, and new urbs are linked onto the list as
-   urb_entry_t elements. Don't reference urb_list directly; use the wrapper
-   functions instead. Note that working with these lists might require spinlock
-   protection. */
-static struct list_head urb_list[NBR_OF_EPIDS];
-
-/* Read about the need and usage of this lock in submit_ctrl_urb. */
-static spinlock_t urb_list_lock;
-
-/* Used when unlinking asynchronously. */
-static struct list_head urb_unlink_list;
-
-/* for returning string descriptors in UTF-16LE */
-static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
-{
-	int retval;
-
-	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
-		*utf++ = *ascii++ & 0x7f;
-		*utf++ = 0;
-	}
-	return retval;
-}
-
-static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
-{
-	char buf [30];
-
-	// assert (len > (2 * (sizeof (buf) + 1)));
-	// assert (strlen (type) <= 8);
-
-	// language ids
-	if (id == 0) {
-		*data++ = 4; *data++ = 3;	/* 4 bytes data */
-		*data++ = 0; *data++ = 0;	/* some language id */
-		return 4;
-
-	// serial number
-	} else if (id == 1) {
-		sprintf (buf, "%x", serial);
-
-	// product description
-	} else if (id == 2) {
-		sprintf (buf, "USB %s Root Hub", type);
-
-	// id 3 == vendor description
-
-	// unsupported IDs --> "stall"
-	} else
-	    return 0;
-
-	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
-	data [1] = 3;
-	return data [0];
-}
-
-/* Wrappers around the list functions (include/linux/list.h). */
-
-static inline int urb_list_empty(int epid)
-{
-	return list_empty(&urb_list[epid]);
-}
-
-/* Returns first urb for this epid, or NULL if list is empty. */
-static inline struct urb *urb_list_first(int epid)
-{
-	struct urb *first_urb = 0;
-
-	if (!urb_list_empty(epid)) {
-		/* Get the first urb (i.e. head->next). */
-		urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
-		first_urb = urb_entry->urb;
-	}
-	return first_urb;
-}
-
-/* Adds an urb_entry last in the list for this epid. */
-static inline void urb_list_add(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
-	assert(urb_entry);
-
-	urb_entry->urb = urb;
-	list_add_tail(&urb_entry->list, &urb_list[epid]);
-}
-
-/* Search through the list for an element that contains this urb. (The list
-   is expected to be short and the one we are about to delete will often be
-   the first in the list.) */
-static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid)
-{
-	struct list_head *entry;
-	struct list_head *tmp;
-	urb_entry_t *urb_entry;
-
-	list_for_each_safe(entry, tmp, &urb_list[epid]) {
-		urb_entry = list_entry(entry, urb_entry_t, list);
-		assert(urb_entry);
-		assert(urb_entry->urb);
-
-		if (urb_entry->urb == urb) {
-			return urb_entry;
-		}
-	}
-	return 0;
-}
-
-/* Delete an urb from the list. */
-static inline void urb_list_del(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
-	assert(urb_entry);
-
-	/* Delete entry and free. */
-	list_del(&urb_entry->list);
-	kfree(urb_entry);
-}
-
-/* Move an urb to the end of the list. */
-static inline void urb_list_move_last(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
-	assert(urb_entry);
-
-	list_del(&urb_entry->list);
-	list_add_tail(&urb_entry->list, &urb_list[epid]);
-}
-
-/* Get the next urb in the list. */
-static inline struct urb *urb_list_next(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
-
-	assert(urb_entry);
-
-	if (urb_entry->list.next != &urb_list[epid]) {
-		struct list_head *elem = urb_entry->list.next;
-		urb_entry = list_entry(elem, urb_entry_t, list);
-		return urb_entry->urb;
-	} else {
-		return NULL;
-	}
-}
-
-
-
-/* For debug purposes only. */
-static inline void urb_list_dump(int epid)
-{
-	struct list_head *entry;
-	struct list_head *tmp;
-	urb_entry_t *urb_entry;
-	int i = 0;
-
-	info("Dumping urb list for epid %d", epid);
-
-	list_for_each_safe(entry, tmp, &urb_list[epid]) {
-		urb_entry = list_entry(entry, urb_entry_t, list);
-		info("   entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb);
-	}
-}
-
-static void init_rx_buffers(void);
-static int etrax_rh_unlink_urb(struct urb *urb);
-static void etrax_rh_send_irq(struct urb *urb);
-static void etrax_rh_init_int_timer(struct urb *urb);
-static void etrax_rh_int_timer_do(unsigned long ptr);
-
-static int etrax_usb_setup_epid(struct urb *urb);
-static int etrax_usb_lookup_epid(struct urb *urb);
-static int etrax_usb_allocate_epid(void);
-static void etrax_usb_free_epid(int epid);
-
-static int etrax_remove_from_sb_list(struct urb *urb);
-
-static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma);
-static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);
-
-static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);
-static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid);
-static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid);
-static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid);
-
-static int etrax_usb_submit_bulk_urb(struct urb *urb);
-static int etrax_usb_submit_ctrl_urb(struct urb *urb);
-static int etrax_usb_submit_intr_urb(struct urb *urb);
-static int etrax_usb_submit_isoc_urb(struct urb *urb);
-
-static int etrax_usb_submit_urb(struct urb *urb, int mem_flags);
-static int etrax_usb_unlink_urb(struct urb *urb, int status);
-static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
-static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
-static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
-
-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
-static void etrax_usb_hc_interrupt_bottom_half(void *data);
-
-static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
-
-
-/* The following is a list of interrupt handlers for the host controller interrupts we use.
-   They are called from etrax_usb_hc_interrupt_bottom_half. */
-static void etrax_usb_hc_isoc_eof_interrupt(void);
-static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);
-static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);
-static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);
-static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);
-
-static int etrax_rh_submit_urb (struct urb *urb);
-
-/* Forward declaration needed because they are used in the rx interrupt routine. */
-static void etrax_usb_complete_urb(struct urb *urb, int status);
-static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);
-static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);
-static void etrax_usb_complete_intr_urb(struct urb *urb, int status);
-static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);
-
-static int etrax_usb_hc_init(void);
-static void etrax_usb_hc_cleanup(void);
-
-static struct usb_operations etrax_usb_device_operations =
-{
-	.allocate = etrax_usb_allocate_dev,
-	.deallocate = etrax_usb_deallocate_dev,
-	.get_frame_number = etrax_usb_get_frame_number,
-	.submit_urb = etrax_usb_submit_urb,
-	.unlink_urb = etrax_usb_unlink_urb,
-        .buffer_alloc = etrax_usb_buffer_alloc,
-        .buffer_free = etrax_usb_buffer_free
-};
-
-/* Note that these functions are always available in their "__" variants, for use in
-   error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/
-   USB_DEBUG_URB macros. */
-static void __dump_urb(struct urb* purb)
-{
-	printk("\nurb                  :0x%08lx\n", (unsigned long)purb);
-	printk("dev                   :0x%08lx\n", (unsigned long)purb->dev);
-	printk("pipe                  :0x%08x\n", purb->pipe);
-	printk("status                :%d\n", purb->status);
-	printk("transfer_flags        :0x%08x\n", purb->transfer_flags);
-	printk("transfer_buffer       :0x%08lx\n", (unsigned long)purb->transfer_buffer);
-	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk("actual_length         :%d\n", purb->actual_length);
-	printk("setup_packet          :0x%08lx\n", (unsigned long)purb->setup_packet);
-	printk("start_frame           :%d\n", purb->start_frame);
-	printk("number_of_packets     :%d\n", purb->number_of_packets);
-	printk("interval              :%d\n", purb->interval);
-	printk("error_count           :%d\n", purb->error_count);
-	printk("context               :0x%08lx\n", (unsigned long)purb->context);
-	printk("complete              :0x%08lx\n\n", (unsigned long)purb->complete);
-}
-
-static void __dump_in_desc(volatile USB_IN_Desc_t *in)
-{
-	printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
-	printk("  sw_len  : 0x%04x (%d)\n", in->sw_len, in->sw_len);
-	printk("  command : 0x%04x\n", in->command);
-	printk("  next    : 0x%08lx\n", in->next);
-	printk("  buf     : 0x%08lx\n", in->buf);
-	printk("  hw_len  : 0x%04x (%d)\n", in->hw_len, in->hw_len);
-	printk("  status  : 0x%04x\n\n", in->status);
-}
-
-static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
-{
-	char tt = (sb->command & 0x30) >> 4;
-	char *tt_string;
-
-	switch (tt) {
-	case 0:
-		tt_string = "zout";
-		break;
-	case 1:
-		tt_string = "in";
-		break;
-	case 2:
-		tt_string = "out";
-		break;
-	case 3:
-		tt_string = "setup";
-		break;
-	default:
-		tt_string = "unknown (weird)";
-	}
-
-	printk("\n   USB_SB_Desc at 0x%08lx\n", (unsigned long)sb);
-	printk("     command : 0x%04x\n", sb->command);
-	printk("        rem     : %d\n", (sb->command & 0x3f00) >> 8);
-	printk("        full    : %d\n", (sb->command & 0x40) >> 6);
-	printk("        tt      : %d (%s)\n", tt, tt_string);
-	printk("        intr    : %d\n", (sb->command & 0x8) >> 3);
-	printk("        eot     : %d\n", (sb->command & 0x2) >> 1);
-	printk("        eol     : %d\n", sb->command & 0x1);
-	printk("     sw_len  : 0x%04x (%d)\n", sb->sw_len, sb->sw_len);
-	printk("     next    : 0x%08lx\n", sb->next);
-	printk("     buf     : 0x%08lx\n\n", sb->buf);
-}
-
-
-static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
-{
-	printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep);
-	printk("  command : 0x%04x\n", ep->command);
-	printk("     ep_id   : %d\n", (ep->command & 0x1f00) >> 8);
-	printk("     enable  : %d\n", (ep->command & 0x10) >> 4);
-	printk("     intr    : %d\n", (ep->command & 0x8) >> 3);
-	printk("     eof     : %d\n", (ep->command & 0x2) >> 1);
-	printk("     eol     : %d\n", ep->command & 0x1);
-	printk("  hw_len  : 0x%04x (%d)\n", ep->hw_len, ep->hw_len);
-	printk("  next    : 0x%08lx\n", ep->next);
-	printk("  sub     : 0x%08lx\n\n", ep->sub);
-}
-
-static inline void __dump_ep_list(int pipe_type)
-{
-	volatile USB_EP_Desc_t *ep;
-	volatile USB_EP_Desc_t *first_ep;
-	volatile USB_SB_Desc_t *sb;
-
-	switch (pipe_type)
-	{
-	case PIPE_BULK:
-		first_ep = &TxBulkEPList[0];
-		break;
-	case PIPE_CONTROL:
-		first_ep = &TxCtrlEPList[0];
-		break;
-	case PIPE_INTERRUPT:
-		first_ep = &TxIntrEPList[0];
-		break;
-	case PIPE_ISOCHRONOUS:
-		first_ep = &TxIsocEPList[0];
-		break;
-	default:
-		warn("Cannot dump unknown traffic type");
-		return;
-	}
-	ep = first_ep;
-
-	printk("\n\nDumping EP list...\n\n");
-
-	do {
-		__dump_ep_desc(ep);
-		/* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
-		sb = ep->sub ? phys_to_virt(ep->sub) : 0;
-		while (sb) {
-			__dump_sb_desc(sb);
-			sb = sb->next ? phys_to_virt(sb->next) : 0;
-		}
-		ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next));
-
-	} while (ep != first_ep);
-}
-
-static inline void __dump_ept_data(int epid)
-{
-	unsigned long flags;
-	__u32 r_usb_ept_data;
-
-	if (epid < 0 || epid > 31) {
-		printk("Cannot dump ept data for invalid epid %d\n", epid);
-		return;
-	}
-
-	save_flags(flags);
-	cli();
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	r_usb_ept_data = *R_USB_EPT_DATA;
-	restore_flags(flags);
-
-	printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
-	if (r_usb_ept_data == 0) {
-		/* No need for more detailed printing. */
-		return;
-	}
-	printk("  valid           : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
-	printk("  hold            : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
-	printk("  error_count_in  : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
-	printk("  t_in            : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
-	printk("  low_speed       : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
-	printk("  port            : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
-	printk("  error_code      : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
-	printk("  t_out           : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
-	printk("  error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
-	printk("  max_len         : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
-	printk("  ep              : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
-	printk("  dev             : %d\n", (r_usb_ept_data & 0x0000003f));
-}
-
-static inline void __dump_ept_data_list(void)
-{
-	int i;
-
-	printk("Dumping the whole R_USB_EPT_DATA list\n");
-
-	for (i = 0; i < 32; i++) {
-		__dump_ept_data(i);
-	}
-}
-#ifdef USB_DEBUG_DESC
-#define dump_in_desc(...) __dump_in_desc(...)
-#define dump_sb_desc(...) __dump_sb_desc(...)
-#define dump_ep_desc(...) __dump_ep_desc(...)
-#else
-#define dump_in_desc(...) do {} while (0)
-#define dump_sb_desc(...) do {} while (0)
-#define dump_ep_desc(...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_URB
-#define dump_urb(x)     __dump_urb(x)
-#else
-#define dump_urb(x)     do {} while (0)
-#endif
-
-static void init_rx_buffers(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
-		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
-		RxDescList[i].command = 0;
-		RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
-		RxDescList[i].hw_len = 0;
-		RxDescList[i].status = 0;
-
-		/* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc
-		   for the relevant fields.) */
-		prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
-
-	}
-
-	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
-	RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
-	RxDescList[i].next = virt_to_phys(&RxDescList[0]);
-	RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
-	RxDescList[i].hw_len = 0;
-	RxDescList[i].status = 0;
-
-	myNextRxDesc = &RxDescList[0];
-	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
-	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
-
-	*R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
-	*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void init_tx_bulk_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
-		CHECK_ALIGN(&TxBulkEPList[i]);
-		TxBulkEPList[i].hw_len = 0;
-		TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
-		TxBulkEPList[i].sub = 0;
-		TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]);
-
-		/* Initiate two EPs, disabled and with the eol flag set. No need for any
-		   preserved epid. */
-
-		/* The first one has the intr flag set so we get an interrupt when the DMA
-		   channel is about to become disabled. */
-		CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
-		TxBulkDummyEPList[i][0].hw_len = 0;
-		TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
-						   IO_STATE(USB_EP_command, eol, yes) |
-						   IO_STATE(USB_EP_command, intr, yes));
-		TxBulkDummyEPList[i][0].sub = 0;
-		TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
-
-		/* The second one. */
-		CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
-		TxBulkDummyEPList[i][1].hw_len = 0;
-		TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
-						   IO_STATE(USB_EP_command, eol, yes));
-		TxBulkDummyEPList[i][1].sub = 0;
-		/* The last dummy's next pointer is the same as the current EP's next pointer. */
-		TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
-	}
-
-	/* Configure the last one. */
-	CHECK_ALIGN(&TxBulkEPList[i]);
-	TxBulkEPList[i].hw_len = 0;
-	TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
-				   IO_FIELD(USB_EP_command, epid, i));
-	TxBulkEPList[i].sub = 0;
-	TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]);
-
-	/* No need configuring dummy EPs for the last one as it will never be used for
-	   bulk traffic (i == INVALD_EPID at this point). */
-
-	/* Set up to start on the last EP so we will enable it when inserting traffic
-	   for the first time (imitating the situation where the DMA has stopped
-	   because there was no more traffic). */
-	*R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
-	/* No point in starting the bulk channel yet.
-	 *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
-	DBFEXIT;
-}
-
-static void init_tx_ctrl_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
-		CHECK_ALIGN(&TxCtrlEPList[i]);
-		TxCtrlEPList[i].hw_len = 0;
-		TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
-		TxCtrlEPList[i].sub = 0;
-		TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]);
-	}
-
-	CHECK_ALIGN(&TxCtrlEPList[i]);
-	TxCtrlEPList[i].hw_len = 0;
-	TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
-				   IO_FIELD(USB_EP_command, epid, i));
-
-	TxCtrlEPList[i].sub = 0;
-	TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
-
-	*R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
-	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-
-static void init_tx_intr_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	/* Read comment at zout_buffer declaration for an explanation to this. */
-	TxIntrSB_zout.sw_len = 1;
-	TxIntrSB_zout.next = 0;
-	TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
-	TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
-				 IO_STATE(USB_SB_command, tt, zout) |
-				 IO_STATE(USB_SB_command, full, yes) |
-				 IO_STATE(USB_SB_command, eot, yes) |
-				 IO_STATE(USB_SB_command, eol, yes));
-
-	for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
-		CHECK_ALIGN(&TxIntrEPList[i]);
-		TxIntrEPList[i].hw_len = 0;
-		TxIntrEPList[i].command =
-			(IO_STATE(USB_EP_command, eof, yes) |
-			 IO_STATE(USB_EP_command, enable, yes) |
-			 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
-		TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
-		TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
-	}
-
-	CHECK_ALIGN(&TxIntrEPList[i]);
-	TxIntrEPList[i].hw_len = 0;
-	TxIntrEPList[i].command =
-		(IO_STATE(USB_EP_command, eof, yes) |
-		 IO_STATE(USB_EP_command, eol, yes) |
-		 IO_STATE(USB_EP_command, enable, yes) |
-		 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
-	TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
-	TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
-
-	*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
-	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
-	DBFEXIT;
-}
-
-static void init_tx_isoc_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	/* Read comment at zout_buffer declaration for an explanation to this. */
-	TxIsocSB_zout.sw_len = 1;
-	TxIsocSB_zout.next = 0;
-	TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
-	TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
-				 IO_STATE(USB_SB_command, tt, zout) |
-				 IO_STATE(USB_SB_command, full, yes) |
-				 IO_STATE(USB_SB_command, eot, yes) |
-				 IO_STATE(USB_SB_command, eol, yes));
-
-	/* The last isochronous EP descriptor is a dummy. */
-
-	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
-		CHECK_ALIGN(&TxIsocEPList[i]);
-		TxIsocEPList[i].hw_len = 0;
-		TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
-		TxIsocEPList[i].sub = 0;
-		TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
-	}
-
-	CHECK_ALIGN(&TxIsocEPList[i]);
-	TxIsocEPList[i].hw_len = 0;
-
-	/* Must enable the last EP descr to get eof interrupt. */
-	TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
-				   IO_STATE(USB_EP_command, eof, yes) |
-				   IO_STATE(USB_EP_command, eol, yes) |
-				   IO_FIELD(USB_EP_command, epid, INVALID_EPID));
-	TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
-	TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
-
-	*R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
-	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void etrax_usb_unlink_intr_urb(struct urb *urb)
-{
-	volatile USB_EP_Desc_t *first_ep;  /* First EP in the list. */
-	volatile USB_EP_Desc_t *curr_ep;   /* Current EP, the iterator. */
-	volatile USB_EP_Desc_t *next_ep;   /* The EP after current. */
-	volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */
-
-	int epid;
-
-	/* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */
-
-	DBFENTER;
-
-	epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;
-
-	first_ep = &TxIntrEPList[0];
-	curr_ep = first_ep;
-
-
-	/* Note that this loop removes all EP descriptors with this epid. This assumes
-	   that all EP descriptors belong to the one and only urb for this epid. */
-
-	do {
-		next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);
-
-		if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
-
-			dbg_intr("Found EP to unlink for epid %d", epid);
-
-			/* This is the one we should unlink. */
-			unlink_ep = next_ep;
-
-			/* Actually unlink the EP from the DMA list. */
-			curr_ep->next = unlink_ep->next;
-
-			/* Wait until the DMA is no longer at this descriptor. */
-			while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));
-
-			/* Now we are free to remove it and its SB descriptor.
-			   Note that it is assumed here that there is only one sb in the
-			   sb list for this ep. */
-			kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));
-			kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);
-		}
-
-		curr_ep = phys_to_virt(curr_ep->next);
-
-	} while (curr_ep != first_ep);
-        urb->hcpriv = NULL;
-}
-
-void etrax_usb_do_intr_recover(int epid)
-{
-	USB_EP_Desc_t *first_ep, *tmp_ep;
-
-	DBFENTER;
-
-	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
-	tmp_ep = first_ep;
-
-	/* What this does is simply to walk the list of interrupt
-	   ep descriptors and enable those that are disabled. */
-
-	do {
-		if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
-		    !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
-			tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
-		}
-
-		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
-
-	} while (tmp_ep != first_ep);
-
-
-	DBFEXIT;
-}
-
-static int etrax_rh_unlink_urb (struct urb *urb)
-{
-	etrax_hc_t *hc;
-
-	DBFENTER;
-
-	hc = urb->dev->bus->hcpriv;
-
-	if (hc->rh.urb == urb) {
-		hc->rh.send = 0;
-		del_timer(&hc->rh.rh_int_timer);
-	}
-
-	DBFEXIT;
-	return 0;
-}
-
-static void etrax_rh_send_irq(struct urb *urb)
-{
-	__u16 data = 0;
-	etrax_hc_t *hc = urb->dev->bus->hcpriv;
-	DBFENTER;
-
-/*
-  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);
-  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
-*/
-
-	data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
-	data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
-
-	*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
-	/* FIXME: Why is actual_length set to 1 when data is 2 bytes?
-	   Since only 1 byte is used, why not declare data as __u8? */
-	urb->actual_length = 1;
-	urb->status = 0;
-
-	if (hc->rh.send && urb->complete) {
-		dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);
-		dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
-
-		urb->complete(urb, NULL);
-	}
-
-	DBFEXIT;
-}
-
-static void etrax_rh_init_int_timer(struct urb *urb)
-{
-	etrax_hc_t *hc;
-
-	DBFENTER;
-
-	hc = urb->dev->bus->hcpriv;
-	hc->rh.interval = urb->interval;
-	init_timer(&hc->rh.rh_int_timer);
-	hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
-	hc->rh.rh_int_timer.data = (unsigned long)urb;
-	/* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped
-	   to 0, and the rest to the nearest lower 10 ms. */
-	hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
-	add_timer(&hc->rh.rh_int_timer);
-
-	DBFEXIT;
-}
-
-static void etrax_rh_int_timer_do(unsigned long ptr)
-{
-	struct urb *urb;
-	etrax_hc_t *hc;
-
-	DBFENTER;
-
-	urb = (struct urb*)ptr;
-	hc = urb->dev->bus->hcpriv;
-
-	if (hc->rh.send) {
-		etrax_rh_send_irq(urb);
-	}
-
-	DBFEXIT;
-}
-
-static int etrax_usb_setup_epid(struct urb *urb)
-{
-	int epid;
-	char devnum, endpoint, out_traffic, slow;
-	int maxlen;
-	unsigned long flags;
-
-	DBFENTER;
-
-	epid = etrax_usb_lookup_epid(urb);
-	if ((epid != -1)){
-		/* An epid that fits this urb has been found. */
-		DBFEXIT;
-		return epid;
-	}
-
-	/* We must find and initiate a new epid for this urb. */
-	epid = etrax_usb_allocate_epid();
-
-	if (epid == -1) {
-		/* Failed to allocate a new epid. */
-		DBFEXIT;
-		return epid;
-	}
-
-	/* We now have a new epid to use. Initiate it. */
-	set_bit(epid, (void *)&epid_usage_bitmask);
-
-	devnum = usb_pipedevice(urb->pipe);
-	endpoint = usb_pipeendpoint(urb->pipe);
-	slow = usb_pipeslow(urb->pipe);
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
-		out_traffic = 1;
-	} else {
-		out_traffic = usb_pipeout(urb->pipe);
-	}
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-
-	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-		*R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
-			/* FIXME: Change any to the actual port? */
-			IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
-			IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
-			IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
-			IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
-	} else {
-		*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
-			IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
-			/* FIXME: Change any to the actual port? */
-			IO_STATE(R_USB_EPT_DATA, port, any) |
-			IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
-			IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
-			IO_FIELD(R_USB_EPT_DATA, dev, devnum);
-	}
-
-	restore_flags(flags);
-
-	if (out_traffic) {
-		set_bit(epid, (void *)&epid_out_traffic);
-	} else {
-		clear_bit(epid, (void *)&epid_out_traffic);
-	}
-
-	dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",
-		 epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");
-
-	DBFEXIT;
-	return epid;
-}
-
-static void etrax_usb_free_epid(int epid)
-{
-	unsigned long flags;
-
-	DBFENTER;
-
-	if (!test_bit(epid, (void *)&epid_usage_bitmask)) {
-		warn("Trying to free unused epid %d", epid);
-		DBFEXIT;
-		return;
-	}
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));
-	/* This will, among other things, set the valid field to 0. */
-	*R_USB_EPT_DATA = 0;
-	restore_flags(flags);
-
-	clear_bit(epid, (void *)&epid_usage_bitmask);
-
-
-	dbg_epid("Freed epid %d", epid);
-
-	DBFEXIT;
-}
-
-static int etrax_usb_lookup_epid(struct urb *urb)
-{
-	int i;
-	__u32 data;
-	char devnum, endpoint, slow, out_traffic;
-	int maxlen;
-	unsigned long flags;
-
-	DBFENTER;
-
-	devnum = usb_pipedevice(urb->pipe);
-	endpoint = usb_pipeendpoint(urb->pipe);
-	slow = usb_pipeslow(urb->pipe);
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
-		out_traffic = 1;
-	} else {
-		out_traffic = usb_pipeout(urb->pipe);
-	}
-
-	/* Step through att epids. */
-	for (i = 0; i < NBR_OF_EPIDS; i++) {
-		if (test_bit(i, (void *)&epid_usage_bitmask) &&
-		    test_bit(i, (void *)&epid_out_traffic) == out_traffic) {
-
-			save_flags(flags);
-			cli();
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
-			nop();
-
-			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-				data = *R_USB_EPT_DATA_ISO;
-				restore_flags(flags);
-
-				if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {
-					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
-						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
-					DBFEXIT;
-					return i;
-				}
-			} else {
-				data = *R_USB_EPT_DATA;
-				restore_flags(flags);
-
-				if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {
-					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
-						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
-					DBFEXIT;
-					return i;
-				}
-			}
-		}
-	}
-
-	DBFEXIT;
-	return -1;
-}
-
-static int etrax_usb_allocate_epid(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < NBR_OF_EPIDS; i++) {
-		if (!test_bit(i, (void *)&epid_usage_bitmask)) {
-			dbg_epid("Found free epid %d", i);
-			DBFEXIT;
-			return i;
-		}
-	}
-
-	dbg_epid("Found no free epids");
-	DBFEXIT;
-	return -1;
-}
-
-static int etrax_usb_submit_urb(struct urb *urb, int mem_flags)
-{
-	etrax_hc_t *hc;
-	int ret = -EINVAL;
-
-	DBFENTER;
-
-	if (!urb->dev || !urb->dev->bus) {
-		return -ENODEV;
-	}
-	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
-		info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe);
-		return -EMSGSIZE;
-	}
-
-	if (urb->timeout) {
-		/* FIXME. */
-		warn("urb->timeout specified, ignoring.");
-	}
-
-	hc = (etrax_hc_t*)urb->dev->bus->hcpriv;
-
-	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
-		/* This request is for the Virtual Root Hub. */
-		ret = etrax_rh_submit_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-
-		ret = etrax_usb_submit_bulk_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-
-		ret = etrax_usb_submit_ctrl_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-		int bustime;
-
-		if (urb->bandwidth == 0) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-			} else {
-				ret = etrax_usb_submit_intr_urb(urb);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {
-			/* Bandwidth already set. */
-			ret = etrax_usb_submit_intr_urb(urb);
-		}
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-		int bustime;
-
-		if (urb->bandwidth == 0) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-			} else {
-				ret = etrax_usb_submit_isoc_urb(urb);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {
-			/* Bandwidth already set. */
-			ret = etrax_usb_submit_isoc_urb(urb);
-		}
-	}
-
-	DBFEXIT;
-
-        if (ret != 0)
-          printk("Submit URB error %d\n", ret);
-
-	return ret;
-}
-
-static int etrax_usb_unlink_urb(struct urb *urb, int status)
-{
-	etrax_hc_t *hc;
-	etrax_urb_priv_t *urb_priv;
-	int epid;
-	unsigned int flags;
-
-	DBFENTER;
-
-	if (!urb) {
-		return -EINVAL;
-	}
-
-	/* Disable interrupts here since a descriptor interrupt for the isoc epid
-	   will modify the sb list.  This could possibly be done more granular, but
-	   unlink_urb should not be used frequently anyway.
-	*/
-
-	save_flags(flags);
-	cli();
-
-	if (!urb->dev || !urb->dev->bus) {
-		restore_flags(flags);
-		return -ENODEV;
-	}
-	if (!urb->hcpriv) {
-		/* This happens if a device driver calls unlink on an urb that
-		   was never submitted (lazy driver) or if the urb was completed
-		   while unlink was being called. */
-		restore_flags(flags);
-		return 0;
-	}
-	if (urb->transfer_flags & URB_ASYNC_UNLINK) {
-		/* FIXME. */
-		/* If URB_ASYNC_UNLINK is set:
-		   unlink
-		   move to a separate urb list
-		   call complete at next sof with ECONNRESET
-
-		   If not:
-		   wait 1 ms
-		   unlink
-		   call complete with ENOENT
-		*/
-		warn("URB_ASYNC_UNLINK set, ignoring.");
-	}
-
-	/* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking,
-	   but that doesn't work for interrupt and isochronous traffic since they are completed
-	   repeatedly, and urb->status is set then. That may in itself be a bug though. */
-
-	hc = urb->dev->bus->hcpriv;
-	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	epid = urb_priv->epid;
-
-	/* Set the urb status (synchronous unlink). */
-	urb->status = -ENOENT;
-	urb_priv->urb_state = UNLINK;
-
-	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
-		int ret;
-		ret = etrax_rh_unlink_urb(urb);
-		DBFEXIT;
-		restore_flags(flags);
-		return ret;
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-
-		dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb);
-
-		if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-			/* The EP was enabled, disable it and wait. */
-			TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-			/* Ah, the luxury of busy-wait. */
-			while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));
-		}
-		/* Kicking dummy list out of the party. */
-		TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-
-		dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb);
-
-		if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-			/* The EP was enabled, disable it and wait. */
-			TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-			/* Ah, the luxury of busy-wait. */
-			while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));
-		}
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-
-		dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb);
-
-		/* Separate function because it's a tad more complicated. */
-		etrax_usb_unlink_intr_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-
-		dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb);
-
-		if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-			/* The EP was enabled, disable it and wait. */
-			TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-			/* Ah, the luxury of busy-wait. */
-			while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
-		}
-	}
-
-	/* Note that we need to remove the urb from the urb list *before* removing its SB
-	   descriptors. (This means that the isoc eof handler might get a null urb when we
-	   are unlinking the last urb.) */
-
-	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-
-		urb_list_del(urb, epid);
-		TxBulkEPList[epid].sub = 0;
-		etrax_remove_from_sb_list(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-
-		urb_list_del(urb, epid);
-		TxCtrlEPList[epid].sub = 0;
-		etrax_remove_from_sb_list(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-
-		urb_list_del(urb, epid);
-		/* Sanity check (should never happen). */
-		assert(urb_list_empty(epid));
-
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 0);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-
-		if (usb_pipeout(urb->pipe)) {
-
-			USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb;
-
-			if (__urb_list_entry(urb, epid)) {
-
-				urb_list_del(urb, epid);
-				iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
-				prev_sb = 0;
-				while (iter_sb && (iter_sb != urb_priv->first_sb)) {
-					prev_sb = iter_sb;
-					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
-				}
-
-				if (iter_sb == 0) {
-					/* Unlink of the URB currently being transmitted. */
-					prev_sb = 0;
-					iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
-				}
-
-				while (iter_sb && (iter_sb != urb_priv->last_sb)) {
-					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
-				}
-				if (iter_sb) {
-					next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
-				} else {
-					/* This should only happen if the DMA has completed
-					   processing the SB list for this EP while interrupts
-					   are disabled. */
-					dbg_isoc("Isoc urb not found, already sent?");
-					next_sb = 0;
-				}
-				if (prev_sb) {
-					prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
-				} else {
-					TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
-				}
-
-				etrax_remove_from_sb_list(urb);
-				if (urb_list_empty(epid)) {
-					TxIsocEPList[epid].sub = 0;
-					dbg_isoc("Last isoc out urb epid %d", epid);
-				} else if (next_sb || prev_sb) {
-					dbg_isoc("Re-enable isoc out epid %d", epid);
-
-					TxIsocEPList[epid].hw_len = 0;
-					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-				} else {
-					TxIsocEPList[epid].sub = 0;
-					dbg_isoc("URB list non-empty and no SB list, EP disabled");
-				}
-			} else {
-				dbg_isoc("Urb 0x%p not found, completed already?", urb);
-			}
-		} else {
-
-			urb_list_del(urb, epid);
-
-			/* For in traffic there is only one SB descriptor for each EP even
-			   though there may be several urbs (all urbs point at the same SB). */
-			if (urb_list_empty(epid)) {
-				/* No more urbs, remove the SB. */
-				TxIsocEPList[epid].sub = 0;
-				etrax_remove_from_sb_list(urb);
-			} else {
-				TxIsocEPList[epid].hw_len = 0;
-				TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-			}
-		}
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 1);
-	}
-	/* Free the epid if urb list is empty. */
-	if (urb_list_empty(epid)) {
-		etrax_usb_free_epid(epid);
-	}
-	restore_flags(flags);
-
-	/* Must be done before calling completion handler. */
-	kfree(urb_priv);
-	urb->hcpriv = 0;
-
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	DBFEXIT;
-	return 0;
-}
-
-static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
-{
-	DBFENTER;
-	DBFEXIT;
-	return (*R_USB_FM_NUMBER & 0x7ff);
-}
-
-static int etrax_usb_allocate_dev(struct usb_device *usb_dev)
-{
-	DBFENTER;
-	DBFEXIT;
-	return 0;
-}
-
-static int etrax_usb_deallocate_dev(struct usb_device *usb_dev)
-{
-	DBFENTER;
-	DBFEXIT;
-	return 0;
-}
-
-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
-{
-	DBFENTER;
-
-	/* This interrupt handler could be used when unlinking EP descriptors. */
-
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
-		USB_EP_Desc_t *ep;
-
-		//dbg_bulk("dma8_sub0_descr (BULK) intr.");
-
-		/* It should be safe clearing the interrupt here, since we don't expect to get a new
-		   one until we restart the bulk channel. */
-		*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
-
-		/* Wait while the DMA is running (though we don't expect it to be). */
-		while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));
-
-		/* Advance the DMA to the next EP descriptor. */
-		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
-
-		//dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);
-
-		/* ep->next is already a physical address; no need for a virt_to_phys. */
-		*R_DMA_CH8_SUB0_EP = ep->next;
-
-		/* Start the DMA bulk channel again. */
-		*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
-	}
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
-		struct urb *urb;
-		int epid;
-		etrax_urb_priv_t *urb_priv;
-		unsigned long int flags;
-
-		dbg_ctrl("dma8_sub1_descr (CTRL) intr.");
-		*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
-
-		/* The complete callback gets called so we cli. */
-		save_flags(flags);
-		cli();
-
-		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-			if ((TxCtrlEPList[epid].sub == 0) ||
-			    (epid == DUMMY_EPID) ||
-			    (epid == INVALID_EPID)) {
-				/* Nothing here to see. */
-				continue;
-			}
-
-			/* Get the first urb (if any). */
-			urb = urb_list_first(epid);
-
-			if (urb) {
-
-				/* Sanity check. */
-				assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);
-
-				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-				assert(urb_priv);
-
-				if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {
-					assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
-
-					etrax_usb_complete_urb(urb, 0);
-				}
-			}
-		}
-		restore_flags(flags);
-	}
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
-		dbg_intr("dma8_sub2_descr (INTR) intr.");
-		*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
-	}
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
-		struct urb *urb;
-		int epid;
-		int epid_done;
-		etrax_urb_priv_t *urb_priv;
-		USB_SB_Desc_t *sb_desc;
-
-		usb_isoc_complete_data_t *comp_data = NULL;
-
-		/* One or more isoc out transfers are done. */
-		dbg_isoc("dma8_sub3_descr (ISOC) intr.");
-
-		/* For each isoc out EP search for the first sb_desc with the intr flag
-		   set.  This descriptor must be the last packet from an URB.  Then
-		   traverse the URB list for the EP until the URB with urb_priv->last_sb
-		   matching the intr-marked sb_desc is found.  All URBs before this have
-		   been sent.
-		*/
-
-		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-			/* Skip past epids with no SB lists, epids used for in traffic,
-			   and special (dummy, invalid) epids. */
-			if ((TxIsocEPList[epid].sub == 0) ||
-			    (test_bit(epid, (void *)&epid_out_traffic) == 0) ||
-			    (epid == DUMMY_EPID) ||
-			    (epid == INVALID_EPID)) {
-				/* Nothing here to see. */
-				continue;
-			}
-			sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
-
-			/* Find the last descriptor of the currently active URB for this ep.
-			   This is the first descriptor in the sub list marked for a descriptor
-			   interrupt. */
-			while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
-				sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
-			}
-			assert(sb_desc);
-
-			dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",
-				 epid,
-				 phys_to_virt(TxIsocEPList[epid].sub),
-				 sb_desc);
-
-			epid_done = 0;
-
-			/* Get the first urb (if any). */
-			urb = urb_list_first(epid);
-			assert(urb);
-
-			while (urb && !epid_done) {
-
-				/* Sanity check. */
-				assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
-
-				if (!usb_pipeout(urb->pipe)) {
-					/* descr interrupts are generated only for out pipes. */
-					epid_done = 1;
-					continue;
-				}
-
-				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-				assert(urb_priv);
-
-				if (sb_desc != urb_priv->last_sb) {
-
-					/* This urb has been sent. */
-					dbg_isoc("out URB 0x%p sent", urb);
-
-					urb_priv->urb_state = TRANSFER_DONE;
-
-				} else if ((sb_desc == urb_priv->last_sb) &&
-					   !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
-
-					assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));
-					assert(sb_desc->next == 0);
-
-					dbg_isoc("out URB 0x%p last in list, epid disabled", urb);
-					TxIsocEPList[epid].sub = 0;
-					TxIsocEPList[epid].hw_len = 0;
-					urb_priv->urb_state = TRANSFER_DONE;
-
-					epid_done = 1;
-
-				} else {
-					epid_done = 1;
-				}
-				if (!epid_done) {
-					urb = urb_list_next(urb, epid);
-				}
-			}
-
-		}
-
-		*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
-
-		comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
-		assert(comp_data != NULL);
-
-                INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);
-                schedule_work(&comp_data->usb_bh);
-	}
-
-	DBFEXIT;
-        return IRQ_HANDLED;
-}
-
-static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
-{
-	usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;
-
-	struct urb *urb;
-	int epid;
-	int epid_done;
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");
-
-	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-
-		epid_done = 0;
-
-		/* The descriptor interrupt handler has marked all transmitted isoch. out
-		   URBs with TRANSFER_DONE.  Now we traverse all epids and for all that
- 		   have isoch. out traffic traverse its URB list and complete the
-		   transmitted URB.
-		*/
-
-		while (!epid_done) {
-
-			/* Get the first urb (if any). */
-			urb = urb_list_first(epid);
-			if (urb == 0) {
-				epid_done = 1;
-				continue;
-			}
-
-			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
-					epid_done = 1;
-					continue;
-			}
-
-			if (!usb_pipeout(urb->pipe)) {
-				/* descr interrupts are generated only for out pipes. */
-				epid_done = 1;
-				continue;
-			}
-
-			dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);
-
-			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-			assert(urb_priv);
-
-			if (urb_priv->urb_state == TRANSFER_DONE) {
-				int i;
-				struct usb_iso_packet_descriptor *packet;
-
-				/* This urb has been sent. */
-				dbg_isoc("Completing isoc out URB 0x%p", urb);
-
-				for (i = 0; i < urb->number_of_packets; i++) {
-					packet = &urb->iso_frame_desc[i];
-					packet->status = 0;
-					packet->actual_length = packet->length;
-				}
-
-				etrax_usb_complete_isoc_urb(urb, 0);
-
-				if (urb_list_empty(epid)) {
-					etrax_usb_free_epid(epid);
-					epid_done = 1;
-				}
-			} else {
-				epid_done = 1;
-			}
-		}
-		restore_flags(flags);
-
-	}
-	kmem_cache_free(isoc_compl_cache, comp_data);
-
-	DBFEXIT;
-}
-
-
-
-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
-{
-	struct urb *urb;
-	etrax_urb_priv_t *urb_priv;
-	int epid = 0;
-	unsigned long flags;
-
-	/* Isoc diagnostics. */
-	static int curr_fm = 0;
-	static int prev_fm = 0;
-
-	DBFENTER;
-
-	/* Clear this interrupt. */
-	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
-
-	/* Note that this while loop assumes that all packets span only
-	   one rx descriptor. */
-
-	/* The reason we cli here is that we call the driver's callback functions. */
-	save_flags(flags);
-	cli();
-
-	while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
-
-		epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
-		urb = urb_list_first(epid);
-
-		//printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);
-
-		if (!urb) {
-			err("No urb for epid %d in rx interrupt", epid);
-			__dump_ept_data(epid);
-			goto skip_out;
-		}
-
-		/* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since
-		   ctrl pipes are not. */
-
-		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
-			__u32 r_usb_ept_data;
-			int no_error = 0;
-
-			assert(test_bit(epid, (void *)&epid_usage_bitmask));
-
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-			nop();
-			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-				r_usb_ept_data = *R_USB_EPT_DATA_ISO;
-
-				if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
-				    (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
-					/* Not an error, just a failure to receive an expected iso
-					   in packet in this frame.  This is not documented
-					   in the designers reference.
-					*/
-					no_error++;
-				} else {
-					warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);
-				}
-			} else {
-				r_usb_ept_data = *R_USB_EPT_DATA;
-				warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);
-			}
-
-			if (!no_error){
-				warn("error in rx desc->status, epid %d, first urb = 0x%lx",
-				     epid, (unsigned long)urb);
-				__dump_in_desc(myNextRxDesc);
-
-				warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);
-
-				/* Check that ept was disabled when error occurred. */
-				switch (usb_pipetype(urb->pipe)) {
-				case PIPE_BULK:
-					assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				case PIPE_CONTROL:
-					assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				case PIPE_INTERRUPT:
-					assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				case PIPE_ISOCHRONOUS:
-					assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				default:
-					warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",
-					     usb_pipetype(urb->pipe),
-					     urb);
-				}
-				etrax_usb_complete_urb(urb, -EPROTO);
-				goto skip_out;
-			}
-		}
-
-		urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-		assert(urb_priv);
-
-		if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
-		    (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
-		    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
-
-			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
-				/* We get nodata for empty data transactions, and the rx descriptor's
-				   hw_len field is not valid in that case. No data to copy in other
-				   words. */
-			} else {
-				/* Make sure the data fits in the buffer. */
-				assert(urb_priv->rx_offset + myNextRxDesc->hw_len
-				       <= urb->transfer_buffer_length);
-
-				memcpy(urb->transfer_buffer + urb_priv->rx_offset,
-				       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
-				urb_priv->rx_offset += myNextRxDesc->hw_len;
-			}
-
-			if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
-				if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&
-				    ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==
-				     IO_STATE(USB_EP_command, enable, yes))) {
-					/* The EP is still enabled, so the OUT packet used to ack
-					   the in data is probably not processed yet.  If the EP
-					   sub pointer has not moved beyond urb_priv->last_sb mark
-					   it for a descriptor interrupt and complete the urb in
-					   the descriptor interrupt handler.
-					*/
-					USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;
-
-					while ((sub != NULL) && (sub != urb_priv->last_sb)) {
-						sub = sub->next ? phys_to_virt(sub->next) : 0;
-					}
-					if (sub != NULL) {
-						/* The urb has not been fully processed. */
-						urb_priv->urb_state = WAITING_FOR_DESCR_INTR;
-					} else {
-						warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);
-						etrax_usb_complete_urb(urb, 0);
-					}
-				} else {
-					etrax_usb_complete_urb(urb, 0);
-				}
-			}
-
-		} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-
-			struct usb_iso_packet_descriptor *packet;
-
-			if (urb_priv->urb_state == UNLINK) {
-				info("Ignoring rx data for urb being unlinked.");
-				goto skip_out;
-			} else if (urb_priv->urb_state == NOT_STARTED) {
-				info("What? Got rx data for urb that isn't started?");
-				goto skip_out;
-			}
-
-			packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
-			packet->status = 0;
-
-			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
-				/* We get nodata for empty data transactions, and the rx descriptor's
-				   hw_len field is not valid in that case. We copy 0 bytes however to
-				   stay in synch. */
-				packet->actual_length = 0;
-			} else {
-				packet->actual_length = myNextRxDesc->hw_len;
-				/* Make sure the data fits in the buffer. */
-				assert(packet->actual_length <= packet->length);
-				memcpy(urb->transfer_buffer + packet->offset,
-				       phys_to_virt(myNextRxDesc->buf), packet->actual_length);
-			}
-
-			/* Increment the packet counter. */
-			urb_priv->isoc_packet_counter++;
-
-			/* Note that we don't care about the eot field in the rx descriptor's status.
-			   It will always be set for isoc traffic. */
-			if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
-
-				/* Out-of-synch diagnostics. */
-				curr_fm = (*R_USB_FM_NUMBER & 0x7ff);
-				if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {
-					/* This test is wrong, if there is more than one isoc
-					   in endpoint active it will always calculate wrong
-					   since prev_fm is shared by all endpoints.
-
-					   FIXME Make this check per URB using urb->start_frame.
-					*/
-					dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",
-						 prev_fm, curr_fm);
-
-				}
-				prev_fm = curr_fm;
-
-				/* Complete the urb with status OK. */
-				etrax_usb_complete_isoc_urb(urb, 0);
-			}
-		}
-
-	skip_out:
-
-		/* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr
-		   has the same layout as USB_IN_Desc for the relevant fields.) */
-		prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);
-
-		myPrevRxDesc = myNextRxDesc;
-		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
-		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
-		myLastRxDesc = myPrevRxDesc;
-
-		myNextRxDesc->status = 0;
-		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
-	}
-
-	restore_flags(flags);
-
-	DBFEXIT;
-
-        return IRQ_HANDLED;
-}
-
-
-/* This function will unlink the SB descriptors associated with this urb. */
-static int etrax_remove_from_sb_list(struct urb *urb)
-{
-	USB_SB_Desc_t *next_sb, *first_sb, *last_sb;
-	etrax_urb_priv_t *urb_priv;
-	int i = 0;
-
-	DBFENTER;
-
-	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	assert(urb_priv);
-
-	/* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor
-	   doesn't really need to be disabled, it's just that we expect it to be. */
-	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-		assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
-	}
-
-	first_sb = urb_priv->first_sb;
-	last_sb = urb_priv->last_sb;
-
-	assert(first_sb);
-	assert(last_sb);
-
-	while (first_sb != last_sb) {
-		next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);
-		kmem_cache_free(usb_desc_cache, first_sb);
-		first_sb = next_sb;
-		i++;
-	}
-	kmem_cache_free(usb_desc_cache, last_sb);
-	i++;
-	dbg_sb("%d SB descriptors freed", i);
-	/* Compare i with urb->number_of_packets for Isoc traffic.
-	   Should be same when calling unlink_urb */
-
-	DBFEXIT;
-
-	return i;
-}
-
-static int etrax_usb_submit_bulk_urb(struct urb *urb)
-{
-	int epid;
-	int empty;
-	unsigned long flags;
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	/* Epid allocation, empty check and list add must be protected.
-	   Read about this in etrax_usb_submit_ctrl_urb. */
-
-	spin_lock_irqsave(&urb_list_lock, flags);
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		DBFEXIT;
-		spin_unlock_irqrestore(&urb_list_lock, flags);
-		return -ENOMEM;
-	}
-	empty = urb_list_empty(epid);
-	urb_list_add(urb, epid);
-	spin_unlock_irqrestore(&urb_list_lock, flags);
-
-	dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",
-		 usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);
-
-	/* Mark the urb as being in progress. */
-	urb->status = -EINPROGRESS;
-
-	/* Setup the hcpriv data. */
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
-	assert(urb_priv != NULL);
-	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
-	urb_priv->urb_state = NOT_STARTED;
-	urb->hcpriv = urb_priv;
-
-	if (empty) {
-		etrax_usb_add_to_bulk_sb_list(urb, epid);
-	}
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
-{
-	USB_SB_Desc_t *sb_desc;
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	unsigned long flags;
-	char maxlen;
-
-	DBFENTER;
-
-	dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);
-
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-
-	sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-	assert(sb_desc != NULL);
-	memset(sb_desc, 0, sizeof(USB_SB_Desc_t));
-
-
-	if (usb_pipeout(urb->pipe)) {
-
-		dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);
-
-		/* This is probably a sanity check of the bulk transaction length
-		   not being larger than 64 kB. */
-		if (urb->transfer_buffer_length > 0xffff) {
-			panic("urb->transfer_buffer_length > 0xffff");
-		}
-
-		sb_desc->sw_len = urb->transfer_buffer_length;
-
-		/* The rem field is don't care if it's not a full-length transfer, so setting
-		   it shouldn't hurt. Also, rem isn't used for OUT traffic. */
-		sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
-				    IO_STATE(USB_SB_command, tt, out) |
-				    IO_STATE(USB_SB_command, eot, yes) |
-				    IO_STATE(USB_SB_command, eol, yes));
-
-		/* The full field is set to yes, even if we don't actually check that this is
-		   a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).
-		   Setting full prevents the USB controller from sending an empty packet in
-		   that case.  However, if URB_ZERO_PACKET was set we want that. */
-		if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
-			sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
-		}
-
-		sb_desc->buf = virt_to_phys(urb->transfer_buffer);
-		sb_desc->next = 0;
-
-	} else if (usb_pipein(urb->pipe)) {
-
-		dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);
-
-		sb_desc->sw_len = urb->transfer_buffer_length ?
-			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
-
-		/* The rem field is don't care if it's not a full-length transfer, so setting
-		   it shouldn't hurt. */
-		sb_desc->command =
-			(IO_FIELD(USB_SB_command, rem,
-				  urb->transfer_buffer_length % maxlen) |
-			 IO_STATE(USB_SB_command, tt, in) |
-			 IO_STATE(USB_SB_command, eot, yes) |
-			 IO_STATE(USB_SB_command, eol, yes));
-
-		sb_desc->buf = 0;
-		sb_desc->next = 0;
-	}
-
-	urb_priv->first_sb = sb_desc;
-	urb_priv->last_sb = sb_desc;
-	urb_priv->epid = epid;
-
-	urb->hcpriv = urb_priv;
-
-	/* Reset toggle bits and reset error count. */
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-
-	/* FIXME: Is this a special case since the hold field is checked,
-	   or should we check hold in a lot of other cases as well? */
-	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
-		panic("Hold was set in %s", __FUNCTION__);
-	}
-
-	/* Reset error counters (regardless of which direction this traffic is). */
-	*R_USB_EPT_DATA &=
-		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
-		  IO_MASK(R_USB_EPT_DATA, error_count_out));
-
-	/* Software must preset the toggle bits. */
-	if (usb_pipeout(urb->pipe)) {
-		char toggle =
-			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
-		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
-	} else {
-		char toggle =
-			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
-		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
-	}
-
-	/* Assert that the EP descriptor is disabled. */
-	assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-
-	/* The reason we set the EP's sub pointer directly instead of
-	   walking the SB list and linking it last in the list is that we only
-	   have one active urb at a time (the rest are queued). */
-
-	/* Note that we cannot have interrupts running when we have set the SB descriptor
-	   but the EP is not yet enabled.  If a bulk eot happens for another EP, we will
-	   find this EP disabled and with a SB != 0, which will make us think that it's done. */
-	TxBulkEPList[epid].sub = virt_to_phys(sb_desc);
-	TxBulkEPList[epid].hw_len = 0;
-	/* Note that we don't have to fill in the ep_id field since this
-	   was done when we allocated the EP descriptors in init_tx_bulk_ep. */
-
-	/* Check if the dummy list is already with us (if several urbs were queued). */
-	if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {
-
-		dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d",
-			 (unsigned long)urb, epid);
-
-		/* The last EP in the dummy list already has its next pointer set to
-		   TxBulkEPList[epid].next. */
-
-		/* We don't need to check if the DMA is at this EP or not before changing the
-		   next pointer, since we will do it in one 32-bit write (EP descriptors are
-		   32-bit aligned). */
-		TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
-	}
-	/* Enable the EP descr. */
-	dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);
-	TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-
-	/* Everything is set up, safe to enable interrupts again. */
-	restore_flags(flags);
-
-	/* If the DMA bulk channel isn't running, we need to restart it if it
-	   has stopped at the last EP descriptor (DMA stopped because there was
-	   no more traffic) or if it has stopped at a dummy EP with the intr flag
-	   set (DMA stopped because we were too slow in inserting new traffic). */
-	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
-
-		USB_EP_Desc_t *ep;
-		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
-		dbg_bulk("DMA channel not running in add");
-		dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);
-
-		if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||
-		    (ep->command & 0x8) >> 3) {
-			*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
-			/* Update/restart the bulk start timer since we just started the channel. */
-			mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
-			/* Update/restart the bulk eot timer since we just inserted traffic. */
-			mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
-		}
-	}
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_bulk_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-	unsigned long flags;
-
-	DBFENTER;
-
-	if (status)
-		warn("Completing bulk urb with status %d.", status);
-
-	dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid);
-
-	/* Update the urb list. */
-	urb_list_del(urb, epid);
-
-	/* For an IN pipe, we always set the actual length, regardless of whether there was
-	   an error or not (which means the device driver can use the data if it wants to). */
-	if (usb_pipein(urb->pipe)) {
-		urb->actual_length = urb_priv->rx_offset;
-	} else {
-		/* Set actual_length for OUT urbs also; the USB mass storage driver seems
-		   to want that. We wouldn't know of any partial writes if there was an error. */
-		if (status == 0) {
-			urb->actual_length = urb->transfer_buffer_length;
-		} else {
-			urb->actual_length = 0;
-		}
-	}
-
-	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
-	   Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-
-	/* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */
-	if (usb_pipeout(urb->pipe)) {
-		char toggle =
-			IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			      usb_pipeout(urb->pipe), toggle);
-	} else {
-		char toggle =
-			IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			      usb_pipeout(urb->pipe), toggle);
-	}
-	restore_flags(flags);
-
-	/* Remember to free the SBs. */
-	etrax_remove_from_sb_list(urb);
-	kfree(urb_priv);
-	urb->hcpriv = 0;
-
-	/* If there are any more urb's in the list we'd better start sending */
-	if (!urb_list_empty(epid)) {
-
-		struct urb *new_urb;
-
-		/* Get the first urb. */
-		new_urb = urb_list_first(epid);
-		assert(new_urb);
-
-		dbg_bulk("More bulk for epid %d", epid);
-
-		etrax_usb_add_to_bulk_sb_list(new_urb, epid);
-	}
-
-	urb->status = status;
-
-	/* We let any non-zero status from the layer above have precedence. */
-	if (status == 0) {
-		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
-		   is to be treated as an error. */
-		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-			if (usb_pipein(urb->pipe) &&
-			    (urb->actual_length !=
-			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
-				urb->status = -EREMOTEIO;
-			}
-		}
-	}
-
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	if (urb_list_empty(epid)) {
-		/* This means that this EP is now free, deconfigure it. */
-		etrax_usb_free_epid(epid);
-
-		/* No more traffic; time to clean up.
-		   Must set sub pointer to 0, since we look at the sub pointer when handling
-		   the bulk eot interrupt. */
-
-		dbg_bulk("No bulk for epid %d", epid);
-
-		TxBulkEPList[epid].sub = 0;
-
-		/* Unlink the dummy list. */
-
-		dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d",
-			 (unsigned long)urb, epid);
-
-		/* No need to wait for the DMA before changing the next pointer.
-		   The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
-		   the last one (INVALID_EPID) for actual traffic. */
-		TxBulkEPList[epid].next =
-			virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
-	}
-
-	DBFEXIT;
-}
-
-static int etrax_usb_submit_ctrl_urb(struct urb *urb)
-{
-	int epid;
-	int empty;
-	unsigned long flags;
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	/* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */
-
-	/* Epid allocation, empty check and list add must be protected.
-
-	   Epid allocation because if we find an existing epid for this endpoint an urb might be
-	   completed (emptying the list) before we add the new urb to the list, causing the epid
-	   to be de-allocated. We would then start the transfer with an invalid epid -> epid attn.
-
-	   Empty check and add because otherwise we might conclude that the list is not empty,
-	   after which it becomes empty before we add the new urb to the list, causing us not to
-	   insert the new traffic into the SB list. */
-
-	spin_lock_irqsave(&urb_list_lock, flags);
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		spin_unlock_irqrestore(&urb_list_lock, flags);
-		DBFEXIT;
-		return -ENOMEM;
-	}
-	empty = urb_list_empty(epid);
-	urb_list_add(urb, epid);
-	spin_unlock_irqrestore(&urb_list_lock, flags);
-
-	dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d",
-		 (unsigned long)urb, empty ? "empty" : "", epid);
-
-	/* Mark the urb as being in progress. */
-	urb->status = -EINPROGRESS;
-
-	/* Setup the hcpriv data. */
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
-	assert(urb_priv != NULL);
-	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
-	urb_priv->urb_state = NOT_STARTED;
-	urb->hcpriv = urb_priv;
-
-	if (empty) {
-		etrax_usb_add_to_ctrl_sb_list(urb, epid);
-	}
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid)
-{
-	USB_SB_Desc_t *sb_desc_setup;
-	USB_SB_Desc_t *sb_desc_data;
-	USB_SB_Desc_t *sb_desc_status;
-
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-
-	unsigned long flags;
-	char maxlen;
-
-	DBFENTER;
-
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-
-	sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-	assert(sb_desc_setup != NULL);
-	sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-	assert(sb_desc_status != NULL);
-
-	/* Initialize the mandatory setup SB descriptor (used only in control transfers) */
-	sb_desc_setup->sw_len = 8;
-	sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) |
-				  IO_STATE(USB_SB_command, tt, setup) |
-				  IO_STATE(USB_SB_command, full, yes) |
-				  IO_STATE(USB_SB_command, eot, yes));
-
-	sb_desc_setup->buf = virt_to_phys(urb->setup_packet);
-
-	if (usb_pipeout(urb->pipe)) {
-		dbg_ctrl("Transfer for epid %d is OUT", epid);
-
-		/* If this Control OUT transfer has an optional data stage we add an OUT token
-		   before the mandatory IN (status) token, hence the reordered SB list */
-
-		sb_desc_setup->next = virt_to_phys(sb_desc_status);
-		if (urb->transfer_buffer) {
-
-			dbg_ctrl("This OUT transfer has an extra data stage");
-
-			sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-			assert(sb_desc_data != NULL);
-
-			sb_desc_setup->next = virt_to_phys(sb_desc_data);
-
-			sb_desc_data->sw_len = urb->transfer_buffer_length;
-			sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) |
-						 IO_STATE(USB_SB_command, full, yes) |
-						 IO_STATE(USB_SB_command, eot, yes));
-			sb_desc_data->buf = virt_to_phys(urb->transfer_buffer);
-			sb_desc_data->next = virt_to_phys(sb_desc_status);
-		}
-
-		sb_desc_status->sw_len = 1;
-		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
-					   IO_STATE(USB_SB_command, tt, in) |
-					   IO_STATE(USB_SB_command, eot, yes) |
-					   IO_STATE(USB_SB_command, intr, yes) |
-					   IO_STATE(USB_SB_command, eol, yes));
-
-		sb_desc_status->buf = 0;
-		sb_desc_status->next = 0;
-
-	} else if (usb_pipein(urb->pipe)) {
-
-		dbg_ctrl("Transfer for epid %d is IN", epid);
-		dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
-		dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
-
-		sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-		assert(sb_desc_data != NULL);
-
-		sb_desc_setup->next = virt_to_phys(sb_desc_data);
-
-		sb_desc_data->sw_len = urb->transfer_buffer_length ?
-			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
-		dbg_ctrl("sw_len got %d", sb_desc_data->sw_len);
-
-		sb_desc_data->command =
-			(IO_FIELD(USB_SB_command, rem,
-				  urb->transfer_buffer_length % maxlen) |
-			 IO_STATE(USB_SB_command, tt, in) |
-			 IO_STATE(USB_SB_command, eot, yes));
-
-		sb_desc_data->buf = 0;
-		sb_desc_data->next = virt_to_phys(sb_desc_status);
-
-		/* Read comment at zout_buffer declaration for an explanation to this. */
-		sb_desc_status->sw_len = 1;
-		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
-					   IO_STATE(USB_SB_command, tt, zout) |
-					   IO_STATE(USB_SB_command, full, yes) |
-					   IO_STATE(USB_SB_command, eot, yes) |
-					   IO_STATE(USB_SB_command, intr, yes) |
-					   IO_STATE(USB_SB_command, eol, yes));
-
-		sb_desc_status->buf = virt_to_phys(&zout_buffer[0]);
-		sb_desc_status->next = 0;
-	}
-
-	urb_priv->first_sb = sb_desc_setup;
-	urb_priv->last_sb = sb_desc_status;
-	urb_priv->epid = epid;
-
-	urb_priv->urb_state = STARTED;
-
-	/* Reset toggle bits and reset error count, remember to di and ei */
-	/* Warning: it is possible that this locking doesn't work with bottom-halves */
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
-		panic("Hold was set in %s", __FUNCTION__);
-	}
-
-
-	/* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits
-	   are set to a specific value. Why the difference? Read "Transfer and Toggle Bits
-	   in Designer's Reference, p. 8 - 11. */
-	*R_USB_EPT_DATA &=
-		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
-		  IO_MASK(R_USB_EPT_DATA, error_count_out) |
-		  IO_MASK(R_USB_EPT_DATA, t_in) |
-		  IO_MASK(R_USB_EPT_DATA, t_out));
-
-	/* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now
-	   (i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */
-	restore_flags(flags);
-
-	/* Assert that the EP descriptor is disabled. */
-	assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-
-	/* Set up and enable the EP descriptor. */
-	TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup);
-	TxCtrlEPList[epid].hw_len = 0;
-	TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-
-	/* We start the DMA sub channel without checking if it's running or not, because:
-	   1) If it's already running, issuing the start command is a nop.
-	   2) We avoid a test-and-set race condition. */
-	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-
-	DBFENTER;
-
-	if (status)
-		warn("Completing ctrl urb with status %d.", status);
-
-	dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb);
-
-	/* Remove this urb from the list. */
-	urb_list_del(urb, epid);
-
-	/* For an IN pipe, we always set the actual length, regardless of whether there was
-	   an error or not (which means the device driver can use the data if it wants to). */
-	if (usb_pipein(urb->pipe)) {
-		urb->actual_length = urb_priv->rx_offset;
-	}
-
-	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
-	   Like, maybe we shouldn't insert more traffic. */
-
-	/* Remember to free the SBs. */
-	etrax_remove_from_sb_list(urb);
-	kfree(urb_priv);
-	urb->hcpriv = 0;
-
-	/* If there are any more urbs in the list we'd better start sending. */
-	if (!urb_list_empty(epid)) {
-		struct urb *new_urb;
-
-		/* Get the first urb. */
-		new_urb = urb_list_first(epid);
-		assert(new_urb);
-
-		dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb);
-
-		etrax_usb_add_to_ctrl_sb_list(new_urb, epid);
-	}
-
-	urb->status = status;
-
-	/* We let any non-zero status from the layer above have precedence. */
-	if (status == 0) {
-		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
-		   is to be treated as an error. */
-		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-			if (usb_pipein(urb->pipe) &&
-			    (urb->actual_length !=
-			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
-				urb->status = -EREMOTEIO;
-			}
-		}
-	}
-
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	if (urb_list_empty(epid)) {
-		/* No more traffic. Time to clean up. */
-		etrax_usb_free_epid(epid);
-		/* Must set sub pointer to 0. */
-		dbg_ctrl("No ctrl for epid %d", epid);
-		TxCtrlEPList[epid].sub = 0;
-	}
-
-	DBFEXIT;
-}
-
-static int etrax_usb_submit_intr_urb(struct urb *urb)
-{
-
-	int epid;
-
-	DBFENTER;
-
-	if (usb_pipeout(urb->pipe)) {
-		/* Unsupported transfer type.
-		   We don't support interrupt out traffic. (If we do, we can't support
-		   intervals for neither in or out traffic, but are forced to schedule all
-		   interrupt traffic in one frame.) */
-		return -EINVAL;
-	}
-
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		DBFEXIT;
-		return -ENOMEM;
-	}
-
-	if (!urb_list_empty(epid)) {
-		/* There is already a queued urb for this endpoint. */
-		etrax_usb_free_epid(epid);
-		return -ENXIO;
-	}
-
-	urb->status = -EINPROGRESS;
-
-	dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid);
-
-	urb_list_add(urb, epid);
-	etrax_usb_add_to_intr_sb_list(urb, epid);
-
-	return 0;
-
-	DBFEXIT;
-}
-
-static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
-{
-
-	volatile USB_EP_Desc_t *tmp_ep;
-	volatile USB_EP_Desc_t *first_ep;
-
-	char maxlen;
-	int interval;
-	int i;
-
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	interval = urb->interval;
-
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
-	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
-	urb->hcpriv = urb_priv;
-
-	first_ep = &TxIntrEPList[0];
-
-	/* Round of the interval to 2^n, it is obvious that this code favours
-	   smaller numbers, but that is actually a good thing */
-	/* FIXME: The "rounding error" for larger intervals will be quite
-	   large. For in traffic this shouldn't be a problem since it will only
-	   mean that we "poll" more often. */
-	for (i = 0; interval; i++) {
-		interval = interval >> 1;
-	}
-	interval = 1 << (i - 1);
-
-	dbg_intr("Interval rounded to %d", interval);
-
-	tmp_ep = first_ep;
-	i = 0;
-	do {
-		if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
-			if ((i % interval) == 0) {
-				/* Insert the traffic ep after tmp_ep */
-				USB_EP_Desc_t *ep_desc;
-				USB_SB_Desc_t *sb_desc;
-
-				dbg_intr("Inserting EP for epid %d", epid);
-
-				ep_desc = (USB_EP_Desc_t *)
-					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-				sb_desc = (USB_SB_Desc_t *)
-					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-				assert(ep_desc != NULL);
-				CHECK_ALIGN(ep_desc);
-				assert(sb_desc != NULL);
-
-				ep_desc->sub = virt_to_phys(sb_desc);
-				ep_desc->hw_len = 0;
-				ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
-						    IO_STATE(USB_EP_command, enable, yes));
-
-
-				/* Round upwards the number of packets of size maxlen
-				   that this SB descriptor should receive. */
-				sb_desc->sw_len = urb->transfer_buffer_length ?
-					(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
-				sb_desc->next = 0;
-				sb_desc->buf = 0;
-				sb_desc->command =
-					(IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) |
-					 IO_STATE(USB_SB_command, tt, in) |
-					 IO_STATE(USB_SB_command, eot, yes) |
-					 IO_STATE(USB_SB_command, eol, yes));
-
-				ep_desc->next = tmp_ep->next;
-				tmp_ep->next = virt_to_phys(ep_desc);
-			}
-			i++;
-		}
-		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
-	} while (tmp_ep != first_ep);
-
-
-	/* Note that first_sb/last_sb doesn't apply to interrupt traffic. */
-	urb_priv->epid = epid;
-
-	/* We start the DMA sub channel without checking if it's running or not, because:
-	   1) If it's already running, issuing the start command is a nop.
-	   2) We avoid a test-and-set race condition. */
-	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-
-
-static void etrax_usb_complete_intr_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-
-	DBFENTER;
-
-	if (status)
-		warn("Completing intr urb with status %d.", status);
-
-	dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb);
-
-	urb->status = status;
-	urb->actual_length = urb_priv->rx_offset;
-
-	dbg_intr("interrupt urb->actual_length = %d", urb->actual_length);
-
-	/* We let any non-zero status from the layer above have precedence. */
-	if (status == 0) {
-		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
-		   is to be treated as an error. */
-		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-			if (urb->actual_length !=
-			    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
-				urb->status = -EREMOTEIO;
-			}
-		}
-	}
-
-	/* The driver will resubmit the URB so we need to remove it first */
-        etrax_usb_unlink_urb(urb, 0);
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	DBFEXIT;
-}
-
-
-static int etrax_usb_submit_isoc_urb(struct urb *urb)
-{
-	int epid;
-	unsigned long flags;
-
-	DBFENTER;
-
-	dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb);
-
-	/* Epid allocation, empty check and list add must be protected.
-	   Read about this in etrax_usb_submit_ctrl_urb. */
-
-	spin_lock_irqsave(&urb_list_lock, flags);
-	/* Is there an active epid for this urb ? */
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		DBFEXIT;
-		spin_unlock_irqrestore(&urb_list_lock, flags);
-		return -ENOMEM;
-	}
-
-	/* Ok, now we got valid endpoint, lets insert some traffic */
-
-	urb->status = -EINPROGRESS;
-
-	/* Find the last urb in the URB_List and add this urb after that one.
-	   Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list.  This
-	   is important to make this in "real time" since isochronous traffic is
-	   time sensitive. */
-
-	dbg_isoc("Adding isoc urb to (possibly empty) list");
-	urb_list_add(urb, epid);
-	etrax_usb_add_to_isoc_sb_list(urb, epid);
-	spin_unlock_irqrestore(&urb_list_lock, flags);
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_check_error_isoc_ep(const int epid)
-{
-	unsigned long int flags;
-	int error_code;
-	__u32 r_usb_ept_data;
-
-	/* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof,
-	   bulk_eot and epid_attn interrupts.  So we just check the status of
-	   the epid without testing if for it in R_USB_EPID_ATTN. */
-
-
-	save_flags(flags);
-	cli();
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
-	   registers, they are located at the same address and are of the same size.
-	   In other words, this read should be ok for isoc also. */
-	r_usb_ept_data = *R_USB_EPT_DATA;
-	restore_flags(flags);
-
-	error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
-
-	if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
-		warn("Hold was set for epid %d.", epid);
-		return;
-	}
-
-	if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) {
-
-		/* This indicates that the SB list of the ept was completed before
-		   new data was appended to it.  This is not an error, but indicates
-		   large system or USB load and could possibly cause trouble for
-		   very timing sensitive USB device drivers so we log it.
-		*/
-		info("Isoc. epid %d disabled with no error", epid);
-		return;
-
-	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) {
-		/* Not really a protocol error, just says that the endpoint gave
-		   a stall response. Note that error_code cannot be stall for isoc. */
-		panic("Isoc traffic cannot stall");
-
-	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) {
-		/* Two devices responded to a transaction request. Must be resolved
-		   by software. FIXME: Reset ports? */
-		panic("Bus error for epid %d."
-		      " Two devices responded to transaction request",
-		      epid);
-
-	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
-		/* DMA overrun or underrun. */
-		warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
-
-		/* It seems that error_code = buffer_error in
-		   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
-		   are the same error. */
-	}
-}
-
-
-static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
-{
-
-	int i = 0;
-
-	etrax_urb_priv_t *urb_priv;
-	USB_SB_Desc_t *prev_sb_desc,  *next_sb_desc, *temp_sb_desc;
-
-	DBFENTER;
-
-	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
-
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
-	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
-
-	urb->hcpriv = urb_priv;
-	urb_priv->epid = epid;
-
-	if (usb_pipeout(urb->pipe)) {
-
-		if (urb->number_of_packets == 0) panic("etrax_usb_add_to_isoc_sb_list 0 packets\n");
-
-		dbg_isoc("Transfer for epid %d is OUT", epid);
-		dbg_isoc("%d packets in URB", urb->number_of_packets);
-
-		/* Create one SB descriptor for each packet and link them together. */
-		for (i = 0; i < urb->number_of_packets; i++) {
-			if (!urb->iso_frame_desc[i].length)
-				continue;
-
-			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
-			assert(next_sb_desc != NULL);
-
-			if (urb->iso_frame_desc[i].length > 0) {
-
-				next_sb_desc->command = (IO_STATE(USB_SB_command, tt, out) |
-							 IO_STATE(USB_SB_command, eot, yes));
-
-				next_sb_desc->sw_len = urb->iso_frame_desc[i].length;
-				next_sb_desc->buf = virt_to_phys((char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset);
-
-				/* Check if full length transfer. */
-				if (urb->iso_frame_desc[i].length ==
-				    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
-					next_sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
-				}
-			} else {
-				dbg_isoc("zero len packet");
-				next_sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
-							 IO_STATE(USB_SB_command, tt, zout) |
-							 IO_STATE(USB_SB_command, eot, yes) |
-							 IO_STATE(USB_SB_command, full, yes));
-
-				next_sb_desc->sw_len = 1;
-				next_sb_desc->buf = virt_to_phys(&zout_buffer[0]);
-			}
-
-			/* First SB descriptor that belongs to this urb */
-			if (i == 0)
-				urb_priv->first_sb = next_sb_desc;
-			else
-				prev_sb_desc->next = virt_to_phys(next_sb_desc);
-
-			prev_sb_desc = next_sb_desc;
-		}
-
-		next_sb_desc->command |= (IO_STATE(USB_SB_command, intr, yes) |
-					  IO_STATE(USB_SB_command, eol, yes));
-		next_sb_desc->next = 0;
-		urb_priv->last_sb = next_sb_desc;
-
-	} else if (usb_pipein(urb->pipe)) {
-
-		dbg_isoc("Transfer for epid %d is IN", epid);
-		dbg_isoc("transfer_buffer_length = %d", urb->transfer_buffer_length);
-		dbg_isoc("rem is calculated to %d", urb->iso_frame_desc[urb->number_of_packets - 1].length);
-
-		/* Note that in descriptors for periodic traffic are not consumed. This means that
-		   the USB controller never propagates in the SB list. In other words, if there already
-		   is an SB descriptor in the list for this EP we don't have to do anything. */
-		if (TxIsocEPList[epid].sub == 0) {
-			dbg_isoc("Isoc traffic not already running, allocating SB");
-
-			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
-			assert(next_sb_desc != NULL);
-
-			next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) |
-						 IO_STATE(USB_SB_command, eot, yes) |
-						 IO_STATE(USB_SB_command, eol, yes));
-
-			next_sb_desc->next = 0;
-			next_sb_desc->sw_len = 1; /* Actual number of packets is not relevant
-						     for periodic in traffic as long as it is more
-						     than zero.  Set to 1 always. */
-			next_sb_desc->buf = 0;
-
-			/* The rem field is don't care for isoc traffic, so we don't set it. */
-
-			/* Only one SB descriptor that belongs to this urb. */
-			urb_priv->first_sb = next_sb_desc;
-			urb_priv->last_sb = next_sb_desc;
-
-		} else {
-
-			dbg_isoc("Isoc traffic already running, just setting first/last_sb");
-
-			/* Each EP for isoc in will have only one SB descriptor, setup when submitting the
-			   already active urb. Note that even though we may have several first_sb/last_sb
-			   pointing at the same SB descriptor, they are freed only once (when the list has
-			   become empty). */
-			urb_priv->first_sb = phys_to_virt(TxIsocEPList[epid].sub);
-			urb_priv->last_sb = phys_to_virt(TxIsocEPList[epid].sub);
-			return;
-		}
-
-	}
-
-	/* Find the spot to insert this urb and add it. */
-	if (TxIsocEPList[epid].sub == 0) {
-		/* First SB descriptor inserted in this list (in or out). */
-		dbg_isoc("Inserting SB desc first in list");
-		TxIsocEPList[epid].hw_len = 0;
-		TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
-
-	} else {
-		/* Isochronous traffic is already running, insert new traffic last (only out). */
-		dbg_isoc("Inserting SB desc last in list");
-		temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
-		while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
-		       IO_STATE(USB_SB_command, eol, yes)) {
-			assert(temp_sb_desc->next);
-			temp_sb_desc = phys_to_virt(temp_sb_desc->next);
-		}
-		dbg_isoc("Appending list on desc 0x%p", temp_sb_desc);
-
-		/* Next pointer must be set before eol is removed. */
-		temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
-		/* Clear the previous end of list flag since there is a new in the
-		   added SB descriptor list. */
-		temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
-
-		if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
-			/* 8.8.5 in Designer's Reference says we should check for and correct
-			   any errors in the EP here.  That should not be necessary if epid_attn
-			   is handled correctly, so we assume all is ok. */
-			dbg_isoc("EP disabled");
-			etrax_usb_check_error_isoc_ep(epid);
-
-			/* The SB list was exhausted. */
-			if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
-				/* The new sublist did not get processed before the EP was
-				   disabled.  Setup the EP again. */
-				dbg_isoc("Set EP sub to new list");
-				TxIsocEPList[epid].hw_len = 0;
-				TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
-			}
-		}
-	}
-
-	if (urb->transfer_flags & URB_ISO_ASAP) {
-		/* The isoc transfer should be started as soon as possible. The start_frame
-		   field is a return value if URB_ISO_ASAP was set. Comparing R_USB_FM_NUMBER
-		   with a USB Chief trace shows that the first isoc IN token is sent 2 frames
-		   later. I'm not sure how this affects usage of the start_frame field by the
-		   device driver, or how it affects things when USB_ISO_ASAP is not set, so
-		   therefore there's no compensation for the 2 frame "lag" here. */
-		urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
-		TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-		urb_priv->urb_state = STARTED;
-		dbg_isoc("URB_ISO_ASAP set, urb->start_frame set to %d", urb->start_frame);
-	} else {
-		/* Not started yet. */
-		urb_priv->urb_state = NOT_STARTED;
-		dbg_isoc("urb_priv->urb_state set to NOT_STARTED");
-	}
-
-       /* We start the DMA sub channel without checking if it's running or not, because:
-	  1) If it's already running, issuing the start command is a nop.
-	  2) We avoid a test-and-set race condition. */
-	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_isoc_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-	int auto_resubmit = 0;
-
-	DBFENTER;
-	dbg_isoc("complete urb 0x%p, status %d", urb, status);
-
-	if (status)
-		warn("Completing isoc urb with status %d.", status);
-
-	if (usb_pipein(urb->pipe)) {
-		int i;
-
-		/* Make that all isoc packets have status and length set before
-		   completing the urb. */
-		for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++) {
-			urb->iso_frame_desc[i].actual_length = 0;
-			urb->iso_frame_desc[i].status = -EPROTO;
-		}
-
-		urb_list_del(urb, epid);
-
-		if (!list_empty(&urb_list[epid])) {
-			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
-		} else {
-			unsigned long int flags;
-			if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-				/* The EP was enabled, disable it and wait. */
-				TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-				/* Ah, the luxury of busy-wait. */
-				while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
-			}
-
-			etrax_remove_from_sb_list(urb);
-			TxIsocEPList[epid].sub = 0;
-			TxIsocEPList[epid].hw_len = 0;
-
-			save_flags(flags);
-			cli();
-			etrax_usb_free_epid(epid);
-			restore_flags(flags);
-		}
-
-		urb->hcpriv = 0;
-		kfree(urb_priv);
-
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 0);
-	} else if (usb_pipeout(urb->pipe)) {
-		int freed_descr;
-
-		dbg_isoc("Isoc out urb complete 0x%p", urb);
-
-		/* Update the urb list. */
-		urb_list_del(urb, epid);
-
-		freed_descr = etrax_remove_from_sb_list(urb);
-		dbg_isoc("freed %d descriptors of %d packets", freed_descr, urb->number_of_packets);
-		assert(freed_descr == urb->number_of_packets);
-		urb->hcpriv = 0;
-		kfree(urb_priv);
-
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 0);
-	}
-
-	urb->status = status;
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	if (auto_resubmit) {
-		/* Check that urb was not unlinked by the complete callback. */
-		if (__urb_list_entry(urb, epid)) {
-			/* Move this one down the list. */
-			urb_list_move_last(urb, epid);
-
-			/* Mark the now first urb as started (may already be). */
-			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
-
-			/* Must set this to 0 since this urb is still active after
-			   completion. */
-			urb_priv->isoc_packet_counter = 0;
-		} else {
-			warn("(ISOC) automatic resubmit urb 0x%p removed by complete.", urb);
-		}
-	}
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_urb(struct urb *urb, int status)
-{
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_BULK:
-		etrax_usb_complete_bulk_urb(urb, status);
-		break;
-	case PIPE_CONTROL:
-		etrax_usb_complete_ctrl_urb(urb, status);
-		break;
-	case PIPE_INTERRUPT:
-		etrax_usb_complete_intr_urb(urb, status);
-		break;
-	case PIPE_ISOCHRONOUS:
-		etrax_usb_complete_isoc_urb(urb, status);
-		break;
-	default:
-		err("Unknown pipetype");
-	}
-}
-
-
-
-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs)
-{
-	usb_interrupt_registers_t *reg;
-	unsigned long flags;
-	__u32 irq_mask;
-	__u8 status;
-	__u32 epid_attn;
-	__u16 port_status_1;
-	__u16 port_status_2;
-	__u32 fm_number;
-
-	DBFENTER;
-
-	/* Read critical registers into local variables, do kmalloc afterwards. */
-	save_flags(flags);
-	cli();
-
-	irq_mask = *R_USB_IRQ_MASK_READ;
-	/* Reading R_USB_STATUS clears the ctl_status interrupt. Note that R_USB_STATUS
-	   must be read before R_USB_EPID_ATTN since reading the latter clears the
-	   ourun and perror fields of R_USB_STATUS. */
-	status = *R_USB_STATUS;
-
-	/* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn interrupts. */
-	epid_attn = *R_USB_EPID_ATTN;
-
-	/* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
-	   port_status interrupt. */
-	port_status_1 = *R_USB_RH_PORT_STATUS_1;
-	port_status_2 = *R_USB_RH_PORT_STATUS_2;
-
-	/* Reading R_USB_FM_NUMBER clears the sof interrupt. */
-	/* Note: the lower 11 bits contain the actual frame number, sent with each sof. */
-	fm_number = *R_USB_FM_NUMBER;
-
-	restore_flags(flags);
-
-	reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, SLAB_ATOMIC);
-
-	assert(reg != NULL);
-
-	reg->hc = (etrax_hc_t *)vhc;
-
-	/* Now put register values into kmalloc'd area. */
-	reg->r_usb_irq_mask_read = irq_mask;
-	reg->r_usb_status = status;
-	reg->r_usb_epid_attn = epid_attn;
-	reg->r_usb_rh_port_status_1 = port_status_1;
-	reg->r_usb_rh_port_status_2 = port_status_2;
-	reg->r_usb_fm_number = fm_number;
-
-        INIT_WORK(&reg->usb_bh, etrax_usb_hc_interrupt_bottom_half, reg);
-        schedule_work(&reg->usb_bh);
-
-	DBFEXIT;
-
-        return IRQ_HANDLED;
-}
-
-static void etrax_usb_hc_interrupt_bottom_half(void *data)
-{
-	usb_interrupt_registers_t *reg = (usb_interrupt_registers_t *)data;
-	__u32 irq_mask = reg->r_usb_irq_mask_read;
-
-	DBFENTER;
-
-	/* Interrupts are handled in order of priority. */
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
-		etrax_usb_hc_epid_attn_interrupt(reg);
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
-		etrax_usb_hc_port_status_interrupt(reg);
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
-		etrax_usb_hc_ctl_status_interrupt(reg);
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
-		etrax_usb_hc_isoc_eof_interrupt();
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
-		/* Update/restart the bulk start timer since obviously the channel is running. */
-		mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
-		/* Update/restart the bulk eot timer since we just received an bulk eot interrupt. */
-		mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
-
-		etrax_usb_hc_bulk_eot_interrupt(0);
-	}
-
-	kmem_cache_free(top_half_reg_cache, reg);
-
-	DBFEXIT;
-}
-
-
-void etrax_usb_hc_isoc_eof_interrupt(void)
-{
-	struct urb *urb;
-	etrax_urb_priv_t *urb_priv;
-	int epid;
-	unsigned long flags;
-
-	DBFENTER;
-
-	/* Do not check the invalid epid (it has a valid sub pointer). */
-	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-
-		/* Do not check the invalid epid (it has a valid sub pointer). */
-		if ((epid == DUMMY_EPID) || (epid == INVALID_EPID))
-			continue;
-
-		/* Disable interrupts to block the isoc out descriptor interrupt handler
-		   from being called while the isoc EPID list is being checked.
-		*/
-		save_flags(flags);
-		cli();
-
-		if (TxIsocEPList[epid].sub == 0) {
-			/* Nothing here to see. */
-			restore_flags(flags);
-			continue;
-		}
-
-		/* Get the first urb (if any). */
-		urb = urb_list_first(epid);
-		if (urb == 0) {
-			warn("Ignoring NULL urb");
-			restore_flags(flags);
-			continue;
-		}
-		if (usb_pipein(urb->pipe)) {
-
-			/* Sanity check. */
-			assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
-
-			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-			assert(urb_priv);
-
-			if (urb_priv->urb_state == NOT_STARTED) {
-
-				/* If ASAP is not set and urb->start_frame is the current frame,
-				   start the transfer. */
-				if (!(urb->transfer_flags & URB_ISO_ASAP) &&
-				    (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
-
-					dbg_isoc("Enabling isoc IN EP descr for epid %d", epid);
-					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-
-					/* This urb is now active. */
-					urb_priv->urb_state = STARTED;
-					continue;
-				}
-			}
-		}
-		restore_flags(flags);
-	}
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_hc_bulk_eot_interrupt(int timer_induced)
-{
- 	int epid;
-
-	/* The technique is to run one urb at a time, wait for the eot interrupt at which
-	   point the EP descriptor has been disabled. */
-
-	DBFENTER;
-	dbg_bulk("bulk eot%s", timer_induced ? ", called by timer" : "");
-
-	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
-
-		if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
-		    (TxBulkEPList[epid].sub != 0)) {
-
-			struct urb *urb;
-			etrax_urb_priv_t *urb_priv;
-			unsigned long flags;
-			__u32 r_usb_ept_data;
-
-			/* Found a disabled EP descriptor which has a non-null sub pointer.
-			   Verify that this ctrl EP descriptor got disabled no errors.
-			   FIXME: Necessary to check error_code? */
-			dbg_bulk("for epid %d?", epid);
-
-			/* Get the first urb. */
-			urb = urb_list_first(epid);
-
-			/* FIXME: Could this happen for valid reasons? Why did it disappear? Because of
-			   wrong unlinking? */
-			if (!urb) {
-				warn("NULL urb for epid %d", epid);
-				continue;
-			}
-
-			assert(urb);
-			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-			assert(urb_priv);
-
-			/* Sanity checks. */
-			assert(usb_pipetype(urb->pipe) == PIPE_BULK);
-			if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
-				err("bulk endpoint got disabled before reaching last sb");
-			}
-
-			/* For bulk IN traffic, there seems to be a race condition between
-			   between the bulk eot and eop interrupts, or rather an uncertainty regarding
-			   the order in which they happen. Normally we expect the eop interrupt from
-			   DMA channel 9 to happen before the eot interrupt.
-
-			   Therefore, we complete the bulk IN urb in the rx interrupt handler instead. */
-
-			if (usb_pipein(urb->pipe)) {
-				dbg_bulk("in urb, continuing");
-				continue;
-			}
-
-			save_flags(flags);
-			cli();
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-			nop();
-			r_usb_ept_data = *R_USB_EPT_DATA;
-			restore_flags(flags);
-
-			if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
-			    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
-				/* This means that the endpoint has no error, is disabled
-				   and had inserted traffic, i.e. transfer successfully completed. */
-				etrax_usb_complete_bulk_urb(urb, 0);
-			} else {
-				/* Shouldn't happen. We expect errors to be caught by epid attention. */
-				err("Found disabled bulk EP desc, error_code != no_error");
-			}
-		}
-	}
-
-	/* Normally, we should find (at least) one disabled EP descriptor with a valid sub pointer.
-	   However, because of the uncertainty in the deliverance of the eop/eot interrupts, we may
-	   not.  Also, we might find two disabled EPs when handling an eot interrupt, and then find
-	   none the next time. */
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg)
-{
-	/* This function handles the epid attention interrupt.  There are a variety of reasons
-	   for this interrupt to happen (Designer's Reference, p. 8 - 22 for the details):
-
-	   invalid ep_id  - Invalid epid in an EP (EP disabled).
-	   stall	  - Not strictly an error condition (EP disabled).
-	   3rd error      - Three successive transaction errors  (EP disabled).
-	   buffer ourun   - Buffer overrun or underrun (EP disabled).
-	   past eof1      - Intr or isoc transaction proceeds past EOF1.
-	   near eof       - Intr or isoc transaction would not fit inside the frame.
-	   zout transfer  - If zout transfer for a bulk endpoint (EP disabled).
-	   setup transfer - If setup transfer for a non-ctrl endpoint (EP disabled). */
-
-	int epid;
-
-
-	DBFENTER;
-
-	assert(reg != NULL);
-
-	/* Note that we loop through all epids. We still want to catch errors for
-	   the invalid one, even though we might handle them differently. */
-	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
-
-		if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
-
-			struct urb *urb;
-			__u32 r_usb_ept_data;
-			unsigned long flags;
-			int error_code;
-
-			save_flags(flags);
-			cli();
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-			nop();
-			/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
-			   registers, they are located at the same address and are of the same size.
-			   In other words, this read should be ok for isoc also. */
-			r_usb_ept_data = *R_USB_EPT_DATA;
-			restore_flags(flags);
-
-			/* First some sanity checks. */
-			if (epid == INVALID_EPID) {
-				/* FIXME: What if it became disabled? Could seriously hurt interrupt
-				   traffic. (Use do_intr_recover.) */
-				warn("Got epid_attn for INVALID_EPID (%d).", epid);
-				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
-				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
-				continue;
-			} else 	if (epid == DUMMY_EPID) {
-				/* We definitely don't care about these ones. Besides, they are
-				   always disabled, so any possible disabling caused by the
-				   epid attention interrupt is irrelevant. */
-				warn("Got epid_attn for DUMMY_EPID (%d).", epid);
-				continue;
-			}
-
-			/* Get the first urb in the urb list for this epid. We blatantly assume
-			   that only the first urb could have caused the epid attention.
-			   (For bulk and ctrl, only one urb is active at any one time. For intr
-			   and isoc we remove them once they are completed.) */
-			urb = urb_list_first(epid);
-
-			if (urb == NULL) {
-				err("Got epid_attn for epid %i with no urb.", epid);
-				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
-				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
-				continue;
-			}
-
-			switch (usb_pipetype(urb->pipe)) {
-			case PIPE_BULK:
-				warn("Got epid attn for bulk endpoint, epid %d", epid);
-				break;
-			case PIPE_CONTROL:
-				warn("Got epid attn for control endpoint, epid %d", epid);
-				break;
-			case PIPE_INTERRUPT:
-				warn("Got epid attn for interrupt endpoint, epid %d", epid);
-				break;
-			case PIPE_ISOCHRONOUS:
-				warn("Got epid attn for isochronous endpoint, epid %d", epid);
-				break;
-			}
-
-			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
-				if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
-					warn("Hold was set for epid %d.", epid);
-					continue;
-				}
-			}
-
-			/* Even though error_code occupies bits 22 - 23 in both R_USB_EPT_DATA and
-			   R_USB_EPT_DATA_ISOC, we separate them here so we don't forget in other places. */
-			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-				error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
-			} else {
-				error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data);
-			}
-
-			/* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
-			if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
-
-				/* Isoc traffic doesn't have error_count_in/error_count_out. */
-				if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3 ||
-				     IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3)) {
-					/* 3rd error. */
-					warn("3rd error for epid %i", epid);
-					etrax_usb_complete_urb(urb, -EPROTO);
-
-				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
-
-					warn("Perror for epid %d", epid);
-
-					if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
-						/* invalid ep_id */
-						panic("Perror because of invalid epid."
-						      " Deconfigured too early?");
-					} else {
-						/* past eof1, near eof, zout transfer, setup transfer */
-
-						/* Dump the urb and the relevant EP descriptor list. */
-
-						__dump_urb(urb);
-						__dump_ept_data(epid);
-						__dump_ep_list(usb_pipetype(urb->pipe));
-
-						panic("Something wrong with DMA descriptor contents."
-						      " Too much traffic inserted?");
-					}
-				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
-					/* buffer ourun */
-					panic("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
-				}
-
-			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) {
-				/* Not really a protocol error, just says that the endpoint gave
-				   a stall response. Note that error_code cannot be stall for isoc. */
-				if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-					panic("Isoc traffic cannot stall");
-				}
-
-				warn("Stall for epid %d", epid);
-				etrax_usb_complete_urb(urb, -EPIPE);
-
-			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) {
-				/* Two devices responded to a transaction request. Must be resolved
-				   by software. FIXME: Reset ports? */
-				panic("Bus error for epid %d."
-				      " Two devices responded to transaction request",
-				      epid);
-
-			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
-				/* DMA overrun or underrun. */
-				warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
-
-				/* It seems that error_code = buffer_error in
-				   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
-				   are the same error. */
-				etrax_usb_complete_urb(urb, -EPROTO);
-			}
-		}
-	}
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_bulk_start_timer_func(unsigned long dummy)
-{
-
-	/* We might enable an EP descriptor behind the current DMA position when it's about
-	   to decide that there are no more bulk traffic and it should stop the bulk channel.
-	   Therefore we periodically check if the bulk channel is stopped and there is an
-	   enabled bulk EP descriptor, in which case we start the bulk channel. */
-	dbg_bulk("bulk_start_timer timed out.");
-
-	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
-		int epid;
-
-		dbg_bulk("Bulk DMA channel not running.");
-
-		for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
-			if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-				dbg_bulk("Found enabled EP for epid %d, starting bulk channel.\n",
-					 epid);
-				*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
-
-				/* Restart the bulk eot timer since we just started the bulk channel. */
-				mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
-
-				/* No need to search any further. */
-				break;
-			}
-		}
-	} else {
-		dbg_bulk("Bulk DMA channel running.");
-	}
-}
-
-void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg)
-{
-	etrax_hc_t *hc = reg->hc;
-	__u16 r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1;
-	__u16 r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2;
-
-	DBFENTER;
-
-	/* The Etrax RH does not include a wPortChange register, so this has to be handled in software
-	   (by saving the old port status value for comparison when the port status interrupt happens).
-	   See section 11.16.2.6.2 in the USB 1.1 spec for details. */
-
-	dbg_rh("hc->rh.prev_wPortStatus_1 = 0x%x", hc->rh.prev_wPortStatus_1);
-	dbg_rh("hc->rh.prev_wPortStatus_2 = 0x%x", hc->rh.prev_wPortStatus_2);
-	dbg_rh("r_usb_rh_port_status_1 = 0x%x", r_usb_rh_port_status_1);
-	dbg_rh("r_usb_rh_port_status_2 = 0x%x", r_usb_rh_port_status_2);
-
-	/* C_PORT_CONNECTION is set on any transition. */
-	hc->rh.wPortChange_1 |=
-		((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) !=
-		 (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ?
-		(1 << RH_PORT_CONNECTION) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) !=
-		 (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ?
-		(1 << RH_PORT_CONNECTION) : 0;
-
-	/* C_PORT_ENABLE is _only_ set on a one to zero transition, i.e. when
-	   the port is disabled, not when it's enabled. */
-	hc->rh.wPortChange_1 |=
-		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE))
-		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
-		(1 << RH_PORT_ENABLE) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE))
-		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
-		(1 << RH_PORT_ENABLE) : 0;
-
-	/* C_PORT_SUSPEND is set to one when the device has transitioned out
-	   of the suspended state, i.e. when suspend goes from one to zero. */
-	hc->rh.wPortChange_1 |=
-		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_SUSPEND))
-		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_SUSPEND))) ?
-		(1 << RH_PORT_SUSPEND) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_SUSPEND))
-		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_SUSPEND))) ?
-		(1 << RH_PORT_SUSPEND) : 0;
-
-
-	/* C_PORT_RESET is set when reset processing on this port is complete. */
-	hc->rh.wPortChange_1 |=
-		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET))
-		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_RESET))) ?
-		(1 << RH_PORT_RESET) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET))
-		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_RESET))) ?
-		(1 << RH_PORT_RESET) : 0;
-
-	/* Save the new values for next port status change. */
-	hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1;
-	hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2;
-
-	dbg_rh("hc->rh.wPortChange_1 set to 0x%x", hc->rh.wPortChange_1);
-	dbg_rh("hc->rh.wPortChange_2 set to 0x%x", hc->rh.wPortChange_2);
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg)
-{
-	DBFENTER;
-
-	/* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
-	   list for the corresponding epid? */
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
-		panic("USB controller got ourun.");
-	}
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
-
-		/* Before, etrax_usb_do_intr_recover was called on this epid if it was
-		   an interrupt pipe. I don't see how re-enabling all EP descriptors
-		   will help if there was a programming error. */
-		panic("USB controller got perror.");
-	}
-
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
-		/* We should never operate in device mode. */
-		panic("USB controller in device mode.");
-	}
-
-	/* These if-statements could probably be nested. */
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, host_mode)) {
-		info("USB controller in host mode.");
-	}
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, started)) {
-		info("USB controller started.");
-	}
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, running)) {
-		info("USB controller running.");
-	}
-
-	DBFEXIT;
-
-}
-
-
-static int etrax_rh_submit_urb(struct urb *urb)
-{
-	struct usb_device *usb_dev = urb->dev;
-	etrax_hc_t *hc = usb_dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int stat = 0;
-
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	DBFENTER;
-
-	/* FIXME: What is this interrupt urb that is sent to the root hub? */
-	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
-		dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval);
-		hc->rh.urb = urb;
-		hc->rh.send = 1;
-		/* FIXME: We could probably remove this line since it's done
-		   in etrax_rh_init_int_timer. (Don't remove it from
-		   etrax_rh_init_int_timer though.) */
-		hc->rh.interval = urb->interval;
-		etrax_rh_init_int_timer(urb);
-		DBFEXIT;
-
-		return 0;
-	}
-
-	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
-	wValue = le16_to_cpu(cmd->wValue);
-	wIndex = le16_to_cpu(cmd->wIndex);
-	wLength = le16_to_cpu(cmd->wLength);
-
-	dbg_rh("bmRType_bReq : 0x%04x (%d)", bmRType_bReq, bmRType_bReq);
-	dbg_rh("wValue       : 0x%04x (%d)", wValue, wValue);
-	dbg_rh("wIndex       : 0x%04x (%d)", wIndex, wIndex);
-	dbg_rh("wLength      : 0x%04x (%d)", wLength, wLength);
-
-	switch (bmRType_bReq) {
-
-		/* Request Destination:
-		   without flags: Device,
-		   RH_INTERFACE: interface,
-		   RH_ENDPOINT: endpoint,
-		   RH_CLASS means HUB here,
-		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
-		 */
-
-	case RH_GET_STATUS:
-		*(__u16 *) data = cpu_to_le16 (1);
-		OK (2);
-
-	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *) data = cpu_to_le16 (0);
-		OK (2);
-
-	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *) data = cpu_to_le16 (0);
-		OK (2);
-
-	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *) data = cpu_to_le32 (0);
-		OK (4);		/* hub power ** */
-
-	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		if (wIndex == 1) {
-			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
-			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
-		} else if (wIndex == 2) {
-			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
-			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
-		} else {
-			dbg_rh("RH_GET_STATUS whith invalid wIndex!");
-			OK(0);
-		}
-
-		OK(4);
-
-	case RH_CLEAR_FEATURE | RH_ENDPOINT:
-		switch (wValue) {
-		case (RH_ENDPOINT_STALL):
-			OK (0);
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_CLASS:
-		switch (wValue) {
-		case (RH_C_HUB_OVER_CURRENT):
-			OK (0);	/* hub power over current ** */
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_ENABLE):
-			if (wIndex == 1) {
-
-				dbg_rh("trying to do disable port 1");
-
-				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
-
-				while (hc->rh.prev_wPortStatus_1 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes));
-				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
-				dbg_rh("Port 1 is disabled");
-
-			} else if (wIndex == 2) {
-
-				dbg_rh("trying to do disable port 2");
-
-				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
-
-				while (hc->rh.prev_wPortStatus_2 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes));
-				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
-				dbg_rh("Port 2 is disabled");
-
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_PORT_SUSPEND):
-			/* Opposite to suspend should be resume, so we'll do a resume. */
-			/* FIXME: USB 1.1, 11.16.2.2 says:
-			   "Clearing the PORT_SUSPEND feature causes a host-initiated resume
-			   on the specified port. If the port is not in the Suspended state,
-			   the hub should treat this request as a functional no-operation."
-			   Shouldn't we check if the port is in a suspended state before
-			   resuming? */
-
-			/* Make sure the controller isn't busy. */
-			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-			if (wIndex == 1) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port1) |
-					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else if (wIndex == 2) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port2) |
-					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_C_PORT_CONNECTION):
-			if (wIndex == 1) {
-				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
-			} else if (wIndex == 2) {
-				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_C_PORT_ENABLE):
-			if (wIndex == 1) {
-				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE);
-			} else if (wIndex == 2) {
-				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-			OK (0);
-		case (RH_C_PORT_SUSPEND):
-/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-			OK (0);
-		case (RH_C_PORT_OVER_CURRENT):
-			OK (0);	/* port power over current ** */
-		case (RH_C_PORT_RESET):
-			if (wIndex == 1) {
-				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET);
-			} else if (wIndex == 2) {
-				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET "
-				       "with invalid index == %d!", wIndex);
-			}
-
-			OK (0);
-
-		}
-		break;
-
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_SUSPEND):
-
-			/* Make sure the controller isn't busy. */
-			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-			if (wIndex == 1) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port1) |
-					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else if (wIndex == 2) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port2) |
-					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else {
-				dbg_rh("RH_SET_FEATURE->RH_PORT_SUSPEND "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_PORT_RESET):
-			if (wIndex == 1) {
-
-			port_1_reset:
-				dbg_rh("Doing reset of port 1");
-
-				/* Make sure the controller isn't busy. */
-				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port1) |
-					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-
-				/* We must wait at least 10 ms for the device to recover.
-				   15 ms should be enough. */
-				udelay(15000);
-
-				/* Wait for reset bit to go low (should be done by now). */
-				while (hc->rh.prev_wPortStatus_1 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes));
-
-				/* If the port status is
-				   1) connected and enabled then there is a device and everything is fine
-				   2) neither connected nor enabled then there is no device, also fine
-				   3) connected and not enabled then we try again
-				   (Yes, there are other port status combinations besides these.) */
-
-				if ((hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
-				    (hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
-					dbg_rh("Connected device on port 1, but port not enabled?"
-					       " Trying reset again.");
-					goto port_2_reset;
-				}
-
-				/* Diagnostic printouts. */
-				if ((hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, no)) &&
-				    (hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
-					dbg_rh("No connected device on port 1");
-				} else if ((hc->rh.prev_wPortStatus_1 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
-					   (hc->rh.prev_wPortStatus_1 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) {
-					dbg_rh("Connected device on port 1, port 1 enabled");
-				}
-
-			} else if (wIndex == 2) {
-
-			port_2_reset:
-				dbg_rh("Doing reset of port 2");
-
-				/* Make sure the controller isn't busy. */
-				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-				/* Issue the reset command. */
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port2) |
-					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-
-				/* We must wait at least 10 ms for the device to recover.
-				   15 ms should be enough. */
-				udelay(15000);
-
-				/* Wait for reset bit to go low (should be done by now). */
-				while (hc->rh.prev_wPortStatus_2 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_2, reset, yes));
-
-				/* If the port status is
-				   1) connected and enabled then there is a device and everything is fine
-				   2) neither connected nor enabled then there is no device, also fine
-				   3) connected and not enabled then we try again
-				   (Yes, there are other port status combinations besides these.) */
-
-				if ((hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
-				    (hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
-					dbg_rh("Connected device on port 2, but port not enabled?"
-					       " Trying reset again.");
-					goto port_2_reset;
-				}
-
-				/* Diagnostic printouts. */
-				if ((hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, no)) &&
-				    (hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
-					dbg_rh("No connected device on port 2");
-				} else if ((hc->rh.prev_wPortStatus_2 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
-					   (hc->rh.prev_wPortStatus_2 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) {
-					dbg_rh("Connected device on port 2, port 2 enabled");
-				}
-
-			} else {
-				dbg_rh("RH_SET_FEATURE->RH_PORT_RESET with invalid wIndex = %d", wIndex);
-			}
-
-			/* Make sure the controller isn't busy. */
-			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-			/* If all enabled ports were disabled the host controller goes down into
-			   started mode, so we need to bring it back into the running state.
-			   (This is safe even if it's already in the running state.) */
-			*R_USB_COMMAND =
-				IO_STATE(R_USB_COMMAND, port_sel, nop) |
-				IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-				IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
-
-			dbg_rh("...Done");
-			OK(0);
-
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_PORT_ENABLE):
-			/* There is no port enable command in the host controller, so if the
-			   port is already enabled, we do nothing. If not, we reset the port
-			   (with an ugly goto). */
-
-			if (wIndex == 1) {
-				if (hc->rh.prev_wPortStatus_1 &
-				    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no)) {
-					goto port_1_reset;
-				}
-			} else if (wIndex == 2) {
-				if (hc->rh.prev_wPortStatus_2 &
-				    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no)) {
-					goto port_2_reset;
-				}
-			} else {
-				dbg_rh("RH_SET_FEATURE->RH_GET_STATUS with invalid wIndex = %d", wIndex);
-			}
-			OK (0);
-		}
-		break;
-
-	case RH_SET_ADDRESS:
-		hc->rh.devnum = wValue;
-		dbg_rh("RH address set to: %d", hc->rh.devnum);
-		OK (0);
-
-	case RH_GET_DESCRIPTOR:
-		switch ((wValue & 0xff00) >> 8) {
-		case (0x01):	/* device descriptor */
-			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength));
-			memcpy (data, root_hub_dev_des, len);
-			OK (len);
-		case (0x02):	/* configuration descriptor */
-			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength));
-			memcpy (data, root_hub_config_des, len);
-			OK (len);
-		case (0x03):	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff,
-						   0xff, "ETRAX 100LX",
-						   data, wLength);
-			if (len > 0) {
-				OK(min(leni, len));
-			} else {
-				stat = -EPIPE;
-			}
-
-		}
-		break;
-
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = hc->rh.numports;
-		len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
-		memcpy (data, root_hub_hub_des, len);
-		OK (len);
-
-	case RH_GET_CONFIGURATION:
-		*(__u8 *) data = 0x01;
-		OK (1);
-
-	case RH_SET_CONFIGURATION:
-		OK (0);
-
-	default:
-		stat = -EPIPE;
-	}
-
-	urb->actual_length = len;
-	urb->status = stat;
-	urb->dev = NULL;
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-	DBFEXIT;
-
-	return 0;
-}
-
-static void
-etrax_usb_bulk_eot_timer_func(unsigned long dummy)
-{
-	/* Because of a race condition in the top half, we might miss a bulk eot.
-	   This timer "simulates" a bulk eot if we don't get one for a while, hopefully
-	   correcting the situation. */
-	dbg_bulk("bulk_eot_timer timed out.");
-	etrax_usb_hc_bulk_eot_interrupt(1);
-}
-
-static void*
-etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma)
-{
-  return kmalloc(size, mem_flags);
-}
-
-static void
-etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma)
-{
-  kfree(addr);
-}
-
-
-static struct device fake_device;
-
-static int __init etrax_usb_hc_init(void)
-{
-	static etrax_hc_t *hc;
-	struct usb_bus *bus;
-	struct usb_device *usb_rh;
-	int i;
-
-	DBFENTER;
-
-	info("ETRAX 100LX USB-HCD %s (c) 2001-2003 Axis Communications AB\n", usb_hcd_version);
-
- 	hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL);
-	assert(hc != NULL);
-
-	/* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
-	/* Note that we specify sizeof(USB_EP_Desc_t) as the size, but also allocate
-	   SB descriptors from this cache. This is ok since sizeof(USB_EP_Desc_t) ==
-	   sizeof(USB_SB_Desc_t). */
-
-	usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0,
-					   SLAB_HWCACHE_ALIGN, 0, 0);
-	assert(usb_desc_cache != NULL);
-
-	top_half_reg_cache = kmem_cache_create("top_half_reg_cache",
-					       sizeof(usb_interrupt_registers_t),
-					       0, SLAB_HWCACHE_ALIGN, 0, 0);
-	assert(top_half_reg_cache != NULL);
-
-	isoc_compl_cache = kmem_cache_create("isoc_compl_cache",
-						sizeof(usb_isoc_complete_data_t),
-						0, SLAB_HWCACHE_ALIGN, 0, 0);
-	assert(isoc_compl_cache != NULL);
-
-	etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
-	hc->bus = bus;
-	bus->bus_name="ETRAX 100LX";
-	bus->hcpriv = hc;
-
-	/* Initalize RH to the default address.
-	   And make sure that we have no status change indication */
-	hc->rh.numports = 2;  /* The RH has two ports */
-	hc->rh.devnum = 1;
-	hc->rh.wPortChange_1 = 0;
-	hc->rh.wPortChange_2 = 0;
-
-	/* Also initate the previous values to zero */
-	hc->rh.prev_wPortStatus_1 = 0;
-	hc->rh.prev_wPortStatus_2 = 0;
-
-	/* Initialize the intr-traffic flags */
-	/* FIXME: This isn't used. (Besides, the error field isn't initialized.) */
-	hc->intr.sleeping = 0;
-	hc->intr.wq = NULL;
-
-	epid_usage_bitmask = 0;
-	epid_out_traffic = 0;
-
-	/* Mark the invalid epid as being used. */
-	set_bit(INVALID_EPID, (void *)&epid_usage_bitmask);
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, INVALID_EPID);
-	nop();
-	/* The valid bit should still be set ('invalid' is in our world; not the hardware's). */
-	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, yes) |
-			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
-
-	/* Mark the dummy epid as being used. */
-	set_bit(DUMMY_EPID, (void *)&epid_usage_bitmask);
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, DUMMY_EPID);
-	nop();
-	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, no) |
-			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
-
-	/* Initialize the urb list by initiating a head for each list. */
-	for (i = 0; i < NBR_OF_EPIDS; i++) {
-		INIT_LIST_HEAD(&urb_list[i]);
-	}
-	spin_lock_init(&urb_list_lock);
-
-	INIT_LIST_HEAD(&urb_unlink_list);
-
-
-	/* Initiate the bulk start timer. */
-	init_timer(&bulk_start_timer);
-	bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
-	bulk_start_timer.function = etrax_usb_bulk_start_timer_func;
-	add_timer(&bulk_start_timer);
-
-
-	/* Initiate the bulk eot timer. */
-	init_timer(&bulk_eot_timer);
-	bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
-	bulk_eot_timer.function = etrax_usb_bulk_eot_timer_func;
-	add_timer(&bulk_eot_timer);
-
-	/* Set up the data structures for USB traffic. Note that this must be done before
-	   any interrupt that relies on sane DMA list occurrs. */
-	init_rx_buffers();
-	init_tx_bulk_ep();
-	init_tx_ctrl_ep();
-	init_tx_intr_ep();
-	init_tx_isoc_ep();
-
-        device_initialize(&fake_device);
-        kobject_set_name(&fake_device.kobj, "etrax_usb");
-        kobject_add(&fake_device.kobj);
-        hc->bus->controller = &fake_device;
-	usb_register_bus(hc->bus);
-
-	*R_IRQ_MASK2_SET =
-		/* Note that these interrupts are not used. */
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
-		/* Sub channel 1 (ctrl) descr. interrupts are used. */
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
-		/* Sub channel 3 (isoc) descr. interrupts are used. */
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
-
-	/* Note that the dma9_descr interrupt is not used. */
-	*R_IRQ_MASK2_SET =
-		IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
-		IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
-
-	/* FIXME: Enable iso_eof only when isoc traffic is running. */
-	*R_USB_IRQ_MASK_SET =
-		IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
-
-
-	if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_interrupt_top_half, 0,
-			"ETRAX 100LX built-in USB (HC)", hc)) {
-		err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
-		etrax_usb_hc_cleanup();
-		DBFEXIT;
-		return -1;
-	}
-
-	if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0,
-			"ETRAX 100LX built-in USB (Rx)", hc)) {
-		err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
-		etrax_usb_hc_cleanup();
-		DBFEXIT;
-		return -1;
-	}
-
-	if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0,
-			"ETRAX 100LX built-in USB (Tx)", hc)) {
-		err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
-		etrax_usb_hc_cleanup();
-		DBFEXIT;
-		return -1;
-	}
-
-	/* R_USB_COMMAND:
-	   USB commands in host mode. The fields in this register should all be
-	   written to in one write. Do not read-modify-write one field at a time. A
-	   write to this register will trigger events in the USB controller and an
-	   incomplete command may lead to unpredictable results, and in worst case
-	   even to a deadlock in the controller.
-	   (Note however that the busy field is read-only, so no need to write to it.) */
-
-	/* Check the busy bit before writing to R_USB_COMMAND. */
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	/* Reset the USB interface. */
-	*R_USB_COMMAND =
-		IO_STATE(R_USB_COMMAND, port_sel, nop) |
-		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-		IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
-
-	/* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to 0x2A30 (10800),
-	   to guarantee that control traffic gets 10% of the bandwidth, and periodic transfer may
-	   allocate the rest (90%). This doesn't work though. Read on for a lenghty explanation.
-
-	   While there is a difference between rev. 2 and rev. 3 of the ETRAX 100LX regarding the NAK
-	   behaviour, it doesn't solve this problem. What happens is that a control transfer will not
-	   be interrupted in its data stage when PSTART happens (the point at which periodic traffic
-	   is started). Thus, if PSTART is set to 10800 and its IN or OUT token is NAKed until just before
-	   PSTART happens, it will continue the IN/OUT transfer as long as it's ACKed. After it's done,
-	   there may be too little time left for an isochronous transfer, causing an epid attention
-	   interrupt due to perror. The work-around for this is to let the control transfers run at the
-	   end of the frame instead of at the beginning, and will be interrupted just fine if it doesn't
-	   fit into the frame. However, since there will *always* be a control transfer at the beginning
-	   of the frame, regardless of what we set PSTART to, that transfer might be a 64-byte transfer
-	   which consumes up to 15% of the frame, leaving only 85% for periodic traffic. The solution to
-	   this would be to 'dummy allocate' 5% of the frame with the usb_claim_bandwidth function to make
-	   sure that the periodic transfers that are inserted will always fit in the frame.
-
-	   The idea was suggested that a control transfer could be split up into several 8 byte transfers,
-	   so that it would be interrupted by PSTART, but since this can't be done for an IN transfer this
-	   hasn't been implemented.
-
-	   The value 11960 is chosen to be just after the SOF token, with a couple of bit times extra
-	   for possible bit stuffing. */
-
-	*R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
-
-#ifdef CONFIG_ETRAX_USB_HOST_PORT1
-	*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
-#endif
-
-#ifdef CONFIG_ETRAX_USB_HOST_PORT2
-	*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
-#endif
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	/* Configure the USB interface as a host controller. */
-	*R_USB_COMMAND =
-		IO_STATE(R_USB_COMMAND, port_sel, nop) |
-		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
-
-	/* Note: Do not reset any ports here. Await the port status interrupts, to have a controlled
-	   sequence of resetting the ports. If we reset both ports now, and there are devices
-	   on both ports, we will get a bus error because both devices will answer the set address
-	   request. */
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	/* Start processing of USB traffic. */
-	*R_USB_COMMAND =
-		IO_STATE(R_USB_COMMAND, port_sel, nop) |
-		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	usb_rh = usb_alloc_dev(NULL, hc->bus, 0);
-	hc->bus->root_hub = usb_rh;
-        usb_rh->state = USB_STATE_ADDRESS;
-        usb_rh->speed = USB_SPEED_FULL;
-        usb_rh->devnum = 1;
-        hc->bus->devnum_next = 2;
-        usb_rh->epmaxpacketin[0] = usb_rh->epmaxpacketout[0] = 64;
-        usb_get_device_descriptor(usb_rh, USB_DT_DEVICE_SIZE);
-	usb_new_device(usb_rh);
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_hc_cleanup(void)
-{
-	DBFENTER;
-
-	free_irq(ETRAX_USB_HC_IRQ, NULL);
-	free_irq(ETRAX_USB_RX_IRQ, NULL);
-	free_irq(ETRAX_USB_TX_IRQ, NULL);
-
-	usb_deregister_bus(etrax_usb_bus);
-
-	/* FIXME: call kmem_cache_destroy here? */
-
-	DBFEXIT;
-}
-
-module_init(etrax_usb_hc_init);
-module_exit(etrax_usb_hc_cleanup);
diff -L arch/cris/arch-v10/drivers/usb-host.h -puN arch/cris/arch-v10/drivers/usb-host.h~cris-architecture-update-move-drivers /dev/null
--- 25/arch/cris/arch-v10/drivers/usb-host.h
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,289 +0,0 @@
-#ifndef __LINUX_ETRAX_USB_H
-#define __LINUX_ETRAX_USB_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-
-typedef struct USB_IN_Desc {
-	volatile __u16 sw_len;
-	volatile __u16 command;
-	volatile unsigned long next;
-	volatile unsigned long buf;
-	volatile __u16 hw_len;
-	volatile __u16 status;
-} USB_IN_Desc_t;
-
-typedef struct USB_SB_Desc {
-	volatile __u16 sw_len;
-	volatile __u16 command;
-	volatile unsigned long next;
-	volatile unsigned long buf;
-	__u32 dummy;
-} USB_SB_Desc_t;
-
-typedef struct USB_EP_Desc {
-	volatile __u16 hw_len;
-	volatile __u16 command;
-	volatile unsigned long sub;
-	volatile unsigned long next;
-	__u32 dummy;
-} USB_EP_Desc_t;
-
-struct virt_root_hub {
-	int devnum;
-	void *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	struct timer_list rh_int_timer;
-	volatile __u16 wPortChange_1;
-	volatile __u16 wPortChange_2;
-	volatile __u16 prev_wPortStatus_1;
-	volatile __u16 prev_wPortStatus_2;
-};
-
-struct etrax_usb_intr_traffic {
-	int sleeping;
-	int error;
-	struct wait_queue *wq;
-};
-
-typedef struct etrax_usb_hc {
-	struct usb_bus *bus;
-	struct virt_root_hub rh;
-	struct etrax_usb_intr_traffic intr;
-} etrax_hc_t;
-
-typedef enum {
-	STARTED,
-	NOT_STARTED,
-	UNLINK,
-	TRANSFER_DONE,
-	WAITING_FOR_DESCR_INTR
-} etrax_usb_urb_state_t;
-
-
-
-typedef struct etrax_usb_urb_priv {
-	/* The first_sb field is used for freeing all SB descriptors belonging
-	   to an urb. The corresponding ep descriptor's sub pointer cannot be
-	   used for this since the DMA advances the sub pointer as it processes
-	   the sb list. */
-	USB_SB_Desc_t *first_sb;
-	/* The last_sb field referes to the last SB descriptor that belongs to
-	   this urb. This is important to know so we can free the SB descriptors
-	   that ranges between first_sb and last_sb. */
-	USB_SB_Desc_t *last_sb;
-
-	/* The rx_offset field is used in ctrl and bulk traffic to keep track
-	   of the offset in the urb's transfer_buffer where incoming data should be
-	   copied to. */
-	__u32 rx_offset;
-
-	/* Counter used in isochronous transfers to keep track of the
-	   number of packets received/transmitted.  */
-	__u32 isoc_packet_counter;
-
-	/* This field is used to pass information about the urb's current state between
-	   the various interrupt handlers (thus marked volatile). */
-	volatile etrax_usb_urb_state_t urb_state;
-
-	/* Connection between the submitted urb and ETRAX epid number */
-	__u8 epid;
-
-	/* The rx_data_list field is used for periodic traffic, to hold
-	   received data for later processing in the the complete_urb functions,
-	   where the data us copied to the urb's transfer_buffer. Basically, we
-	   use this intermediate storage because we don't know when it's safe to
-	   reuse the transfer_buffer (FIXME?). */
-	struct list_head rx_data_list;
-} etrax_urb_priv_t;
-
-/* This struct is for passing data from the top half to the bottom half. */
-typedef struct usb_interrupt_registers
-{
-	etrax_hc_t *hc;
-	__u32 r_usb_epid_attn;
-	__u8 r_usb_status;
-	__u16 r_usb_rh_port_status_1;
-	__u16 r_usb_rh_port_status_2;
-	__u32 r_usb_irq_mask_read;
-	__u32 r_usb_fm_number;
-	struct work_struct usb_bh;
-} usb_interrupt_registers_t;
-
-/* This struct is for passing data from the isoc top half to the isoc bottom half. */
-typedef struct usb_isoc_complete_data
-{
-	struct urb *urb;
-	struct work_struct usb_bh;
-} usb_isoc_complete_data_t;
-
-/* This struct holds data we get from the rx descriptors for DMA channel 9
-   for periodic traffic (intr and isoc). */
-typedef struct rx_data
-{
-	void *data;
-	int length;
-	struct list_head list;
-} rx_data_t;
-
-typedef struct urb_entry
-{
-	struct urb *urb;
-	struct list_head list;
-} urb_entry_t;
-
-/* ---------------------------------------------------------------------------
-   Virtual Root HUB
-   ------------------------------------------------------------------------- */
-/* 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
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP               0x00
-
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
-
-/* Field definitions for */
-
-#define USB_IN_command__eol__BITNR      0 /* command macros */
-#define USB_IN_command__eol__WIDTH      1
-#define USB_IN_command__eol__no         0
-#define USB_IN_command__eol__yes        1
-
-#define USB_IN_command__intr__BITNR     3
-#define USB_IN_command__intr__WIDTH     1
-#define USB_IN_command__intr__no        0
-#define USB_IN_command__intr__yes       1
-
-#define USB_IN_status__eop__BITNR       1 /* status macros. */
-#define USB_IN_status__eop__WIDTH       1
-#define USB_IN_status__eop__no          0
-#define USB_IN_status__eop__yes         1
-
-#define USB_IN_status__eot__BITNR       5
-#define USB_IN_status__eot__WIDTH       1
-#define USB_IN_status__eot__no          0
-#define USB_IN_status__eot__yes         1
-
-#define USB_IN_status__error__BITNR     6
-#define USB_IN_status__error__WIDTH     1
-#define USB_IN_status__error__no        0
-#define USB_IN_status__error__yes       1
-
-#define USB_IN_status__nodata__BITNR    7
-#define USB_IN_status__nodata__WIDTH    1
-#define USB_IN_status__nodata__no       0
-#define USB_IN_status__nodata__yes      1
-
-#define USB_IN_status__epid__BITNR      8
-#define USB_IN_status__epid__WIDTH      5
-
-#define USB_EP_command__eol__BITNR      0
-#define USB_EP_command__eol__WIDTH      1
-#define USB_EP_command__eol__no         0
-#define USB_EP_command__eol__yes        1
-
-#define USB_EP_command__eof__BITNR      1
-#define USB_EP_command__eof__WIDTH      1
-#define USB_EP_command__eof__no         0
-#define USB_EP_command__eof__yes        1
-
-#define USB_EP_command__intr__BITNR     3
-#define USB_EP_command__intr__WIDTH     1
-#define USB_EP_command__intr__no        0
-#define USB_EP_command__intr__yes       1
-
-#define USB_EP_command__enable__BITNR   4
-#define USB_EP_command__enable__WIDTH   1
-#define USB_EP_command__enable__no      0
-#define USB_EP_command__enable__yes     1
-
-#define USB_EP_command__hw_valid__BITNR 5
-#define USB_EP_command__hw_valid__WIDTH 1
-#define USB_EP_command__hw_valid__no    0
-#define USB_EP_command__hw_valid__yes   1
-
-#define USB_EP_command__epid__BITNR     8
-#define USB_EP_command__epid__WIDTH     5
-
-#define USB_SB_command__eol__BITNR      0 /* command macros. */
-#define USB_SB_command__eol__WIDTH      1
-#define USB_SB_command__eol__no         0
-#define USB_SB_command__eol__yes        1
-
-#define USB_SB_command__eot__BITNR      1
-#define USB_SB_command__eot__WIDTH      1
-#define USB_SB_command__eot__no         0
-#define USB_SB_command__eot__yes        1
-
-#define USB_SB_command__intr__BITNR     3
-#define USB_SB_command__intr__WIDTH     1
-#define USB_SB_command__intr__no        0
-#define USB_SB_command__intr__yes       1
-
-#define USB_SB_command__tt__BITNR       4
-#define USB_SB_command__tt__WIDTH       2
-#define USB_SB_command__tt__zout        0
-#define USB_SB_command__tt__in          1
-#define USB_SB_command__tt__out         2
-#define USB_SB_command__tt__setup       3
-
-
-#define USB_SB_command__rem__BITNR      8
-#define USB_SB_command__rem__WIDTH      6
-
-#define USB_SB_command__full__BITNR     6
-#define USB_SB_command__full__WIDTH     1
-#define USB_SB_command__full__no        0
-#define USB_SB_command__full__yes       1
-
-#endif
diff -puN /dev/null drivers/ide/cris/ide-v10.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/ide/cris/ide-v10.c	Mon Nov  8 14:19:37 2004
@@ -0,0 +1,940 @@
+/* $Id: ide.c,v 1.4 2004/10/12 07:55:48 starvik Exp $
+ *
+ * Etrax specific IDE functions, like init and PIO-mode setting etc.
+ * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
+ * Copyright (c) 2000-2004 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen        (initial version)
+ *             Mikael Starvik     (pio setup stuff, Linux 2.6 port)
+ */
+
+/* Regarding DMA:
+ *
+ * There are two forms of DMA - "DMA handshaking" between the interface and the drive,
+ * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
+ * something built-in in the Etrax. However only some drives support the DMA-mode handshaking
+ * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
+ * device can't do DMA handshaking for some stupid reason. We don't need to do that.
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+#include <asm/dma.h>
+
+/* number of Etrax DMA descriptors */
+#define MAX_DMA_DESCRS 64
+
+/* number of times to retry busy-flags when reading/writing IDE-registers
+ * this can't be too high because a hung harddisk might cause the watchdog
+ * to trigger (sometimes INB and OUTB are called with irq's disabled)
+ */
+
+#define IDE_REGISTER_TIMEOUT 300
+
+static int e100_read_command = 0;
+
+#define LOWDB(x)
+#define D(x)
+
+void
+etrax100_ide_outw(unsigned short data, unsigned long reg) {
+	int timeleft;
+	LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
+
+	/* note the lack of handling any timeouts. we stop waiting, but we don't
+	 * really notify anybody.
+	 */
+
+	timeleft = IDE_REGISTER_TIMEOUT;
+	/* wait for busy flag */
+	while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+		timeleft--;
+
+	/*
+	 * Fall through at a timeout, so the ongoing command will be
+	 * aborted by the write below, which is expected to be a dummy
+	 * command to the command register.  This happens when a faulty
+	 * drive times out on a command.  See comment on timeout in
+	 * INB.
+	 */
+	if(!timeleft)
+		printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
+
+	*R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
+
+	timeleft = IDE_REGISTER_TIMEOUT;
+	/* wait for transmitter ready */
+	while(timeleft && !(*R_ATA_STATUS_DATA &
+			    IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
+		timeleft--;
+}
+
+void
+etrax100_ide_outb(unsigned char data, unsigned long reg)
+{
+	etrax100_ide_outw(data, reg);
+}
+
+void
+etrax100_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
+{
+	etrax100_ide_outw(addr, port);
+}
+
+unsigned short
+etrax100_ide_inw(unsigned long reg) {
+	int status;
+	int timeleft;
+
+	timeleft = IDE_REGISTER_TIMEOUT;
+	/* wait for busy flag */
+	while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+		timeleft--;
+
+	if(!timeleft) {
+		/*
+		 * If we're asked to read the status register, like for
+		 * example when a command does not complete for an
+		 * extended time, but the ATA interface is stuck in a
+		 * busy state at the *ETRAX* ATA interface level (as has
+		 * happened repeatedly with at least one bad disk), then
+		 * the best thing to do is to pretend that we read
+		 * "busy" in the status register, so the IDE driver will
+		 * time-out, abort the ongoing command and perform a
+		 * reset sequence.  Note that the subsequent OUT_BYTE
+		 * call will also timeout on busy, but as long as the
+		 * write is still performed, everything will be fine.
+		 */
+		if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr))
+		    == IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET))
+			return BUSY_STAT;
+		else
+			/* For other rare cases we assume 0 is good enough.  */
+			return 0;
+	}
+
+	*R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
+
+	timeleft = IDE_REGISTER_TIMEOUT;
+	/* wait for available */
+	while(timeleft && !((status = *R_ATA_STATUS_DATA) &
+			    IO_MASK(R_ATA_STATUS_DATA, dav)))
+		timeleft--;
+
+	if(!timeleft)
+		return 0;
+
+	LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
+
+        return (unsigned short)status;
+}
+
+unsigned char
+etrax100_ide_inb(unsigned long reg)
+{
+	return (unsigned char)etrax100_ide_inw(reg);
+}
+
+/* PIO timing (in R_ATA_CONFIG)
+ *
+ *                        _____________________________
+ * ADDRESS :     ________/
+ *
+ *                            _______________
+ * DIOR    :     ____________/               \__________
+ *
+ *                               _______________
+ * DATA    :     XXXXXXXXXXXXXXXX_______________XXXXXXXX
+ *
+ *
+ * DIOR is unbuffered while address and data is buffered.
+ * This creates two problems:
+ * 1. The DIOR pulse is to early (because it is unbuffered)
+ * 2. The rise time of DIOR is long
+ *
+ * There are at least three different plausible solutions
+ * 1. Use a pad capable of larger currents in Etrax
+ * 2. Use an external buffer
+ * 3. Make the strobe pulse longer
+ *
+ * Some of the strobe timings below are modified to compensate
+ * for this. This implies a slight performance decrease.
+ *
+ * THIS SHOULD NEVER BE CHANGED!
+ *
+ * TODO: Is this true for the latest LX boards still ?
+ */
+
+#define ATA_DMA2_STROBE  4
+#define ATA_DMA2_HOLD    0
+#define ATA_DMA1_STROBE  4
+#define ATA_DMA1_HOLD    1
+#define ATA_DMA0_STROBE 12
+#define ATA_DMA0_HOLD    9
+#define ATA_PIO4_SETUP   1
+#define ATA_PIO4_STROBE  5
+#define ATA_PIO4_HOLD    0
+#define ATA_PIO3_SETUP   1
+#define ATA_PIO3_STROBE  5
+#define ATA_PIO3_HOLD    1
+#define ATA_PIO2_SETUP   1
+#define ATA_PIO2_STROBE  6
+#define ATA_PIO2_HOLD    2
+#define ATA_PIO1_SETUP   2
+#define ATA_PIO1_STROBE 11
+#define ATA_PIO1_HOLD    4
+#define ATA_PIO0_SETUP   4
+#define ATA_PIO0_STROBE 19
+#define ATA_PIO0_HOLD    4
+
+static int e100_dma_check (ide_drive_t *drive);
+static int e100_dma_begin (ide_drive_t *drive);
+static int e100_dma_end (ide_drive_t *drive);
+static int e100_dma_read (ide_drive_t *drive);
+static int e100_dma_write (ide_drive_t *drive);
+static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int);
+static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int);
+static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
+static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
+static int e100_dma_off (ide_drive_t *drive);
+static int e100_dma_verbose (ide_drive_t *drive);
+
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mword2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+
+const char *good_dma_drives[] = {"Micropolis 2112A",
+				 "CONNER CTMA 4000",
+				 "CONNER CTT8000-A",
+				 NULL};
+
+static void tune_e100_ide(ide_drive_t *drive, byte pio)
+{
+	pio = 4;
+	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
+
+	/* set pio mode! */
+
+	switch(pio) {
+		case 0:
+			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO0_SETUP ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO0_HOLD ) );
+			break;
+		case 1:
+			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO1_SETUP ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO1_HOLD ) );
+			break;
+		case 2:
+			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO2_SETUP ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO2_HOLD ) );
+			break;
+		case 3:
+			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO3_SETUP ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO3_HOLD ) );
+			break;
+		case 4:
+			*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO4_SETUP ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
+			break;
+	}
+}
+
+void __init
+init_e100_ide (void)
+{
+	volatile unsigned int dummy;
+	int h;
+
+	printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
+
+	/* first fill in some stuff in the ide_hwifs fields */
+
+	for(h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		hwif->mmio = 2;
+		hwif->chipset = ide_etrax100;
+		hwif->tuneproc = &tune_e100_ide;
+                hwif->ata_input_data = &e100_ide_input_data;
+                hwif->ata_output_data = &e100_ide_output_data;
+                hwif->atapi_input_bytes = &e100_atapi_input_bytes;
+                hwif->atapi_output_bytes = &e100_atapi_output_bytes;
+                hwif->ide_dma_check = &e100_dma_check;
+                hwif->ide_dma_end = &e100_dma_end;
+		hwif->ide_dma_write = &e100_dma_write;
+		hwif->ide_dma_read = &e100_dma_read;
+		hwif->ide_dma_begin = &e100_dma_begin;
+		hwif->OUTB = &etrax100_ide_outb;
+		hwif->OUTW = &etrax100_ide_outw;
+		hwif->OUTBSYNC = &etrax100_ide_outbsync;
+		hwif->INB = &etrax100_ide_inb;
+		hwif->INW = &etrax100_ide_inw;
+		hwif->ide_dma_off_quietly = &e100_dma_off;
+		hwif->ide_dma_verbose = &e100_dma_verbose;
+		hwif->sg_table =
+		  kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL);
+	}
+
+	/* actually reset and configure the etrax100 ide/ata interface */
+
+	*R_ATA_CTRL_DATA = 0;
+	*R_ATA_TRANSFER_CNT = 0;
+	*R_ATA_CONFIG = 0;
+
+	genconfig_shadow = (genconfig_shadow &
+			    ~IO_MASK(R_GEN_CONFIG, dma2) &
+			    ~IO_MASK(R_GEN_CONFIG, dma3) &
+			    ~IO_MASK(R_GEN_CONFIG, ata)) |
+		( IO_STATE( R_GEN_CONFIG, dma3, ata    ) |
+		  IO_STATE( R_GEN_CONFIG, dma2, ata    ) |
+		  IO_STATE( R_GEN_CONFIG, ata,  select ) );
+
+	*R_GEN_CONFIG = genconfig_shadow;
+
+        /* pull the chosen /reset-line low */
+
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+        REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+        REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+        REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_PB7_RESET
+	port_pb_dir_shadow = port_pb_dir_shadow |
+		IO_STATE(R_PORT_PB_DIR, dir7, output);
+	*R_PORT_PB_DIR = port_pb_dir_shadow;
+	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
+#endif
+
+	/* wait some */
+
+	udelay(25);
+
+	/* de-assert bus-reset */
+
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+	REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+	REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1);
+#endif
+
+	/* make a dummy read to set the ata controller in a proper state */
+	dummy = *R_ATA_STATUS_DATA;
+
+	*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+			  IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+			  IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+			  IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO4_SETUP ) |
+			  IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+			  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
+
+	*R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw,   read) |
+			     IO_FIELD( R_ATA_CTRL_DATA, addr, 1   ) );
+
+	while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
+
+	*R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
+			     IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
+			     IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
+			     IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
+
+	printk("ide: waiting %d seconds for drives to regain consciousness\n",
+	       CONFIG_ETRAX_IDE_DELAY);
+
+	h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
+	while(time_before(jiffies, h)) /* nothing */ ;
+
+	/* reset the dma channels we will use */
+
+	RESET_DMA(ATA_TX_DMA_NBR);
+	RESET_DMA(ATA_RX_DMA_NBR);
+	WAIT_DMA(ATA_TX_DMA_NBR);
+	WAIT_DMA(ATA_RX_DMA_NBR);
+
+}
+
+static int e100_dma_off (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int e100_dma_verbose (ide_drive_t *drive)
+{
+	printk(", DMA(mode 2)");
+	return 0;
+}
+
+static etrax_dma_descr mydescr;
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+static void
+e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+	unsigned long data_reg = IDE_DATA_REG;
+
+	D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+		 data_reg, buffer, bytecount));
+
+	if(bytecount & 1) {
+		printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
+		bytecount++; /* to round off */
+	}
+
+	/* make sure the DMA channel is available */
+	RESET_DMA(ATA_RX_DMA_NBR);
+	WAIT_DMA(ATA_RX_DMA_NBR);
+
+	/* setup DMA descriptor */
+
+	mydescr.sw_len = bytecount;
+	mydescr.ctrl   = d_eol;
+	mydescr.buf    = virt_to_phys(buffer);
+
+	/* start the dma channel */
+
+	*R_DMA_CH3_FIRST = virt_to_phys(&mydescr);
+	*R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+	/* initiate a multi word dma read using PIO handshaking */
+
+	*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
+
+	*R_ATA_CTRL_DATA = data_reg |
+		IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+		IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
+		IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+		IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+	/* wait for completion */
+
+	LED_DISK_READ(1);
+	WAIT_DMA(ATA_RX_DMA_NBR);
+	LED_DISK_READ(0);
+
+#if 0
+        /* old polled transfer code
+	 * this should be moved into a new function that can do polled
+	 * transfers if DMA is not available
+	 */
+
+        /* initiate a multi word read */
+
+        *R_ATA_TRANSFER_CNT = wcount << 1;
+
+        *R_ATA_CTRL_DATA = data_reg |
+                IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
+                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+        /* svinto has a latency until the busy bit actually is set */
+
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+
+        /* unit should be busy during multi transfer */
+        while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
+                while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
+                        status = *R_ATA_STATUS_DATA;
+                *ptr++ = (unsigned short)(status & 0xffff);
+        }
+#endif
+}
+
+static void
+e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+	unsigned long data_reg = IDE_DATA_REG;
+
+	D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+		 data_reg, buffer, bytecount));
+
+	if(bytecount & 1) {
+		printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
+		bytecount++;
+	}
+
+	/* make sure the DMA channel is available */
+	RESET_DMA(ATA_TX_DMA_NBR);
+	WAIT_DMA(ATA_TX_DMA_NBR);
+
+	/* setup DMA descriptor */
+
+	mydescr.sw_len = bytecount;
+	mydescr.ctrl   = d_eol;
+	mydescr.buf    = virt_to_phys(buffer);
+
+	/* start the dma channel */
+
+	*R_DMA_CH2_FIRST = virt_to_phys(&mydescr);
+	*R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+	/* initiate a multi word dma write using PIO handshaking */
+
+	*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
+
+	*R_ATA_CTRL_DATA = data_reg |
+		IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+		IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
+		IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+		IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+	/* wait for completion */
+
+	LED_DISK_WRITE(1);
+	WAIT_DMA(ATA_TX_DMA_NBR);
+	LED_DISK_WRITE(0);
+
+#if 0
+        /* old polled write code - see comment in input_bytes */
+
+	/* wait for busy flag */
+        while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+        /* initiate a multi word write */
+
+        *R_ATA_TRANSFER_CNT = bytecount >> 1;
+
+        ctrl = data_reg |
+                IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
+                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+        LED_DISK_WRITE(1);
+
+        /* Etrax will set busy = 1 until the multi pio transfer has finished
+         * and tr_rdy = 1 after each successful word transfer.
+         * When the last byte has been transferred Etrax will first set tr_tdy = 1
+         * and then busy = 0 (not in the same cycle). If we read busy before it
+         * has been set to 0 we will think that we should transfer more bytes
+         * and then tr_rdy would be 0 forever. This is solved by checking busy
+         * in the inner loop.
+         */
+
+        do {
+                *R_ATA_CTRL_DATA = ctrl | *ptr++;
+                while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
+                      (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
+        } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+        LED_DISK_WRITE(0);
+#endif
+
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+static void
+e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	e100_atapi_input_bytes(drive, buffer, wcount << 2);
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+static void
+e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	e100_atapi_output_bytes(drive, buffer, wcount << 2);
+}
+
+/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
+static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
+static unsigned int ata_tot_size;
+
+/*
+ * e100_ide_build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ */
+static int e100_ide_build_dmatable (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct scatterlist* sg;
+	struct request *rq  = HWGROUP(drive)->rq;
+	unsigned long size, addr;
+	unsigned int count = 0;
+	int i = 0;
+
+	sg = hwif->sg_table;
+
+	ata_tot_size = 0;
+
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		u8 *virt_addr = rq->buffer;
+		int sector_count = rq->nr_sectors;
+		memset(&sg[0], 0, sizeof(*sg));
+		sg[0].page = virt_to_page(virt_addr);
+		sg[0].offset = offset_in_page(virt_addr);
+		sg[0].length =  sector_count  * SECTOR_SIZE;
+		hwif->sg_nents = i = 1;
+	}
+	else
+	{
+		hwif->sg_nents = i = blk_rq_map_sg(drive->queue, rq, hwif->sg_table);
+	}
+
+
+	while(i) {
+		/*
+		 * Determine addr and size of next buffer area.  We assume that
+		 * individual virtual buffers are always composed linearly in
+		 * physical memory.  For example, we assume that any 8kB buffer
+		 * is always composed of two adjacent physical 4kB pages rather
+		 * than two possibly non-adjacent physical 4kB pages.
+		 */
+		/* group sequential buffers into one large buffer */
+		addr = page_to_phys(sg->page) + sg->offset;
+		size = sg_dma_len(sg);
+		while (sg++, --i) {
+			if ((addr + size) != page_to_phys(sg->page) + sg->offset)
+				break;
+			size += sg_dma_len(sg);
+		}
+
+		/* did we run out of descriptors? */
+
+		if(count >= MAX_DMA_DESCRS) {
+			printk("%s: too few DMA descriptors\n", drive->name);
+			return 1;
+		}
+
+		/* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
+		   than 65536 words per transfer, so in that case we need to either
+		   1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
+		      the descriptors, or
+		   2) simply do the request here, and get dma_intr to only ide_end_request on
+		      those blocks that were actually set-up for transfer.
+		*/
+
+		if(ata_tot_size + size > 131072) {
+			printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
+			return 1;
+		}
+
+		/* If size > 65536 it has to be splitted into new descriptors. Since we don't handle
+                   size > 131072 only one split is necessary */
+
+		if(size > 65536) {
+ 		        /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+                        ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
+                        ata_descrs[count].ctrl = 0;
+                        ata_descrs[count].buf = addr;
+                        ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+                        count++;
+                        ata_tot_size += 65536;
+                        /* size and addr should refere to not handled data */
+                        size -= 65536;
+                        addr += 65536;
+                }
+		/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+                if(size == 65536) {
+			ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
+                } else {
+			ata_descrs[count].sw_len = size;
+                }
+		ata_descrs[count].ctrl = 0;
+		ata_descrs[count].buf = addr;
+		ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+		count++;
+		ata_tot_size += size;
+	}
+
+	if (count) {
+		/* set the end-of-list flag on the last descriptor */
+		ata_descrs[count - 1].ctrl |= d_eol;
+		/* return and say all is ok */
+		return 0;
+	}
+
+	printk("%s: empty DMA table?\n", drive->name);
+	return 1;	/* let the PIO routines handle this weirdness */
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+        const char **list;
+        struct hd_driveid *id = drive->id;
+
+        if (id && (id->capability & 1)) {
+                /* Enable DMA on any drive that supports mword2 DMA */
+                if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
+                        drive->using_dma = 1;
+                        return 0;               /* DMA enabled */
+                }
+
+                /* Consult the list of known "good" drives */
+                list = good_dma_drives;
+                while (*list) {
+                        if (!strcmp(*list++,id->model)) {
+                                drive->using_dma = 1;
+                                return 0;       /* DMA enabled */
+                        }
+                }
+        }
+        return 1;       /* DMA not enabled */
+}
+
+/*
+ * etrax_dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
+{
+	int i, dma_stat;
+	byte stat;
+
+	LED_DISK_READ(0);
+	LED_DISK_WRITE(0);
+
+	dma_stat = HWIF(drive)->ide_dma_end(drive);
+	stat = HWIF(drive)->INB(IDE_STATUS_REG);		/* get drive status */
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
+			}
+			return ide_stopped;
+		}
+		printk("%s: bad DMA status\n", drive->name);
+	}
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+/*
+ * Functions below initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * For ATAPI devices, we just prepare for DMA and return. The caller should
+ * then issue the packet command to the drive and call us again with
+ * ide_dma_begin afterwards.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ */
+
+static int e100_dma_check(ide_drive_t *drive)
+{
+	return config_drive_for_dma (drive);
+}
+
+static int e100_dma_end(ide_drive_t *drive)
+{
+	/* TODO: check if something went wrong with the DMA */
+	return 0;
+}
+
+static int e100_start_dma(ide_drive_t *drive, int atapi, int reading)
+{
+	if(reading) {
+
+		RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+		WAIT_DMA(ATA_RX_DMA_NBR);
+
+		/* set up the Etrax DMA descriptors */
+
+		if(e100_ide_build_dmatable (drive))
+			return 1;
+
+		if(!atapi) {
+			/* set the irq handler which will finish the request when DMA is done */
+
+			ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+			/* issue cmd to drive */
+                        if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+			    (drive->addressing == 1)) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing) {
+				etrax100_ide_outb(WIN_READDMA_EXT, IDE_COMMAND_REG);
+			} else {
+				etrax100_ide_outb(WIN_READDMA, IDE_COMMAND_REG);
+			}
+		}
+
+		/* begin DMA */
+
+		/* need to do this before RX DMA due to a chip bug
+		 * it is enough to just flush the part of the cache that
+		 * corresponds to the buffers we start, but since HD transfers
+		 * usually are more than 8 kB, it is easier to optimize for the
+		 * normal case and just flush the entire cache. its the only
+		 * way to be sure! (OB movie quote)
+		 */
+		flush_etrax_cache();
+		*R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
+		*R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+		/* initiate a multi word dma read using DMA handshaking */
+
+		*R_ATA_TRANSFER_CNT =
+			IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
+
+		*R_ATA_CTRL_DATA =
+			IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
+			IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+			IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma)  |
+			IO_STATE(R_ATA_CTRL_DATA, handsh,   dma)  |
+			IO_STATE(R_ATA_CTRL_DATA, multi,    on)   |
+			IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+		LED_DISK_READ(1);
+
+		D(printk("dma read of %d bytes.\n", ata_tot_size));
+
+	} else {
+		/* writing */
+
+		RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+		WAIT_DMA(ATA_TX_DMA_NBR);
+
+		/* set up the Etrax DMA descriptors */
+
+		if(e100_ide_build_dmatable (drive))
+			return 1;
+
+		if(!atapi) {
+			/* set the irq handler which will finish the request when DMA is done */
+
+			ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+			/* issue cmd to drive */
+			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+			    (drive->addressing == 1)) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing) {
+				etrax100_ide_outb(WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			} else {
+				etrax100_ide_outb(WIN_WRITEDMA, IDE_COMMAND_REG);
+			}
+		}
+
+		/* begin DMA */
+
+		*R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
+		*R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+		/* initiate a multi word dma write using DMA handshaking */
+
+		*R_ATA_TRANSFER_CNT =
+			IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
+
+		*R_ATA_CTRL_DATA =
+			IO_FIELD(R_ATA_CTRL_DATA, data,     IDE_DATA_REG) |
+			IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+			IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
+			IO_STATE(R_ATA_CTRL_DATA, handsh,   dma) |
+			IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+			IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+		LED_DISK_WRITE(1);
+
+		D(printk("dma write of %d bytes.\n", ata_tot_size));
+	}
+	return 0;
+}
+
+static int e100_dma_write(ide_drive_t *drive)
+{
+	e100_read_command = 0;
+	/* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
+	 * then they call ide_dma_begin after they have issued the appropriate drive command
+	 * themselves to actually start the chipset DMA. so we just return here if we're
+	 * not a diskdrive.
+	 */
+	if (drive->media != ide_disk)
+                return 0;
+	return e100_start_dma(drive, 0, 0);
+}
+
+static int e100_dma_read(ide_drive_t *drive)
+{
+	e100_read_command = 1;
+	/* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
+	 * then they call ide_dma_begin after they have issued the appropriate drive command
+	 * themselves to actually start the chipset DMA. so we just return here if we're
+	 * not a diskdrive.
+	 */
+	if (drive->media != ide_disk)
+                return 0;
+	return e100_start_dma(drive, 0, 1);
+}
+
+static int e100_dma_begin(ide_drive_t *drive)
+{
+	/* begin DMA, used by ATAPI devices which want to issue the
+	 * appropriate IDE command themselves.
+	 *
+	 * they have already called ide_dma_read/write to set the
+	 * static reading flag, now they call ide_dma_begin to do
+	 * the real stuff. we tell our code below not to issue
+	 * any IDE commands itself and jump into it.
+	 */
+	 return e100_start_dma(drive, 1, e100_read_command);
+}
diff -puN /dev/null drivers/net/cris/eth_v10.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/net/cris/eth_v10.c	Mon Nov  8 14:19:37 2004
@@ -0,0 +1,1836 @@
+/* $Id: ethernet.c,v 1.31 2004/10/18 14:49:03 starvik Exp $
+ *
+ * e100net.c: A network driver for the ETRAX 100LX network controller.
+ *
+ * Copyright (c) 1998-2002 Axis Communications AB.
+ *
+ * The outline of this driver comes from skeleton.c.
+ *
+ * $Log: ethernet.c,v $
+ * Revision 1.31  2004/10/18 14:49:03  starvik
+ * Use RX interrupt as random source
+ *
+ * Revision 1.30  2004/09/29 10:44:04  starvik
+ * Enabed MAC-address output again
+ *
+ * Revision 1.29  2004/08/24 07:14:05  starvik
+ * Make use of generic MDIO interface and constants.
+ *
+ * Revision 1.28  2004/08/20 09:37:11  starvik
+ * Added support for Intel LXT972A. Creds to Randy Scarborough.
+ *
+ * Revision 1.27  2004/08/16 12:37:22  starvik
+ * Merge of Linux 2.6.8
+ *
+ * Revision 1.25  2004/06/21 10:29:57  starvik
+ * Merge of Linux 2.6.7
+ *
+ * Revision 1.23  2004/06/09 05:29:22  starvik
+ * Avoid any race where R_DMA_CH1_FIRST is NULL (may trigger cache bug).
+ *
+ * Revision 1.22  2004/05/14 07:58:03  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.20  2004/03/11 11:38:40  starvik
+ * Merge of Linux 2.6.4
+ *
+ * Revision 1.18  2003/12/03 13:45:46  starvik
+ * Use hardware pad for short packets to prevent information leakage.
+ *
+ * Revision 1.17  2003/07/04 08:27:37  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.16  2003/04/24 08:28:22  starvik
+ * New LED behaviour: LED off when no link
+ *
+ * Revision 1.15  2003/04/09 05:20:47  starvik
+ * Merge of Linux 2.5.67
+ *
+ * Revision 1.13  2003/03/06 16:11:01  henriken
+ * Off by one error in group address register setting.
+ *
+ * Revision 1.12  2003/02/27 17:24:19  starvik
+ * Corrected Rev to Revision
+ *
+ * Revision 1.11  2003/01/24 09:53:21  starvik
+ * Oops. Initialize GA to 0, not to 1
+ *
+ * Revision 1.10  2003/01/24 09:50:55  starvik
+ * Initialize GA_0 and GA_1 to 0 to avoid matching of unwanted packets
+ *
+ * Revision 1.9  2002/12/13 07:40:58  starvik
+ * Added basic ethtool interface
+ * Handled out of memory when allocating new buffers
+ *
+ * Revision 1.8  2002/12/11 13:13:57  starvik
+ * Added arch/ to v10 specific includes
+ * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+ *
+ * Revision 1.7  2002/11/26 09:41:42  starvik
+ * Added e100_set_config (standard interface to set media type)
+ * Added protection against preemptive scheduling
+ * Added standard MII ioctls
+ *
+ * Revision 1.6  2002/11/21 07:18:18  starvik
+ * Timers must be initialized in 2.5.48
+ *
+ * Revision 1.5  2002/11/20 11:56:11  starvik
+ * Merge of Linux 2.5.48
+ *
+ * Revision 1.4  2002/11/18 07:26:46  starvik
+ * Linux 2.5 port of latest Linux 2.4 ethernet driver
+ *
+ * Revision 1.33  2002/10/02 20:16:17  hp
+ * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
+ *
+ * Revision 1.32  2002/09/16 06:05:58  starvik
+ * Align memory returned by dev_alloc_skb
+ * Moved handling of sent packets to interrupt to avoid reference counting problem
+ *
+ * Revision 1.31  2002/09/10 13:28:23  larsv
+ * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
+ * for supported functionality by issuing special ioctls, i.e. wireless
+ * extensions.
+ *
+ * Revision 1.30  2002/05/07 18:50:08  johana
+ * Correct spelling in comments.
+ *
+ * Revision 1.29  2002/05/06 05:38:49  starvik
+ * Performance improvements:
+ *    Large packets are not copied (breakpoint set to 256 bytes)
+ *    The cache bug workaround is delayed until half of the receive list
+ *      has been used
+ *    Added transmit list
+ *    Transmit interrupts are only enabled when transmit queue is full
+ *
+ * Revision 1.28.2.1  2002/04/30 08:15:51  starvik
+ * Performance improvements:
+ *   Large packets are not copied (breakpoint set to 256 bytes)
+ *   The cache bug workaround is delayed until half of the receive list
+ *     has been used.
+ *   Added transmit list
+ *   Transmit interrupts are only enabled when transmit queue is full
+ *
+ * Revision 1.28  2002/04/22 11:47:21  johana
+ * Fix according to 2.4.19-pre7. time_after/time_before and
+ * missing end of comment.
+ * The patch has a typo for ethernet.c in e100_clear_network_leds(),
+ *  that is fixed here.
+ *
+ * Revision 1.27  2002/04/12 11:55:11  bjornw
+ * Added TODO
+ *
+ * Revision 1.26  2002/03/15 17:11:02  bjornw
+ * Use prepare_rx_descriptor after the CPU has touched the receiving descs
+ *
+ * Revision 1.25  2002/03/08 13:07:53  bjornw
+ * Unnecessary spinlock removed
+ *
+ * Revision 1.24  2002/02/20 12:57:43  fredriks
+ * Replaced MIN() with min().
+ *
+ * Revision 1.23  2002/02/20 10:58:14  fredriks
+ * Strip the Ethernet checksum (4 bytes) before forwarding a frame to upper layers.
+ *
+ * Revision 1.22  2002/01/30 07:48:22  matsfg
+ * Initiate R_NETWORK_TR_CTRL
+ *
+ * Revision 1.21  2001/11/23 11:54:49  starvik
+ * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list
+ * Removed compiler warnings
+ *
+ * Revision 1.20  2001/11/12 19:26:00  pkj
+ * * Corrected e100_negotiate() to not assign half to current_duplex when
+ *   it was supposed to compare them...
+ * * Cleaned up failure handling in e100_open().
+ * * Fixed compiler warnings.
+ *
+ * Revision 1.19  2001/11/09 07:43:09  starvik
+ * Added full duplex support
+ * Added ioctl to set speed and duplex
+ * Clear LED timer only runs when LED is lit
+ *
+ * Revision 1.18  2001/10/03 14:40:43  jonashg
+ * Update rx_bytes counter.
+ *
+ * Revision 1.17  2001/06/11 12:43:46  olof
+ * Modified defines for network LED behavior
+ *
+ * Revision 1.16  2001/05/30 06:12:46  markusl
+ * TxDesc.next should not be set to NULL
+ *
+ * Revision 1.15  2001/05/29 10:27:04  markusl
+ * Updated after review remarks:
+ * +Use IO_EXTRACT
+ * +Handle underrun
+ *
+ * Revision 1.14  2001/05/29 09:20:14  jonashg
+ * Use driver name on printk output so one can tell which driver that complains.
+ *
+ * Revision 1.13  2001/05/09 12:35:59  johana
+ * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
+ *
+ * Revision 1.12  2001/04/05 11:43:11  tobiasa
+ * Check dev before panic.
+ *
+ * Revision 1.11  2001/04/04 11:21:05  markusl
+ * Updated according to review remarks
+ *
+ * Revision 1.10  2001/03/26 16:03:06  bjornw
+ * Needs linux/config.h
+ *
+ * Revision 1.9  2001/03/19 14:47:48  pkj
+ * * Make sure there is always a pause after the network LEDs are
+ *   changed so they will not look constantly lit during heavy traffic.
+ * * Always use HZ when setting times relative to jiffies.
+ * * Use LED_NETWORK_SET() when setting the network LEDs.
+ *
+ * Revision 1.8  2001/02/27 13:52:48  bjornw
+ * malloc.h -> slab.h
+ *
+ * Revision 1.7  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.6  2001/01/26 15:21:04  starvik
+ * Don't disable interrupts while reading MDIO registers (MDIO is slow)
+ * Corrected promiscuous mode
+ * Improved deallocation of IRQs ("ifconfig eth0 down" now works)
+ *
+ * Revision 1.5  2000/11/29 17:22:22  bjornw
+ * Get rid of the udword types legacy stuff
+ *
+ * Revision 1.4  2000/11/22 16:36:09  bjornw
+ * Please marketing by using the correct case when spelling Etrax.
+ *
+ * Revision 1.3  2000/11/21 16:43:04  bjornw
+ * Minor short->int change
+ *
+ * Revision 1.2  2000/11/08 14:27:57  bjornw
+ * 2.4 port
+ *
+ * Revision 1.1  2000/11/06 13:56:00  bjornw
+ * Verbatim copy of the 1.24 version of e100net.c from elinux
+ *
+ * Revision 1.24  2000/10/04 15:55:23  bjornw
+ * * Use virt_to_phys etc. for DMA addresses
+ * * Removed bogus CHECKSUM_UNNECESSARY
+ *
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/if.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+
+#include <asm/arch/svinto.h>/* DMA and register descriptions */
+#include <asm/io.h>         /* LED_* I/O functions */
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/ethernet.h>
+#include <asm/cache.h>
+
+//#define ETHDEBUG
+#define D(x)
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+
+static const char* cardname = "ETRAX 100LX built-in ethernet controller";
+
+/* A default ethernet address. Highlevel SW will set the real one later */
+
+static struct sockaddr default_mac = {
+	0,
+	{ 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
+};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct net_device_stats stats;
+	struct mii_if_info mii_if;
+
+	/* Tx control lock.  This protects the transmit buffer ring
+	 * state along with the "tx full" state of the driver.  This
+	 * means all netif_queue flow control actions are protected
+	 * by this lock as well.
+	 */
+	spinlock_t lock;
+};
+
+typedef struct etrax_eth_descr
+{
+	etrax_dma_descr descr;
+	struct sk_buff* skb;
+} etrax_eth_descr;
+
+/* Some transceivers requires special handling */
+struct transceiver_ops
+{
+	unsigned int oui;
+	void (*check_speed)(struct net_device* dev);
+	void (*check_duplex)(struct net_device* dev);
+};
+
+struct transceiver_ops* transceiver;
+
+/* Duplex settings */
+enum duplex
+{
+	half,
+	full,
+	autoneg
+};
+
+/* Dma descriptors etc. */
+
+#define MAX_MEDIA_DATA_SIZE 1518
+
+#define MIN_PACKET_LEN      46
+#define ETHER_HEAD_LEN      14
+
+/*
+** MDIO constants.
+*/
+#define MDIO_START                          0x1
+#define MDIO_READ                           0x2
+#define MDIO_WRITE                          0x1
+#define MDIO_PREAMBLE              0xfffffffful
+
+/* Broadcom specific */
+#define MDIO_AUX_CTRL_STATUS_REG           0x18
+#define MDIO_BC_FULL_DUPLEX_IND             0x1
+#define MDIO_BC_SPEED                       0x2
+
+/* TDK specific */
+#define MDIO_TDK_DIAGNOSTIC_REG              18
+#define MDIO_TDK_DIAGNOSTIC_RATE          0x400
+#define MDIO_TDK_DIAGNOSTIC_DPLX          0x800
+
+/*Intel LXT972A specific*/
+#define MDIO_INT_STATUS_REG_2			0x0011
+#define MDIO_INT_FULL_DUPLEX_IND		( 1 << 9 )
+#define MDIO_INT_SPEED				( 1 << 14 )
+
+/* Network flash constants */
+#define NET_FLASH_TIME                  (HZ/50) /* 20 ms */
+#define NET_FLASH_PAUSE                (HZ/100) /* 10 ms */
+#define NET_LINK_UP_CHECK_INTERVAL       (2*HZ) /* 2 s   */
+#define NET_DUPLEX_CHECK_INTERVAL        (2*HZ) /* 2 s   */
+
+#define NO_NETWORK_ACTIVITY 0
+#define NETWORK_ACTIVITY    1
+
+#define NBR_OF_RX_DESC     64
+#define NBR_OF_TX_DESC     256
+
+/* Large packets are sent directly to upper layers while small packets are */
+/* copied (to reduce memory waste). The following constant decides the breakpoint */
+#define RX_COPYBREAK 256
+
+/* Due to a chip bug we need to flush the cache when descriptors are returned */
+/* to the DMA. To decrease performance impact we return descriptors in chunks. */
+/* The following constant determines the number of descriptors to return. */
+#define RX_QUEUE_THRESHOLD  NBR_OF_RX_DESC/2
+
+#define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
+
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
+
+static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
+                                          to be processed */
+static etrax_eth_descr *myLastRxDesc;  /* The last processed descriptor */
+static etrax_eth_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
+
+static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
+
+static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */
+static etrax_eth_descr* myLastTxDesc;  /* End of send queue */
+static etrax_eth_descr* myNextTxDesc;  /* Next descriptor to use */
+static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
+
+static unsigned int network_rec_config_shadow = 0;
+static unsigned int mdio_phy_addr; /* Transciever address */
+
+static unsigned int network_tr_ctrl_shadow = 0;
+
+/* Network speed indication. */
+static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static int current_speed; /* Speed read from transceiver */
+static int current_speed_selection; /* Speed selected by user */
+static unsigned long led_next_time;
+static int led_active;
+static int rx_queue_len;
+
+/* Duplex */
+static struct timer_list duplex_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static int full_duplex;
+static enum duplex current_duplex;
+
+/* Index to functions, as function prototypes. */
+
+static int etrax_ethernet_init(void);
+
+static int e100_open(struct net_device *dev);
+static int e100_set_mac_address(struct net_device *dev, void *addr);
+static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100_rx(struct net_device *dev);
+static int e100_close(struct net_device *dev);
+static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
+static int e100_set_config(struct net_device* dev, struct ifmap* map);
+static void e100_tx_timeout(struct net_device *dev);
+static struct net_device_stats *e100_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void e100_hardware_send_packet(char *buf, int length);
+static void update_rx_stats(struct net_device_stats *);
+static void update_tx_stats(struct net_device_stats *);
+static int e100_probe_transceiver(struct net_device* dev);
+
+static void e100_check_speed(unsigned long priv);
+static void e100_set_speed(struct net_device* dev, unsigned long speed);
+static void e100_check_duplex(unsigned long priv);
+static void e100_set_duplex(struct net_device* dev, enum duplex);
+static void e100_negotiate(struct net_device* dev);
+
+static int e100_get_mdio_reg(struct net_device *dev, int phy_id, int location);
+static void e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value);
+
+static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
+static void e100_send_mdio_bit(unsigned char bit);
+static unsigned char e100_receive_mdio_bit(void);
+static void e100_reset_transceiver(struct net_device* net);
+
+static void e100_clear_network_leds(unsigned long dummy);
+static void e100_set_network_leds(int active);
+
+static void broadcom_check_speed(struct net_device* dev);
+static void broadcom_check_duplex(struct net_device* dev);
+static void tdk_check_speed(struct net_device* dev);
+static void tdk_check_duplex(struct net_device* dev);
+static void intel_check_speed(struct net_device* dev);
+static void intel_check_duplex(struct net_device* dev);
+static void generic_check_speed(struct net_device* dev);
+static void generic_check_duplex(struct net_device* dev);
+
+struct transceiver_ops transceivers[] =
+{
+	{0x1018, broadcom_check_speed, broadcom_check_duplex},  /* Broadcom */
+	{0xC039, tdk_check_speed, tdk_check_duplex},            /* TDK 2120 */
+	{0x039C, tdk_check_speed, tdk_check_duplex},            /* TDK 2120C */
+        {0x04de, intel_check_speed, intel_check_duplex},     	/* Intel LXT972A*/
+	{0x0000, generic_check_speed, generic_check_duplex}     /* Generic, must be last */
+};
+
+#define tx_done(dev) (*R_DMA_CH0_CMD == 0)
+
+/*
+ * Check for a network adaptor of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, allocate space for the device and return success
+ * (detachable devices only).
+ */
+
+static int __init
+etrax_ethernet_init(void)
+{
+	struct net_device *dev;
+        struct net_local* np;
+	int i, err;
+
+	printk(KERN_INFO
+	       "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
+
+	dev = alloc_etherdev(sizeof(struct net_local));
+	np = dev->priv;
+
+	if (!dev)
+		return -ENOMEM;
+
+	dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
+
+	/* now setup our etrax specific stuff */
+
+	dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */
+	dev->dma = NETWORK_RX_DMA_NBR;
+
+	/* fill in our handlers so the network layer can talk to us in the future */
+
+	dev->open               = e100_open;
+	dev->hard_start_xmit    = e100_send_packet;
+	dev->stop               = e100_close;
+	dev->get_stats          = e100_get_stats;
+	dev->set_multicast_list = set_multicast_list;
+	dev->set_mac_address    = e100_set_mac_address;
+	dev->do_ioctl           = e100_ioctl;
+	dev->set_config		= e100_set_config;
+	dev->tx_timeout         = e100_tx_timeout;
+
+	/* Initialise the list of Etrax DMA-descriptors */
+
+	/* Initialise receive descriptors */
+
+	for (i = 0; i < NBR_OF_RX_DESC; i++) {
+		/* Allocate two extra cachelines to make sure that buffer used by DMA
+		 * does not share cacheline with any other data (to avoid cache bug)
+		 */
+		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+		RxDescList[i].descr.ctrl   = 0;
+		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
+		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
+		RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
+		RxDescList[i].descr.status = 0;
+		RxDescList[i].descr.hw_len = 0;
+		prepare_rx_descriptor(&RxDescList[i].descr);
+	}
+
+	RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl   = d_eol;
+	RxDescList[NBR_OF_RX_DESC - 1].descr.next   = virt_to_phys(&RxDescList[0]);
+	rx_queue_len = 0;
+
+	/* Initialize transmit descriptors */
+	for (i = 0; i < NBR_OF_TX_DESC; i++) {
+		TxDescList[i].descr.ctrl   = 0;
+		TxDescList[i].descr.sw_len = 0;
+		TxDescList[i].descr.next   = virt_to_phys(&TxDescList[i + 1].descr);
+		TxDescList[i].descr.buf    = 0;
+		TxDescList[i].descr.status = 0;
+		TxDescList[i].descr.hw_len = 0;
+		TxDescList[i].skb = 0;
+	}
+
+	TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl   = d_eol;
+	TxDescList[NBR_OF_TX_DESC - 1].descr.next   = virt_to_phys(&TxDescList[0].descr);
+
+	/* Initialise initial pointers */
+
+	myNextRxDesc  = &RxDescList[0];
+	myLastRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
+	myPrevRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
+	myFirstTxDesc = &TxDescList[0];
+	myNextTxDesc  = &TxDescList[0];
+	myLastTxDesc  = &TxDescList[NBR_OF_TX_DESC - 1];
+
+	/* Register device */
+	err = register_netdev(dev);
+	if (err) {
+		free_netdev(dev);
+		return err;
+	}
+
+	/* set the default MAC address */
+
+	e100_set_mac_address(dev, &default_mac);
+
+	/* Initialize speed indicator stuff. */
+
+	current_speed = 10;
+	current_speed_selection = 0; /* Auto */
+	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+        duplex_timer.data = (unsigned long)dev;
+	speed_timer.function = e100_check_speed;
+
+	clear_led_timer.function = e100_clear_network_leds;
+
+	full_duplex = 0;
+	current_duplex = autoneg;
+	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+        duplex_timer.data = (unsigned long)dev;
+	duplex_timer.function = e100_check_duplex;
+
+        /* Initialize mii interface */
+	np->mii_if.phy_id = mdio_phy_addr;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = e100_get_mdio_reg;
+	np->mii_if.mdio_write = e100_set_mdio_reg;
+
+	/* Initialize group address registers to make sure that no */
+	/* unwanted addresses are matched */
+	*R_NETWORK_GA_0 = 0x00000000;
+	*R_NETWORK_GA_1 = 0x00000000;
+	return 0;
+}
+
+/* set MAC address of the interface. called from the core after a
+ * SIOCSIFADDR ioctl, and from the bootup above.
+ */
+
+static int
+e100_set_mac_address(struct net_device *dev, void *p)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+	struct sockaddr *addr = p;
+	int i;
+
+	spin_lock(&np->lock); /* preemption protection */
+
+	/* remember it */
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/* Write it to the hardware.
+	 * Note the way the address is wrapped:
+	 * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24);
+	 * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8);
+	 */
+
+	*R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+		(dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+	*R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
+	*R_NETWORK_SA_2 = 0;
+
+	/* show it in the log as well */
+
+	printk(KERN_INFO "%s: changed MAC to ", dev->name);
+
+	for (i = 0; i < 5; i++)
+		printk("%02X:", dev->dev_addr[i]);
+
+	printk("%02X\n", dev->dev_addr[i]);
+
+	spin_unlock(&np->lock);
+
+	return 0;
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+static int
+e100_open(struct net_device *dev)
+{
+	unsigned long flags;
+
+	/* enable the MDIO output pin */
+
+	*R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable);
+
+	*R_IRQ_MASK0_CLR =
+		IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
+
+	/* clear dma0 and 1 eop and descr irq masks */
+	*R_IRQ_MASK2_CLR =
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+
+	/* Reset and wait for the DMA channels */
+
+	RESET_DMA(NETWORK_TX_DMA_NBR);
+	RESET_DMA(NETWORK_RX_DMA_NBR);
+	WAIT_DMA(NETWORK_TX_DMA_NBR);
+	WAIT_DMA(NETWORK_RX_DMA_NBR);
+
+	/* Initialise the etrax network controller */
+
+	/* allocate the irq corresponding to the receiving DMA */
+
+	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt,
+			SA_SAMPLE_RANDOM, cardname, (void *)dev)) {
+		goto grace_exit0;
+	}
+
+	/* allocate the irq corresponding to the transmitting DMA */
+
+	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
+			cardname, (void *)dev)) {
+		goto grace_exit1;
+	}
+
+	/* allocate the irq corresponding to the network errors etc */
+
+	if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0,
+			cardname, (void *)dev)) {
+		goto grace_exit2;
+	}
+
+	/* give the HW an idea of what MAC address we want */
+
+	*R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+		(dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+	*R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
+	*R_NETWORK_SA_2 = 0;
+
+#if 0
+	/* use promiscuous mode for testing */
+	*R_NETWORK_GA_0 = 0xffffffff;
+	*R_NETWORK_GA_1 = 0xffffffff;
+
+	*R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
+#else
+	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
+	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
+	SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+	*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+#endif
+
+	*R_NETWORK_GEN_CONFIG =
+		IO_STATE(R_NETWORK_GEN_CONFIG, phy,    mii_clk) |
+		IO_STATE(R_NETWORK_GEN_CONFIG, enable, on);
+
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none);
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont);
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable);
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable);
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable);
+	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
+	*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+
+	save_flags(flags);
+	cli();
+
+	/* enable the irq's for ethernet DMA */
+
+	*R_IRQ_MASK2_SET =
+		IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
+
+	*R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, overrun,       set) |
+		IO_STATE(R_IRQ_MASK0_SET, underrun,      set) |
+		IO_STATE(R_IRQ_MASK0_SET, excessive_col, set);
+
+	/* make sure the irqs are cleared */
+
+	*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+	*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
+
+	/* make sure the rec and transmit error counters are cleared */
+
+	(void)*R_REC_COUNTERS;  /* dummy read */
+	(void)*R_TR_COUNTERS;   /* dummy read */
+
+	/* start the receiving DMA channel so we can receive packets from now on */
+
+	*R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc);
+	*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start);
+
+	/* Set up transmit DMA channel so it can be restarted later */
+
+	*R_DMA_CH0_FIRST = 0;
+	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+
+	restore_flags(flags);
+
+	/* Probe for transceiver */
+	if (e100_probe_transceiver(dev))
+		goto grace_exit3;
+
+	/* Start duplex/speed timers */
+	add_timer(&speed_timer);
+	add_timer(&duplex_timer);
+
+	/* We are now ready to accept transmit requeusts from
+	 * the queueing layer of the networking.
+	 */
+	netif_start_queue(dev);
+
+	return 0;
+
+grace_exit3:
+	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+grace_exit2:
+	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+grace_exit1:
+	free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+grace_exit0:
+	return -EAGAIN;
+}
+
+
+static void
+generic_check_speed(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+	if ((data & ADVERTISE_100FULL) ||
+	    (data & ADVERTISE_100HALF))
+		current_speed = 100;
+	else
+		current_speed = 10;
+}
+
+static void
+tdk_check_speed(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+	current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
+}
+
+static void
+broadcom_check_speed(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+	current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
+}
+
+static void
+intel_check_speed(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+	current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
+}
+
+static void
+e100_check_speed(unsigned long priv)
+{
+	struct net_device* dev = (struct net_device*)priv;
+	static int led_initiated = 0;
+	unsigned long data;
+	int old_speed = current_speed;
+
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR);
+	if (!(data & BMSR_LSTATUS)) {
+		current_speed = 0;
+	} else {
+		transceiver->check_speed(dev);
+	}
+
+	if ((old_speed != current_speed) || !led_initiated) {
+		led_initiated = 1;
+		e100_set_network_leds(NO_NETWORK_ACTIVITY);
+	}
+
+	/* Reinitialize the timer. */
+	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+	add_timer(&speed_timer);
+}
+
+static void
+e100_negotiate(struct net_device* dev)
+{
+	unsigned short data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+
+	/* Discard old speed and duplex settings */
+	data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL |
+	          ADVERTISE_10HALF | ADVERTISE_10FULL);
+
+	switch (current_speed_selection) {
+		case 10 :
+			if (current_duplex == full)
+				data |= ADVERTISE_10FULL;
+			else if (current_duplex == half)
+				data |= ADVERTISE_10HALF;
+			else
+				data |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+			break;
+
+		case 100 :
+			 if (current_duplex == full)
+				data |= ADVERTISE_100FULL;
+			else if (current_duplex == half)
+				data |= ADVERTISE_100HALF;
+			else
+				data |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+			break;
+
+		case 0 : /* Auto */
+			 if (current_duplex == full)
+				data |= ADVERTISE_100FULL | ADVERTISE_10FULL;
+			else if (current_duplex == half)
+				data |= ADVERTISE_100HALF | ADVERTISE_10HALF;
+			else
+				data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
+				  ADVERTISE_100HALF | ADVERTISE_100FULL;
+			break;
+
+		default : /* assume autoneg speed and duplex */
+			data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
+				  ADVERTISE_100HALF | ADVERTISE_100FULL;
+	}
+
+	e100_set_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE, data);
+
+	/* Renegotiate with link partner */
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+	data |= BMCR_ANENABLE | BMCR_ANRESTART;
+
+	e100_set_mdio_reg(dev, mdio_phy_addr, MII_BMCR, data);
+}
+
+static void
+e100_set_speed(struct net_device* dev, unsigned long speed)
+{
+	if (speed != current_speed_selection) {
+		current_speed_selection = speed;
+		e100_negotiate(dev);
+	}
+}
+
+static void
+e100_check_duplex(unsigned long priv)
+{
+	struct net_device *dev = (struct net_device *)priv;
+	struct net_local *np = (struct net_local *)dev->priv;
+	int old_duplex = full_duplex;
+	transceiver->check_duplex(dev);
+	if (old_duplex != full_duplex) {
+		/* Duplex changed */
+		SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+	}
+
+	/* Reinitialize the timer. */
+	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+	add_timer(&duplex_timer);
+	np->mii_if.full_duplex = full_duplex;
+}
+
+static void
+generic_check_duplex(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+	if ((data & ADVERTISE_10FULL) ||
+	    (data & ADVERTISE_100FULL))
+		full_duplex = 1;
+	else
+		full_duplex = 0;
+}
+
+static void
+tdk_check_duplex(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+	full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
+}
+
+static void
+broadcom_check_duplex(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+	full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
+}
+
+static void
+intel_check_duplex(struct net_device* dev)
+{
+	unsigned long data;
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+	full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;
+}
+
+static void
+e100_set_duplex(struct net_device* dev, enum duplex new_duplex)
+{
+	if (new_duplex != current_duplex) {
+		current_duplex = new_duplex;
+		e100_negotiate(dev);
+	}
+}
+
+static int
+e100_probe_transceiver(struct net_device* dev)
+{
+	unsigned int phyid_high;
+	unsigned int phyid_low;
+	unsigned int oui;
+	struct transceiver_ops* ops = NULL;
+
+	/* Probe MDIO physical address */
+	for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
+		if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 0xffff)
+			break;
+	}
+	if (mdio_phy_addr == 32)
+		 return -ENODEV;
+
+	/* Get manufacturer */
+	phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);
+	phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2);
+	oui = (phyid_high << 6) | (phyid_low >> 10);
+
+	for (ops = &transceivers[0]; ops->oui; ops++) {
+		if (ops->oui == oui)
+			break;
+	}
+	transceiver = ops;
+
+	return 0;
+}
+
+static int
+e100_get_mdio_reg(struct net_device *dev, int phy_id, int location)
+{
+	unsigned short cmd;    /* Data to be sent on MDIO port */
+	int data;   /* Data read from MDIO */
+	int bitCounter;
+
+	/* Start of frame, OP Code, Physical Address, Register Address */
+	cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) |
+		(location << 2);
+
+	e100_send_mdio_cmd(cmd, 0);
+
+	data = 0;
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		data |= (e100_receive_mdio_bit() << bitCounter);
+	}
+
+	return data;
+}
+
+static void
+e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value)
+{
+	int bitCounter;
+	unsigned short cmd;
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) |
+	      (location << 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, value));
+	}
+
+}
+
+static void
+e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
+{
+	int bitCounter;
+	unsigned char data = 0x2;
+
+	/* Preamble */
+	for (bitCounter = 31; bitCounter>= 0; bitCounter--)
+		e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));
+
+	for (bitCounter = 15; bitCounter >= 2; bitCounter--)
+		e100_send_mdio_bit(GET_BIT(bitCounter, cmd));
+
+	/* Turnaround */
+	for (bitCounter = 1; bitCounter >= 0 ; bitCounter--)
+		if (write_cmd)
+			e100_send_mdio_bit(GET_BIT(bitCounter, data));
+		else
+			e100_receive_mdio_bit();
+}
+
+static void
+e100_send_mdio_bit(unsigned char bit)
+{
+	*R_NETWORK_MGM_CTRL =
+		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
+		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
+	udelay(1);
+	*R_NETWORK_MGM_CTRL =
+		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
+		IO_MASK(R_NETWORK_MGM_CTRL, mdck) |
+		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
+	udelay(1);
+}
+
+static unsigned char
+e100_receive_mdio_bit()
+{
+	unsigned char bit;
+	*R_NETWORK_MGM_CTRL = 0;
+	bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT);
+	udelay(1);
+	*R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck);
+	udelay(1);
+	return bit;
+}
+
+static void
+e100_reset_transceiver(struct net_device* dev)
+{
+	unsigned short cmd;
+	unsigned short data;
+	int bitCounter;
+
+	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	data |= 0x8000;
+
+	for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}
+}
+
+/* Called by upper layers if they decide it took too long to complete
+ * sending a packet - we need to reset and stuff.
+ */
+
+static void
+e100_tx_timeout(struct net_device *dev)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+	       tx_done(dev) ? "IRQ problem" : "network cable problem");
+
+	/* remember we got an error */
+
+	np->stats.tx_errors++;
+
+	/* reset the TX DMA in case it has hung on something */
+
+	RESET_DMA(NETWORK_TX_DMA_NBR);
+	WAIT_DMA(NETWORK_TX_DMA_NBR);
+
+	/* Reset the transceiver. */
+
+	e100_reset_transceiver(dev);
+
+	/* and get rid of the packets that never got an interrupt */
+	while (myFirstTxDesc != myNextTxDesc)
+	{
+		dev_kfree_skb(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
+
+	/* Set up transmit DMA channel so it can be restarted later */
+	*R_DMA_CH0_FIRST = 0;
+	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+
+	/* tell the upper layers we're ok again */
+
+	netif_wake_queue(dev);
+	spin_unlock_irqrestore(&np->lock, flags);
+}
+
+
+/* This will only be invoked if the driver is _not_ in XOFF state.
+ * What this means is that we need not check it, and that this
+ * invariant will hold if we make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+
+static int
+e100_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+	unsigned char *buf = skb->data;
+	unsigned long flags;
+
+#ifdef ETHDEBUG
+	printk("send packet len %d\n", length);
+#endif
+	spin_lock_irqsave(&np->lock, flags);  /* protect from tx_interrupt and ourself */
+
+	myNextTxDesc->skb = skb;
+
+	dev->trans_start = jiffies;
+
+	e100_hardware_send_packet(buf, skb->len);
+
+	myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
+
+	/* Stop queue if full */
+	if (myNextTxDesc == myFirstTxDesc) {
+		netif_stop_queue(dev);
+	}
+
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	return 0;
+}
+
+/*
+ * The typical workload of the driver:
+ *   Handle the network interface interrupts.
+ */
+
+static irqreturn_t
+e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *np = (struct net_local *)dev->priv;
+	unsigned long irqbits = *R_IRQ_MASK2_RD;
+
+	/* Disable RX/TX IRQs to avoid reentrancy */
+	*R_IRQ_MASK2_CLR =
+	  IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+	  IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+
+	/* Handle received packets */
+	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
+		/* acknowledge the eop interrupt */
+
+		*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
+
+		/* check if one or more complete packets were indeed received */
+
+		while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) &&
+		       (myNextRxDesc != myLastRxDesc)) {
+			/* Take out the buffer and give it to the OS, then
+			 * allocate a new buffer to put a packet in.
+			 */
+			e100_rx(dev);
+			((struct net_local *)dev->priv)->stats.rx_packets++;
+			/* restart/continue on the channel, for safety */
+			*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
+			/* clear dma channel 1 eop/descr irq bits */
+			*R_DMA_CH1_CLR_INTR =
+				IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) |
+				IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do);
+
+			/* now, we might have gotten another packet
+			   so we have to loop back and check if so */
+		}
+	}
+
+	/* Report any packets that have been sent */
+	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+	       myFirstTxDesc != myNextTxDesc)
+	{
+		np->stats.tx_bytes += myFirstTxDesc->skb->len;
+		np->stats.tx_packets++;
+
+		/* dma is ready with the transmission of the data in tx_skb, so now
+		   we can release the skb memory */
+		dev_kfree_skb_irq(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
+
+	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
+		/* acknowledge the eop interrupt and wake up queue */
+		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+		netif_wake_queue(dev);
+	}
+
+	/* Enable RX/TX IRQs again */
+	*R_IRQ_MASK2_SET =
+	  IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
+	  IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *np = (struct net_local *)dev->priv;
+	unsigned long irqbits = *R_IRQ_MASK0_RD;
+
+	/* check for underrun irq */
+	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) {
+		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
+		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
+		np->stats.tx_errors++;
+		D(printk("ethernet receiver underrun!\n"));
+	}
+
+	/* check for overrun irq */
+	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {
+		update_rx_stats(&np->stats); /* this will ack the irq */
+		D(printk("ethernet receiver overrun!\n"));
+	}
+	/* check for excessive collision irq */
+	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) {
+		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
+		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
+		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
+		np->stats.tx_errors++;
+		D(printk("ethernet excessive collisions!\n"));
+	}
+	return IRQ_HANDLED;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+e100_rx(struct net_device *dev)
+{
+	struct sk_buff *skb;
+	int length = 0;
+	struct net_local *np = (struct net_local *)dev->priv;
+	unsigned char *skb_data_ptr;
+#ifdef ETHDEBUG
+	int i;
+#endif
+
+	if (!led_active && time_after(jiffies, led_next_time)) {
+		/* light the network leds depending on the current speed. */
+		e100_set_network_leds(NETWORK_ACTIVITY);
+
+		/* Set the earliest time we may clear the LED */
+		led_next_time = jiffies + NET_FLASH_TIME;
+		led_active = 1;
+		mod_timer(&clear_led_timer, jiffies + HZ/10);
+	}
+
+	length = myNextRxDesc->descr.hw_len - 4;
+	((struct net_local *)dev->priv)->stats.rx_bytes += length;
+
+#ifdef ETHDEBUG
+	printk("Got a packet of length %d:\n", length);
+	/* dump the first bytes in the packet */
+	skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf);
+	for (i = 0; i < 8; i++) {
+		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
+		       skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
+		       skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
+		skb_data_ptr += 8;
+	}
+#endif
+
+	if (length < RX_COPYBREAK) {
+		/* Small packet, copy data */
+		skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
+		if (!skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
+
+		skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
+		skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
+
+#ifdef ETHDEBUG
+		printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
+		  skb->head, skb->data, skb->tail, skb->end);
+		printk("copying packet to 0x%x.\n", skb_data_ptr);
+#endif
+
+		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
+	}
+	else {
+		/* Large packet, send directly to upper layers and allocate new
+		 * memory (aligned to cache line boundary to avoid bug).
+		 * Before sending the skb to upper layers we must make sure that
+		 * skb->data points to the aligned start of the packet.
+		 */
+		int align;
+		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+		if (!new_skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
+		skb = myNextRxDesc->skb;
+		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;
+		skb_put(skb, length + align);
+		skb_pull(skb, align); /* Remove alignment bytes */
+		myNextRxDesc->skb = new_skb;
+		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
+	}
+
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+
+	/* Send the packet to the upper layers */
+	netif_rx(skb);
+
+	/* Prepare for next packet */
+	myNextRxDesc->descr.status = 0;
+	myPrevRxDesc = myNextRxDesc;
+	myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
+
+	rx_queue_len++;
+
+	/* Check if descriptors should be returned */
+	if (rx_queue_len == RX_QUEUE_THRESHOLD) {
+		flush_etrax_cache();
+		myPrevRxDesc->descr.ctrl |= d_eol;
+		myLastRxDesc->descr.ctrl &= ~d_eol;
+		myLastRxDesc = myPrevRxDesc;
+		rx_queue_len = 0;
+	}
+}
+
+/* The inverse routine to net_open(). */
+static int
+e100_close(struct net_device *dev)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+
+	printk(KERN_INFO "Closing %s.\n", dev->name);
+
+	netif_stop_queue(dev);
+
+	*R_IRQ_MASK0_CLR =
+		IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
+
+	*R_IRQ_MASK2_CLR =
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+
+	/* Stop the receiver and the transmitter */
+
+	RESET_DMA(NETWORK_TX_DMA_NBR);
+	RESET_DMA(NETWORK_RX_DMA_NBR);
+
+	/* Flush the Tx and disable Rx here. */
+
+	free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+
+	/* Update the statistics here. */
+
+	update_rx_stats(&np->stats);
+	update_tx_stats(&np->stats);
+
+	/* Stop speed/duplex timers */
+	del_timer(&speed_timer);
+	del_timer(&duplex_timer);
+
+	return 0;
+}
+
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = if_mii(ifr);
+	struct net_local *np = netdev_priv(dev);
+
+	spin_lock(&np->lock); /* Preempt protection */
+	switch (cmd) {
+		case SIOCETHTOOL:
+			return e100_ethtool_ioctl(dev,ifr);
+		case SIOCGMIIPHY: /* Get PHY address */
+			data->phy_id = mdio_phy_addr;
+			break;
+		case SIOCGMIIREG: /* Read MII register */
+			data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num);
+			break;
+		case SIOCSMIIREG: /* Write MII register */
+			e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in);
+			break;
+		/* The ioctls below should be considered obsolete but are */
+		/* still present for compatability with old scripts/apps  */
+		case SET_ETH_SPEED_10:                  /* 10 Mbps */
+			e100_set_speed(dev, 10);
+			break;
+		case SET_ETH_SPEED_100:                /* 100 Mbps */
+			e100_set_speed(dev, 100);
+			break;
+		case SET_ETH_SPEED_AUTO:              /* Auto negotiate speed */
+			e100_set_speed(dev, 0);
+			break;
+		case SET_ETH_DUPLEX_HALF:              /* Half duplex. */
+			e100_set_duplex(dev, half);
+			break;
+		case SET_ETH_DUPLEX_FULL:              /* Full duplex. */
+			e100_set_duplex(dev, full);
+			break;
+		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
+			e100_set_duplex(dev, autoneg);
+			break;
+		default:
+			return -EINVAL;
+	}
+	spin_unlock(&np->lock);
+	return 0;
+}
+
+static int
+e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+		case ETHTOOL_GSET:
+		{
+			memset((void *) &ecmd, 0, sizeof (ecmd));
+			ecmd.supported =
+			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_EXTERNAL;
+			ecmd.phy_address = mdio_phy_addr;
+			ecmd.speed = current_speed;
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+			ecmd.advertising = ADVERTISED_TP;
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				ecmd.advertising |= ADVERTISED_Autoneg;
+			else {
+				ecmd.advertising |=
+				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+				if (current_speed_selection == 10)
+					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+				else if (current_speed_selection == 100)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+				if (current_duplex == half)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+				else if (current_duplex == full)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+			}
+			ecmd.autoneg = AUTONEG_ENABLE;
+			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_SSET:
+		{
+			if (!capable(CAP_NET_ADMIN)) {
+				return -EPERM;
+			}
+			if (ecmd.autoneg == AUTONEG_ENABLE) {
+				e100_set_duplex(dev, autoneg);
+				e100_set_speed(dev, 0);
+			} else {
+				e100_set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
+				e100_set_speed(dev, ecmd.speed == SPEED_10 ? 10: 100);
+			}
+		}
+		break;
+		case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info;
+			memset((void *) &info, 0, sizeof (info));
+			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
+			strncpy(info.version, "$Revision: 1.31 $", sizeof(info.version) - 1);
+			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+			info.regdump_len = 0;
+			info.eedump_len = 0;
+			info.testinfo_len = 0;
+			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_NWAY_RST:
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				e100_negotiate(dev);
+		break;
+		default:
+			return -EOPNOTSUPP;
+		break;
+	}
+	return 0;
+}
+
+static int
+e100_set_config(struct net_device *dev, struct ifmap *map)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+	spin_lock(&np->lock); /* Preempt protection */
+
+	switch(map->port) {
+		case IF_PORT_UNKNOWN:
+			/* Use autoneg */
+			e100_set_speed(dev, 0);
+			e100_set_duplex(dev, autoneg);
+			break;
+		case IF_PORT_10BASET:
+			e100_set_speed(dev, 10);
+			e100_set_duplex(dev, autoneg);
+			break;
+		case IF_PORT_100BASET:
+		case IF_PORT_100BASETX:
+			e100_set_speed(dev, 100);
+			e100_set_duplex(dev, autoneg);
+			break;
+		case IF_PORT_100BASEFX:
+		case IF_PORT_10BASE2:
+		case IF_PORT_AUI:
+			spin_unlock(&np->lock);
+			return -EOPNOTSUPP;
+			break;
+		default:
+			printk(KERN_ERR "%s: Invalid media selected", dev->name);
+			spin_unlock(&np->lock);
+			return -EINVAL;
+	}
+	spin_unlock(&np->lock);
+	return 0;
+}
+
+static void
+update_rx_stats(struct net_device_stats *es)
+{
+	unsigned long r = *R_REC_COUNTERS;
+	/* update stats relevant to reception errors */
+	es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r);
+	es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r);
+	es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r);
+	es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r);
+}
+
+static void
+update_tx_stats(struct net_device_stats *es)
+{
+	unsigned long r = *R_TR_COUNTERS;
+	/* update stats relevant to transmission errors */
+	es->collisions +=
+		IO_EXTRACT(R_TR_COUNTERS, single_col, r) +
+		IO_EXTRACT(R_TR_COUNTERS, multiple_col, r);
+	es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
+	spin_lock_irqsave(&lp->lock, flags);
+
+	update_rx_stats(&lp->stats);
+	update_tx_stats(&lp->stats);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int num_addr = dev->mc_count;
+	unsigned long int lo_bits;
+	unsigned long int hi_bits;
+	spin_lock(&lp->lock);
+	if (dev->flags & IFF_PROMISC)
+	{
+		/* promiscuous mode */
+		lo_bits = 0xfffffffful;
+		hi_bits = 0xfffffffful;
+
+		/* Enable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive);
+		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		/* enable all multicasts */
+		lo_bits = 0xfffffffful;
+		hi_bits = 0xfffffffful;
+
+		/* Disable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+		*R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
+	} else if (num_addr == 0) {
+		/* Normal, clear the mc list */
+		lo_bits = 0x00000000ul;
+		hi_bits = 0x00000000ul;
+
+		/* Disable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+		*R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
+	} else {
+		/* MC mode, receive normal and MC packets */
+		char hash_ix;
+		struct dev_mc_list *dmi = dev->mc_list;
+		int i;
+		char *baddr;
+		lo_bits = 0x00000000ul;
+		hi_bits = 0x00000000ul;
+		for (i=0; i<num_addr; i++) {
+			/* Calculate the hash index for the GA registers */
+
+			hash_ix = 0;
+			baddr = dmi->dmi_addr;
+			hash_ix ^= (*baddr) & 0x3f;
+			hash_ix ^= ((*baddr) >> 6) & 0x03;
+			++baddr;
+			hash_ix ^= ((*baddr) << 2) & 0x03c;
+			hash_ix ^= ((*baddr) >> 4) & 0xf;
+			++baddr;
+			hash_ix ^= ((*baddr) << 4) & 0x30;
+			hash_ix ^= ((*baddr) >> 2) & 0x3f;
+			++baddr;
+			hash_ix ^= (*baddr) & 0x3f;
+			hash_ix ^= ((*baddr) >> 6) & 0x03;
+			++baddr;
+			hash_ix ^= ((*baddr) << 2) & 0x03c;
+			hash_ix ^= ((*baddr) >> 4) & 0xf;
+			++baddr;
+			hash_ix ^= ((*baddr) << 4) & 0x30;
+			hash_ix ^= ((*baddr) >> 2) & 0x3f;
+
+			hash_ix &= 0x3f;
+
+			if (hash_ix >= 32) {
+				hi_bits |= (1 << (hash_ix-32));
+			}
+			else {
+				lo_bits |= (1 << hash_ix);
+			}
+			dmi = dmi->next;
+		}
+		/* Disable individual receive */
+		SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+	}
+	*R_NETWORK_GA_0 = lo_bits;
+	*R_NETWORK_GA_1 = hi_bits;
+	spin_unlock(&lp->lock);
+}
+
+void
+e100_hardware_send_packet(char *buf, int length)
+{
+	D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
+
+	if (!led_active && time_after(jiffies, led_next_time)) {
+		/* light the network leds depending on the current speed. */
+		e100_set_network_leds(NETWORK_ACTIVITY);
+
+		/* Set the earliest time we may clear the LED */
+		led_next_time = jiffies + NET_FLASH_TIME;
+		led_active = 1;
+		mod_timer(&clear_led_timer, jiffies + HZ/10);
+	}
+
+	/* configure the tx dma descriptor */
+	myNextTxDesc->descr.sw_len = length;
+	myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait;
+	myNextTxDesc->descr.buf = virt_to_phys(buf);
+
+        /* Move end of list */
+        myLastTxDesc->descr.ctrl &= ~d_eol;
+        myLastTxDesc = myNextTxDesc;
+
+	/* Restart DMA channel */
+	*R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart);
+}
+
+static void
+e100_clear_network_leds(unsigned long dummy)
+{
+	if (led_active && time_after(jiffies, led_next_time)) {
+		e100_set_network_leds(NO_NETWORK_ACTIVITY);
+
+		/* Set the earliest time we may set the LED */
+		led_next_time = jiffies + NET_FLASH_PAUSE;
+		led_active = 0;
+	}
+}
+
+static void
+e100_set_network_leds(int active)
+{
+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
+	int light_leds = (active == NO_NETWORK_ACTIVITY);
+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
+	int light_leds = (active == NETWORK_ACTIVITY);
+#else
+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
+#endif
+
+	if (!current_speed) {
+		/* Make LED red, link is down */
+#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
+		LED_NETWORK_SET(LED_RED);
+#else
+		LED_NETWORK_SET(LED_OFF);
+#endif
+	}
+	else if (light_leds) {
+		if (current_speed == 10) {
+			LED_NETWORK_SET(LED_ORANGE);
+		} else {
+			LED_NETWORK_SET(LED_GREEN);
+		}
+	}
+	else {
+		LED_NETWORK_SET(LED_OFF);
+	}
+}
+
+static int
+etrax_init_module(void)
+{
+	return etrax_ethernet_init();
+}
+
+static int __init
+e100_boot_setup(char* str)
+{
+	struct sockaddr sa = {0};
+	int i;
+
+	/* Parse the colon separated Ethernet station address */
+	for (i = 0; i <  ETH_ALEN; i++) {
+		unsigned int tmp;
+		if (sscanf(str + 3*i, "%2x", &tmp) != 1) {
+			printk(KERN_WARNING "Malformed station address");
+			return 0;
+		}
+		sa.sa_data[i] = (char)tmp;
+	}
+
+	default_mac = sa;
+	return 1;
+}
+
+__setup("etrax100_eth=", e100_boot_setup);
+
+module_init(etrax_init_module);
diff -puN /dev/null drivers/serial/crisv10.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/serial/crisv10.c	Mon Nov  8 14:19:37 2004
@@ -0,0 +1,5061 @@
+/* $Id: serial.c,v 1.25 2004/09/29 10:33:49 starvik Exp $
+ *
+ * Serial port driver for the ETRAX 100LX chip
+ *
+ *    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Axis Communications AB
+ *
+ *    Many, many authors. Based once upon a time on serial.c for 16x50.
+ *
+ * $Log: serial.c,v $
+ * Revision 1.25  2004/09/29 10:33:49  starvik
+ * Resolved a dealock when printing debug from kernel.
+ *
+ * Revision 1.24  2004/08/27 23:25:59  johana
+ * rs_set_termios() must call change_speed() if c_iflag has changed or
+ * automatic XOFF handling will be enabled and transmitter will stop
+ * if 0x13 is received.
+ *
+ * Revision 1.23  2004/08/24 06:57:13  starvik
+ * More whitespace cleanup
+ *
+ * Revision 1.22  2004/08/24 06:12:20  starvik
+ * Whitespace cleanup
+ *
+ * Revision 1.20  2004/05/24 12:00:20  starvik
+ * Big merge of stuff from Linux 2.4 (e.g. manual mode for the serial port).
+ *
+ * Revision 1.19  2004/05/17 13:12:15  starvik
+ * Kernel console hook
+ * Big merge from Linux 2.4 still pending.
+ *
+ * Revision 1.18  2003/10/28 07:18:30  starvik
+ * Compiles with debug info
+ *
+ * Revision 1.17  2003/07/04 08:27:37  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.16  2003/06/13 10:05:19  johana
+ * Help the user to avoid trouble by:
+ * Forcing mixed mode for status/control lines if not all pins are used.
+ *
+ * Revision 1.15  2003/06/13 09:43:01  johana
+ * Merged in the following changes from os/linux/arch/cris/drivers/serial.c
+ * + some minor changes to reduce diff.
+ *
+ * Revision 1.49  2003/05/30 11:31:54  johana
+ * Merged in change-branch--serial9bit that adds CMSPAR support for sticky
+ * parity (mark/space)
+ *
+ * Revision 1.48  2003/05/30 11:03:57  johana
+ * Implemented rs_send_xchar() by disabling the DMA and writing manually.
+ * Added e100_disable_txdma_channel() and e100_enable_txdma_channel().
+ * Fixed rs_throttle() and rs_unthrottle() to properly call rs_send_xchar
+ * instead of setting info->x_char and check the CRTSCTS flag before
+ * controlling the rts pin.
+ *
+ * Revision 1.14  2003/04/09 08:12:44  pkj
+ * Corrected typo changes made upstream.
+ *
+ * Revision 1.13  2003/04/09 05:20:47  starvik
+ * Merge of Linux 2.5.67
+ *
+ * Revision 1.11  2003/01/22 06:48:37  starvik
+ * Fixed warnings issued by GCC 3.2.1
+ *
+ * Revision 1.9  2002/12/13 09:07:47  starvik
+ * Alert user that RX_TIMEOUT_TICKS==0 doesn't work
+ *
+ * Revision 1.8  2002/12/11 13:13:57  starvik
+ * Added arch/ to v10 specific includes
+ * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+ *
+ * Revision 1.7  2002/12/06 07:13:57  starvik
+ * Corrected work queue stuff
+ * Removed CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+ *
+ * Revision 1.6  2002/11/21 07:17:46  starvik
+ * Change static inline to extern inline where otherwise outlined with gcc-3.2
+ *
+ * Revision 1.5  2002/11/14 15:59:49  starvik
+ * Linux 2.5 port of the latest serial driver from 2.4. The work queue stuff
+ * probably doesn't work yet.
+ *
+ * Revision 1.42  2002/11/05 09:08:47  johana
+ * Better implementation of rs_stop() and rs_start() that uses the XOFF
+ * register to start/stop transmission.
+ * change_speed() also initilises XOFF register correctly so that
+ * auto_xoff is enabled when IXON flag is set by user.
+ * This gives fast XOFF response times.
+ *
+ * Revision 1.41  2002/11/04 18:40:57  johana
+ * Implemented rs_stop() and rs_start().
+ * Simple tests using hwtestserial indicates that this should be enough
+ * to make it work.
+ *
+ * Revision 1.40  2002/10/14 05:33:18  starvik
+ * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
+ *
+ * Revision 1.39  2002/09/30 21:00:57  johana
+ * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
+ * control pins can be mixed between PA and PB.
+ * If no serial port uses MIXED old solution is used
+ * (saves a few bytes and cycles).
+ * control_pins struct uses masks instead of bit numbers.
+ * Corrected dummy values and polarity in line_info() so
+ * /proc/tty/driver/serial is now correct.
+ * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
+ *
+ * Revision 1.38  2002/08/23 11:01:36  starvik
+ * Check that serial port is enabled in all interrupt handlers to avoid
+ * restarts of DMA channels not assigned to serial ports
+ *
+ * Revision 1.37  2002/08/13 13:02:37  bjornw
+ * Removed some warnings because of unused code
+ *
+ * Revision 1.36  2002/08/08 12:50:01  starvik
+ * Serial interrupt is shared with synchronous serial port driver
+ *
+ * Revision 1.35  2002/06/03 10:40:49  starvik
+ * Increased RS-485 RTS toggle timer to 2 characters
+ *
+ * Revision 1.34  2002/05/28 18:59:36  johana
+ * Whitespace and comment fixing to be more like etrax100ser.c 1.71.
+ *
+ * Revision 1.33  2002/05/28 17:55:43  johana
+ * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time)
+ * timer from tranismit_chars (interrupt context).
+ * The timer toggles RTS in interrupt context when expired giving minimum
+ * latencies.
+ *
+ * Revision 1.32  2002/05/22 13:58:00  johana
+ * Renamed rs_write() to raw_write() and made it inline.
+ * New rs_write() handles RS-485 if configured and enabled
+ * (moved code from e100_write_rs485()).
+ * RS-485 ioctl's uses copy_from_user() instead of verify_area().
+ *
+ * Revision 1.31  2002/04/22 11:20:03  johana
+ * Updated copyright years.
+ *
+ * Revision 1.30  2002/04/22 09:39:12  johana
+ * RS-485 support compiles.
+ *
+ * Revision 1.29  2002/01/14 16:10:01  pkj
+ * Allocate the receive buffers dynamically. The static 4kB buffer was
+ * too small for the peaks. This means that we can get rid of the extra
+ * buffer and the copying to it. It also means we require less memory
+ * under normal operations, but can use more when needed (there is a
+ * cap at 64kB for safety reasons). If there is no memory available
+ * we panic(), and die a horrible death...
+ *
+ * Revision 1.28  2001/12/18 15:04:53  johana
+ * Cleaned up write_rs485() - now it works correctly without padding extra
+ * char.
+ * Added sane default initialisation of rs485.
+ * Added #ifdef around dummy variables.
+ *
+ * Revision 1.27  2001/11/29 17:00:41  pkj
+ * 2kB seems to be too small a buffer when using 921600 bps,
+ * so increase it to 4kB (this was already done for the elinux
+ * version of the serial driver).
+ *
+ * Revision 1.26  2001/11/19 14:20:41  pkj
+ * Minor changes to comments and unused code.
+ *
+ * Revision 1.25  2001/11/12 20:03:43  pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.24  2001/11/12 15:10:05  pkj
+ * Total redesign of the receiving part of the serial driver.
+ * Uses eight chained descriptors to write to a 4kB buffer.
+ * This data is then serialised into a 2kB buffer. From there it
+ * is copied into the TTY's flip buffers when they become available.
+ * A lot of copying, and the sizes of the buffers might need to be
+ * tweaked, but all in all it should work better than the previous
+ * version, without the need to modify the TTY code in any way.
+ * Also note that erroneous bytes are now correctly marked in the
+ * flag buffers (instead of always marking the first byte).
+ *
+ * Revision 1.23  2001/10/30 17:53:26  pkj
+ * * Set info->uses_dma to 0 when a port is closed.
+ * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT).
+ * * Call start_flush_timer() in start_receive() if
+ *   CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is defined.
+ *
+ * Revision 1.22  2001/10/30 17:44:03  pkj
+ * Use %lu for received and transmitted counters in line_info().
+ *
+ * Revision 1.21  2001/10/30 17:40:34  pkj
+ * Clean-up. The only change to functionality is that
+ * CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS(=5) is used instead of
+ * MAX_FLUSH_TIME(=8).
+ *
+ * Revision 1.20  2001/10/30 15:24:49  johana
+ * Added char_time stuff from 2.0 driver.
+ *
+ * Revision 1.19  2001/10/30 15:23:03  johana
+ * Merged with 1.13.2 branch + fixed indentation
+ * and changed CONFIG_ETRAX100_XYS to CONFIG_ETRAX_XYZ
+ *
+ * Revision 1.18  2001/09/24 09:27:22  pkj
+ * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud().
+ *
+ * Revision 1.17  2001/08/24 11:32:49  ronny
+ * More fixes for the CONFIG_ETRAX_SERIAL_PORT0 define.
+ *
+ * Revision 1.16  2001/08/24 07:56:22  ronny
+ * Added config ifdefs around ser0 irq requests.
+ *
+ * Revision 1.15  2001/08/16 09:10:31  bjarne
+ * serial.c - corrected the initialization of rs_table, the wrong defines
+ *            where used.
+ *            Corrected a test in timed_flush_handler.
+ *            Changed configured to enabled.
+ * serial.h - Changed configured to enabled.
+ *
+ * Revision 1.14  2001/08/15 07:31:23  bjarne
+ * Introduced two new members to the e100_serial struct.
+ * configured - Will be set to 1 if the port has been configured in .config
+ * uses_dma   - Should be set to 1 if the port uses DMA. Currently it is set
+ *              to 1
+ *              when a port is opened. This is used to limit the DMA interrupt
+ *              routines to only manipulate DMA channels actually used by the
+ *              serial driver.
+ *
+ * Revision 1.13.2.2  2001/10/17 13:57:13  starvik
+ * Receiver was broken by the break fixes
+ *
+ * Revision 1.13.2.1  2001/07/20 13:57:39  ronny
+ * Merge with new stuff from etrax100ser.c. Works but haven't checked stuff
+ * like break handling.
+ *
+ * Revision 1.13  2001/05/09 12:40:31  johana
+ * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
+ *
+ * Revision 1.12  2001/04/19 12:23:07  bjornw
+ * CONFIG_RS485 -> CONFIG_ETRAX_RS485
+ *
+ * Revision 1.11  2001/04/05 14:29:48  markusl
+ * Updated according to review remarks i.e.
+ * -Use correct types in port structure to avoid compiler warnings
+ * -Try to use IO_* macros whenever possible
+ * -Open should never return -EBUSY
+ *
+ * Revision 1.10  2001/03/05 13:14:07  bjornw
+ * Another spelling fix
+ *
+ * Revision 1.9  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.8  2001/01/23 14:56:35  markusl
+ * Made use of ser1 optional
+ * Needed by USB
+ *
+ * Revision 1.7  2001/01/19 16:14:48  perf
+ * Added kernel options for serial ports 234.
+ * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ.
+ *
+ * Revision 1.6  2000/11/22 16:36:09  bjornw
+ * Please marketing by using the correct case when spelling Etrax.
+ *
+ * Revision 1.5  2000/11/21 16:43:37  bjornw
+ * Fixed so it compiles under CONFIG_SVINTO_SIM
+ *
+ * Revision 1.4  2000/11/15 17:34:12  bjornw
+ * Added a timeout timer for flushing input channels. The interrupt-based
+ * fast flush system should be easy to merge with this later (works the same
+ * way, only with an irq instead of a system timer_list)
+ *
+ * Revision 1.3  2000/11/13 17:19:57  bjornw
+ * * Incredibly, this almost complete rewrite of serial.c worked (at least
+ *   for output) the first time.
+ *
+ *   Items worth noticing:
+ *
+ *      No Etrax100 port 1 workarounds (does only compile on 2.4 anyway now)
+ *      RS485 is not ported (why can't it be done in userspace as on x86 ?)
+ *      Statistics done through async_icount - if any more stats are needed,
+ *      that's the place to put them or in an arch-dep version of it.
+ *      timeout_interrupt and the other fast timeout stuff not ported yet
+ *      There be dragons in this 3k+ line driver
+ *
+ * Revision 1.2  2000/11/10 16:50:28  bjornw
+ * First shot at a 2.4 port, does not compile totally yet
+ *
+ * Revision 1.1  2000/11/10 16:47:32  bjornw
+ * Added verbatim copy of rev 1.49 etrax100ser.c from elinux
+ *
+ * Revision 1.49  2000/10/30 15:47:14  tobiasa
+ * Changed version number.
+ *
+ * Revision 1.48  2000/10/25 11:02:43  johana
+ * Changed %ul to %lu in printf's
+ *
+ * Revision 1.47  2000/10/18 15:06:53  pkj
+ * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and
+ * CONFIG_ETRAX_SERIAL_PROC_ENTRY together.
+ * Some clean-up of the /proc/serial file.
+ *
+ * Revision 1.46  2000/10/16 12:59:40  johana
+ * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info.
+ *
+ * Revision 1.45  2000/10/13 17:10:59  pkj
+ * Do not flush DMAs while flipping TTY buffers.
+ *
+ * Revision 1.44  2000/10/13 16:34:29  pkj
+ * Added a delay in ser_interrupt() for 2.3ms when an error is detected.
+ * We do not know why this delay is required yet, but without it the
+ * irmaflash program does not work (this was the program that needed
+ * the ser_interrupt() to be needed in the first place). This should not
+ * affect normal use of the serial ports.
+ *
+ * Revision 1.43  2000/10/13 16:30:44  pkj
+ * New version of the fast flush of serial buffers code. This time
+ * it is localized to the serial driver and uses a fast timer to
+ * do the work.
+ *
+ * Revision 1.42  2000/10/13 14:54:26  bennyo
+ * Fix for switching RTS when using rs485
+ *
+ * Revision 1.41  2000/10/12 11:43:44  pkj
+ * Cleaned up a number of comments.
+ *
+ * Revision 1.40  2000/10/10 11:58:39  johana
+ * Made RS485 support generic for all ports.
+ * Toggle rts in interrupt if no delay wanted.
+ * WARNING: No true transmitter empty check??
+ * Set d_wait bit when sending data so interrupt is delayed until
+ * fifo flushed. (Fix tcdrain() problem)
+ *
+ * Revision 1.39  2000/10/04 16:08:02  bjornw
+ * * Use virt_to_phys etc. for DMA addresses
+ * * Removed CONFIG_FLUSH_DMA_FAST hacks
+ * * Indentation fix
+ *
+ * Revision 1.38  2000/10/02 12:27:10  mattias
+ * * added variable used when using fast flush on serial dma.
+ *   (CONFIG_FLUSH_DMA_FAST)
+ *
+ * Revision 1.37  2000/09/27 09:44:24  pkj
+ * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
+ *
+ * Revision 1.36  2000/09/20 13:12:52  johana
+ * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS:
+ *   Number of timer ticks between flush of receive fifo (1 tick = 10ms).
+ *   Try 0-3 for low latency applications. Approx 5 for high load
+ *   applications (e.g. PPP). Maybe this should be more adaptive some day...
+ *
+ * Revision 1.35  2000/09/20 10:36:08  johana
+ * Typo in get_lsr_info()
+ *
+ * Revision 1.34  2000/09/20 10:29:59  johana
+ * Let rs_chars_in_buffer() check fifo content as well.
+ * get_lsr_info() might work now (not tested).
+ * Easier to change the port to debug.
+ *
+ * Revision 1.33  2000/09/13 07:52:11  torbjore
+ * Support RS485
+ *
+ * Revision 1.32  2000/08/31 14:45:37  bjornw
+ * After sending a break we need to reset the transmit DMA channel
+ *
+ * Revision 1.31  2000/06/21 12:13:29  johana
+ * Fixed wait for all chars sent when closing port.
+ * (Used to always take 1 second!)
+ * Added shadows for directions of status/ctrl signals.
+ *
+ * Revision 1.30  2000/05/29 16:27:55  bjornw
+ * Simulator ifdef moved a bit
+ *
+ * Revision 1.29  2000/05/09 09:40:30  mattias
+ * * Added description of dma registers used in timeout_interrupt
+ * * Removed old code
+ *
+ * Revision 1.28  2000/05/08 16:38:58  mattias
+ * * Bugfix for flushing fifo in timeout_interrupt
+ *   Problem occurs when bluetooth stack waits for a small number of bytes
+ *   containing an event acknowledging free buffers in bluetooth HW
+ *   As before, data was stuck in fifo until more data came on uart and
+ *   flushed it up to the stack.
+ *
+ * Revision 1.27  2000/05/02 09:52:28  jonasd
+ * Added fix for peculiar etrax behaviour when eop is forced on an empty
+ * fifo. This is used when flashing the IRMA chip. Disabled by default.
+ *
+ * Revision 1.26  2000/03/29 15:32:02  bjornw
+ * 2.0.34 updates
+ *
+ * Revision 1.25  2000/02/16 16:59:36  bjornw
+ * * Receive DMA directly into the flip-buffer, eliminating an intermediary
+ *   receive buffer and a memcpy. Will avoid some overruns.
+ * * Error message on debug port if an overrun or flip buffer overrun occurs.
+ * * Just use the first byte in the flag flip buffer for errors.
+ * * Check for timeout on the serial ports only each 5/100 s, not 1/100.
+ *
+ * Revision 1.24  2000/02/09 18:02:28  bjornw
+ * * Clear serial errors (overrun, framing, parity) correctly. Before, the
+ *   receiver would get stuck if an error occurred and we did not restart
+ *   the input DMA.
+ * * Cosmetics (indentation, some code made into inlines)
+ * * Some more debug options
+ * * Actually shut down the serial port (DMA irq, DMA reset, receiver stop)
+ *   when the last open is closed. Corresponding fixes in startup().
+ * * rs_close() "tx FIFO wait" code moved into right place, bug & -> && fixed
+ *   and make a special case out of port 1 (R_DMA_CHx_STATUS is broken for that)
+ * * e100_disable_rx/enable_rx just disables/enables the receiver, not RTS
+ *
+ * Revision 1.23  2000/01/24 17:46:19  johana
+ * Wait for flush of DMA/FIFO when closing port.
+ *
+ * Revision 1.22  2000/01/20 18:10:23  johana
+ * Added TIOCMGET ioctl to return modem status.
+ * Implemented modem status/control that works with the extra signals
+ * (DTR, DSR, RI,CD) as well.
+ * 3 different modes supported:
+ * ser0 on PB (Bundy), ser1 on PB (Lisa) and ser2 on PA (Bundy)
+ * Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when
+ * closing the last filehandle, NASTY!.
+ * Added break generation, not tested though!
+ * Use SA_SHIRQ when request_irq() for ser2 and ser3 (shared with) par0 and par1.
+ * You can't use them at the same time (yet..), but you can hopefully switch
+ * between ser2/par0, ser3/par1 with the same kernel config.
+ * Replaced some magic constants with defines
+ *
+ *
+ */
+
+static char *serial_version = "$Revision: 1.25 $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <linux/delay.h>
+
+#include <asm/arch/svinto.h>
+
+/* non-arch dependent serial structures are in linux/serial.h */
+#include <linux/serial.h>
+/* while we keep our own stuff (struct e100_serial) in a local .h file */
+#include "serial.h"
+#include <asm/fasttimer.h>
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifndef CONFIG_ETRAX_FAST_TIMER
+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
+#endif
+#endif
+
+#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
+           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
+#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
+#endif
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
+#endif
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS)
+#include "serial_compat.h"
+#endif
+
+#define _INLINE_ inline
+
+struct tty_driver *serial_driver;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL	1
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+//#define SERIAL_DEBUG_INTR
+//#define SERIAL_DEBUG_OPEN
+//#define SERIAL_DEBUG_FLOW
+//#define SERIAL_DEBUG_DATA
+//#define SERIAL_DEBUG_THROTTLE
+//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
+//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
+
+/* Enable this to use serial interrupts to handle when you
+   expect the first received event on the serial port to
+   be an error, break or similar. Used to be able to flash IRMA
+   from eLinux */
+#define SERIAL_HANDLE_EARLY_ERRORS
+
+/* Defined and used in n_tty.c, but we need it here as well */
+#define TTY_THRESHOLD_THROTTLE 128
+
+/* Due to buffersizes and threshold values, our SERIAL_DESCR_BUF_SIZE
+ * must not be to high or flow control won't work if we leave it to the tty
+ * layer so we have our own throttling in flush_to_flip
+ * TTY_FLIPBUF_SIZE=512,
+ * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128
+ * BUF_SIZE can't be > 128
+ */
+/* Currently 16 descriptors x 128 bytes = 2048 bytes */
+#define SERIAL_DESCR_BUF_SIZE 256
+
+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
+
+/* We don't want to load the system with massive fast timer interrupt
+ * on high baudrates so limit it to 250 us (4kHz) */
+#define MIN_FLUSH_TIME_USEC 250
+
+/* Add an x here to log a lot of timer stuff */
+#define TIMERD(x)
+/* Debug details of interrupt handling */
+#define DINTR1(x)  /* irq on/off, errors */
+#define DINTR2(x)    /* tx and rx */
+/* Debug flip buffer stuff */
+#define DFLIP(x)
+/* Debug flow control and overview of data flow */
+#define DFLOW(x)
+#define DBAUD(x)
+#define DLOG_INT_TRIG(x)
+
+//#define DEBUG_LOG_INCLUDED
+#ifndef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG(line, string, value)
+#else
+struct debug_log_info
+{
+	unsigned long time;
+	unsigned long timer_data;
+//  int line;
+	const char *string;
+	int value;
+};
+#define DEBUG_LOG_SIZE 4096
+
+struct debug_log_info debug_log[DEBUG_LOG_SIZE];
+int debug_log_pos = 0;
+
+#define DEBUG_LOG(_line, _string, _value) do { \
+  if ((_line) == SERIAL_DEBUG_LINE) {\
+    debug_log_func(_line, _string, _value); \
+  }\
+}while(0)
+
+void debug_log_func(int line, const char *string, int value)
+{
+	if (debug_log_pos < DEBUG_LOG_SIZE) {
+		debug_log[debug_log_pos].time = jiffies;
+		debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
+//    debug_log[debug_log_pos].line = line;
+		debug_log[debug_log_pos].string = string;
+		debug_log[debug_log_pos].value = value;
+		debug_log_pos++;
+	}
+	/*printk(string, value);*/
+}
+#endif
+
+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
+/* Default number of timer ticks before flushing rx fifo
+ * When using "little data, low latency applications: use 0
+ * When using "much data applications (PPP)" use ~5
+ */
+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
+#endif
+
+unsigned long timer_data_to_ns(unsigned long timer_data);
+
+static void change_speed(struct e100_serial *info);
+static void rs_throttle(struct tty_struct * tty);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+static int rs_write(struct tty_struct * tty, int from_user,
+                    const unsigned char *buf, int count);
+extern _INLINE_ int rs_raw_write(struct tty_struct * tty, int from_user,
+                            const unsigned char *buf, int count);
+#ifdef CONFIG_ETRAX_RS485
+static int e100_write_rs485(struct tty_struct * tty, int from_user,
+                            const unsigned char *buf, int count);
+#endif
+static int get_lsr_info(struct e100_serial * info, unsigned int *value);
+
+
+#define DEF_BAUD 115200   /* 115.2 kbit/s */
+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
+#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
+
+/* offsets from R_SERIALx_CTRL */
+
+#define REG_DATA 0
+#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
+#define REG_TR_DATA 0
+#define REG_STATUS 1
+#define REG_TR_CTRL 1
+#define REG_REC_CTRL 2
+#define REG_BAUD 3
+#define REG_XOFF 4  /* this is a 32 bit register */
+
+/* The bitfields are the same for all serial ports */
+#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
+#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
+#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
+#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
+#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
+
+#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
+
+/* Values for info->errorcode */
+#define ERRCODE_SET_BREAK    (TTY_BREAK)
+#define ERRCODE_INSERT        0x100
+#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
+
+#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
+
+/*
+ * General note regarding the use of IO_* macros in this file:
+ *
+ * We will use the bits defined for DMA channel 6 when using various
+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
+ * the same for all channels (which of course they are).
+ *
+ * We will also use the bits defined for serial port 0 when writing commands
+ * to the different ports, as these bits too are the same for all ports.
+ */
+
+
+/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
+static const unsigned long e100_ser_int_mask = 0
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
+#endif
+;
+unsigned long r_alt_ser_baudrate_shadow = 0;
+
+/* this is the data for the four serial ports in the etrax100 */
+/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
+
+static struct e100_serial rs_table[] = {
+	{ .baud        = DEF_BAUD,
+	  .port        = (unsigned char *)R_SERIAL0_CTRL,
+	  .irq         = 1U << 12, /* uses DMA 6 and 7 */
+	  .oclrintradr = R_DMA_CH6_CLR_INTR,
+	  .ofirstadr   = R_DMA_CH6_FIRST,
+	  .ocmdadr     = R_DMA_CH6_CMD,
+	  .ostatusadr  = R_DMA_CH6_STATUS,
+	  .iclrintradr = R_DMA_CH7_CLR_INTR,
+	  .ifirstadr   = R_DMA_CH7_FIRST,
+	  .icmdadr     = R_DMA_CH7_CMD,
+	  .idescradr   = R_DMA_CH7_DESCR,
+	  .flags       = STD_FLAGS,
+	  .rx_ctrl     = DEF_RX,
+	  .tx_ctrl     = DEF_TX,
+	  .iseteop     = 2,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+	  .dma_out_enabled = 1,
+#else
+	  .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+	  .dma_in_enabled = 1,
+#else
+	  .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+	  .dma_out_enabled = 0,
+	  .dma_in_enabled = 0
+#endif
+
+},  /* ttyS0 */
+#ifndef CONFIG_SVINTO_SIM
+	{ .baud        = DEF_BAUD,
+	  .port        = (unsigned char *)R_SERIAL1_CTRL,
+	  .irq         = 1U << 16, /* uses DMA 8 and 9 */
+	  .oclrintradr = R_DMA_CH8_CLR_INTR,
+	  .ofirstadr   = R_DMA_CH8_FIRST,
+	  .ocmdadr     = R_DMA_CH8_CMD,
+	  .ostatusadr  = R_DMA_CH8_STATUS,
+	  .iclrintradr = R_DMA_CH9_CLR_INTR,
+	  .ifirstadr   = R_DMA_CH9_FIRST,
+	  .icmdadr     = R_DMA_CH9_CMD,
+	  .idescradr   = R_DMA_CH9_DESCR,
+	  .flags       = STD_FLAGS,
+	  .rx_ctrl     = DEF_RX,
+	  .tx_ctrl     = DEF_TX,
+	  .iseteop     = 3,
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+	  .dma_out_enabled = 1,
+#else
+	  .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+	  .dma_in_enabled = 1,
+#else
+	  .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+	  .dma_out_enabled = 0,
+	  .dma_in_enabled = 0
+#endif
+},  /* ttyS1 */
+
+	{ .baud        = DEF_BAUD,
+	  .port        = (unsigned char *)R_SERIAL2_CTRL,
+	  .irq         = 1U << 4,  /* uses DMA 2 and 3 */
+	  .oclrintradr = R_DMA_CH2_CLR_INTR,
+	  .ofirstadr   = R_DMA_CH2_FIRST,
+	  .ocmdadr     = R_DMA_CH2_CMD,
+	  .ostatusadr  = R_DMA_CH2_STATUS,
+	  .iclrintradr = R_DMA_CH3_CLR_INTR,
+	  .ifirstadr   = R_DMA_CH3_FIRST,
+	  .icmdadr     = R_DMA_CH3_CMD,
+	  .idescradr   = R_DMA_CH3_DESCR,
+	  .flags       = STD_FLAGS,
+	  .rx_ctrl     = DEF_RX,
+	  .tx_ctrl     = DEF_TX,
+	  .iseteop     = 0,
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+	  .dma_out_enabled = 1,
+#else
+	  .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+	  .dma_in_enabled = 1,
+#else
+	  .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+	  .dma_out_enabled = 0,
+	  .dma_in_enabled = 0
+#endif
+ },  /* ttyS2 */
+
+	{ .baud        = DEF_BAUD,
+	  .port        = (unsigned char *)R_SERIAL3_CTRL,
+	  .irq         = 1U << 8,  /* uses DMA 4 and 5 */
+	  .oclrintradr = R_DMA_CH4_CLR_INTR,
+	  .ofirstadr   = R_DMA_CH4_FIRST,
+	  .ocmdadr     = R_DMA_CH4_CMD,
+	  .ostatusadr  = R_DMA_CH4_STATUS,
+	  .iclrintradr = R_DMA_CH5_CLR_INTR,
+	  .ifirstadr   = R_DMA_CH5_FIRST,
+	  .icmdadr     = R_DMA_CH5_CMD,
+	  .idescradr   = R_DMA_CH5_DESCR,
+	  .flags       = STD_FLAGS,
+	  .rx_ctrl     = DEF_RX,
+	  .tx_ctrl     = DEF_TX,
+	  .iseteop     = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+	  .dma_out_enabled = 1,
+#else
+	  .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+	  .dma_in_enabled = 1,
+#else
+	  .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+	  .dma_out_enabled = 0,
+	  .dma_in_enabled = 0
+#endif
+ }   /* ttyS3 */
+#endif
+};
+
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
+
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static struct fast_timer fast_timers[NR_PORTS];
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
+#define PROCSTAT(x) x
+struct ser_statistics_type {
+	int overrun_cnt;
+	int early_errors_cnt;
+	int ser_ints_ok_cnt;
+	int errors_cnt;
+	unsigned long int processing_flip;
+	unsigned long processing_flip_still_room;
+	unsigned long int timeout_flush_cnt;
+	int rx_dma_ints;
+	int tx_dma_ints;
+	int rx_tot;
+	int tx_tot;
+};
+
+static struct ser_statistics_type ser_stat[NR_PORTS];
+
+#else
+
+#define PROCSTAT(x)
+
+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
+
+/* RS-485 */
+#if defined(CONFIG_ETRAX_RS485)
+#ifdef CONFIG_ETRAX_FAST_TIMER
+static struct fast_timer fast_timers_rs485[NR_PORTS];
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
+#endif
+#endif
+
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(R_PORT_PB_DATA):&dummy_ser[line]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+/* If not all status pins are used or disabled, use mixed mode */
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+
+#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
+
+#if SER0_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
+
+#if SER0_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT0 */
+
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+
+#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
+
+#if SER1_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
+
+#if SER1_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT1 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+
+#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
+
+#if SER2_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
+
+#if SER2_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT2 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+
+#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
+
+#if SER3_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
+
+#if SER3_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT3 */
+
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+	volatile unsigned char *dtr_port;
+	unsigned char          *dtr_shadow;
+	volatile unsigned char *ri_port;
+	unsigned char          *ri_shadow;
+	volatile unsigned char *dsr_port;
+	unsigned char          *dsr_shadow;
+	volatile unsigned char *cd_port;
+	unsigned char          *cd_shadow;
+
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+	/* Ser 0 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+	E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+	E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+	},
+
+	/* Ser 1 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+	E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+	E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+	},
+
+	/* Ser 2 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+	E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+	E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+	},
+
+	/* Ser 3 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+	E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+	E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+	}
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+	volatile unsigned char *port;
+	unsigned char          *shadow;
+
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
+};
+
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+	/* Ser 0 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+	},
+
+	/* Ser 1 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+	},
+
+	/* Ser 2 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+	},
+
+	/* Ser 3 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+	}
+};
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+#define E100_RTS_MASK 0x20
+#define E100_CTS_MASK 0x40
+
+/* All serial port signals are active low:
+ * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
+ * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
+ *
+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
+ */
+
+/* Output */
+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
+/* Input */
+#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK)
+
+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
+/* Is an output */
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
+
+/* Normally inputs */
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
+
+/* Input */
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
+
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+/* Calculate the chartime depending on baudrate, numbor of bits etc. */
+static void update_char_time(struct e100_serial * info)
+{
+	tcflag_t cflags = info->tty->termios->c_cflag;
+	int bits;
+
+	/* calc. number of bits / data byte */
+	/* databits + startbit and 1 stopbit */
+	if ((cflags & CSIZE) == CS7)
+		bits = 9;
+	else
+		bits = 10;
+
+	if (cflags & CSTOPB)     /* 2 stopbits ? */
+		bits++;
+
+	if (cflags & PARENB)     /* parity bit ? */
+		bits++;
+
+	/* calc timeout */
+	info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
+	info->flush_time_usec = 4*info->char_time_usec;
+	if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
+		info->flush_time_usec = MIN_FLUSH_TIME_USEC;
+
+}
+
+/*
+ * This function maps from the Bxxxx defines in asm/termbits.h into real
+ * baud rates.
+ */
+
+static int
+cflag_to_baud(unsigned int cflag)
+{
+	static int baud_table[] = {
+		0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+		4800, 9600, 19200, 38400 };
+
+	static int ext_baud_table[] = {
+		0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
+                0, 0, 0, 0, 0, 0, 0, 0 };
+
+	if (cflag & CBAUDEX)
+		return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+	else
+		return baud_table[cflag & CBAUD];
+}
+
+/* and this maps to an etrax100 hardware baud constant */
+
+static unsigned char
+cflag_to_etrax_baud(unsigned int cflag)
+{
+	char retval;
+
+	static char baud_table[] = {
+		-1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
+
+	static char ext_baud_table[] = {
+		-1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+	if (cflag & CBAUDEX)
+		retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+	else
+		retval = baud_table[cflag & CBAUD];
+
+	if (retval < 0) {
+		printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
+		retval = 5; /* choose default 9600 instead */
+	}
+
+	return retval | (retval << 4); /* choose same for both TX and RX */
+}
+
+
+/* Various static support functions */
+
+/* Functions to set or clear DTR/RTS on the requested line */
+/* It is complicated by the fact that RTS is a serial port register, while
+ * DTR might not be implemented in the HW at all, and if it is, it can be on
+ * any general port.
+ */
+
+
+static inline void
+e100_dtr(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+	unsigned char mask = e100_modem_pins[info->line].dtr_mask;
+
+#ifdef SERIAL_DEBUG_IO
+	printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
+	printk("ser%i shadow before 0x%02X get: %i\n",
+	       info->line, *e100_modem_pins[info->line].dtr_shadow,
+	       E100_DTR_GET(info));
+#endif
+	/* DTR is active low */
+	{
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		*e100_modem_pins[info->line].dtr_shadow &= ~mask;
+		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
+		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
+		restore_flags(flags);
+	}
+
+#ifdef SERIAL_DEBUG_IO
+	printk("ser%i shadow after 0x%02X get: %i\n",
+	       info->line, *e100_modem_pins[info->line].dtr_shadow,
+	       E100_DTR_GET(info));
+#endif
+#endif
+}
+
+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ *                                          0=0V    , 1=3.3V
+ */
+static inline void
+e100_rts(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	info->rx_ctrl &= ~E100_RTS_MASK;
+	info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
+	info->port[REG_REC_CTRL] = info->rx_ctrl;
+	restore_flags(flags);
+#ifdef SERIAL_DEBUG_IO
+	printk("ser%i rts %i\n", info->line, set);
+#endif
+#endif
+}
+
+
+/* If this behaves as a modem, RI and CD is an output */
+static inline void
+e100_ri_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+	/* RI is active low */
+	{
+		unsigned char mask = e100_modem_pins[info->line].ri_mask;
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		*e100_modem_pins[info->line].ri_shadow &= ~mask;
+		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
+		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
+		restore_flags(flags);
+	}
+#endif
+}
+static inline void
+e100_cd_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+	/* CD is active low */
+	{
+		unsigned char mask = e100_modem_pins[info->line].cd_mask;
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		*e100_modem_pins[info->line].cd_shadow &= ~mask;
+		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
+		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
+		restore_flags(flags);
+	}
+#endif
+}
+
+static inline void
+e100_disable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+	/* disable the receiver */
+	info->port[REG_REC_CTRL] =
+		(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+static inline void
+e100_enable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+	/* enable the receiver */
+	info->port[REG_REC_CTRL] =
+		(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
+
+static inline void
+e100_disable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("rxdma_irq(%d): 0\n",info->line);
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
+	*R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
+}
+
+static inline void
+e100_enable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("rxdma_irq(%d): 1\n",info->line);
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
+	*R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
+}
+
+/* the tx DMA uses only dma_descr interrupt */
+
+static _INLINE_ void
+e100_disable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("txdma_irq(%d): 0\n",info->line);
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
+	*R_IRQ_MASK2_CLR = info->irq;
+}
+
+static _INLINE_ void
+e100_enable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("txdma_irq(%d): 1\n",info->line);
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
+	*R_IRQ_MASK2_SET = info->irq;
+}
+
+static _INLINE_ void
+e100_disable_txdma_channel(struct e100_serial *info)
+{
+	unsigned long flags;
+
+	/* Disable output DMA channel for the serial port in question
+	 * ( set to something other then serialX)
+	 */
+	save_flags(flags);
+	cli();
+	DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
+	if (info->line == 0) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
+		    IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
+		}
+	} else if (info->line == 1) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
+		    IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
+		}
+	} else if (info->line == 2) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
+		    IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
+		}
+	} else if (info->line == 3) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
+		    IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
+		}
+	}
+	*R_GEN_CONFIG = genconfig_shadow;
+	restore_flags(flags);
+}
+
+
+static _INLINE_ void
+e100_enable_txdma_channel(struct e100_serial *info)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
+	/* Enable output DMA channel for the serial port in question */
+	if (info->line == 0) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
+	} else if (info->line == 1) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
+	} else if (info->line == 2) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
+	} else if (info->line == 3) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
+	}
+	*R_GEN_CONFIG = genconfig_shadow;
+	restore_flags(flags);
+}
+
+static _INLINE_ void
+e100_disable_rxdma_channel(struct e100_serial *info)
+{
+	unsigned long flags;
+
+	/* Disable input DMA channel for the serial port in question
+	 * ( set to something other then serialX)
+	 */
+	save_flags(flags);
+	cli();
+	if (info->line == 0) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
+		    IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
+		}
+	} else if (info->line == 1) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
+		    IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
+		}
+	} else if (info->line == 2) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
+		    IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
+		}
+	} else if (info->line == 3) {
+		if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
+		    IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
+			genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+			genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
+		}
+	}
+	*R_GEN_CONFIG = genconfig_shadow;
+	restore_flags(flags);
+}
+
+
+static _INLINE_ void
+e100_enable_rxdma_channel(struct e100_serial *info)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	/* Enable input DMA channel for the serial port in question */
+	if (info->line == 0) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
+	} else if (info->line == 1) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
+	} else if (info->line == 2) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
+	} else if (info->line == 3) {
+		genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
+	}
+	*R_GEN_CONFIG = genconfig_shadow;
+	restore_flags(flags);
+}
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+/* in order to detect and fix errors on the first byte
+   we have to use the serial interrupts as well. */
+
+static inline void
+e100_disable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("ser_irq(%d): 0\n",info->line);
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
+	*R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
+}
+
+static inline void
+e100_enable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("ser_irq(%d): 1\n",info->line);
+	printk("**** %d = %d\n",
+	       (8+2*info->line),
+	       (1U << (8+2*info->line)));
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
+	*R_IRQ_MASK1_SET = (1U << (8+2*info->line));
+}
+#endif
+
+static inline void
+e100_disable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("ser_tx_irq(%d): 0\n",info->line);
+#endif
+	DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
+	*R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
+}
+
+static inline void
+e100_enable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+	printk("ser_tx_irq(%d): 1\n",info->line);
+	printk("**** %d = %d\n",
+	       (8+1+2*info->line),
+	       (1U << (8+1+2*info->line)));
+#endif
+	DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
+	*R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
+}
+
+static inline void e100_enable_rx_irq(struct e100_serial *info)
+{
+	if (info->uses_dma_in)
+		e100_enable_rxdma_irq(info);
+	else
+		e100_enable_serial_data_irq(info);
+}
+static inline void e100_disable_rx_irq(struct e100_serial *info)
+{
+	if (info->uses_dma_in)
+		e100_disable_rxdma_irq(info);
+	else
+		e100_disable_serial_data_irq(info);
+}
+
+#if defined(CONFIG_ETRAX_RS485)
+/* Enable RS-485 mode on selected port. This is UGLY. */
+static int
+e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
+{
+	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+	*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+	REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
+		       rs485_port_g_bit, 1);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+		       CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
+	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+		       CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
+#endif
+
+	info->rs485.rts_on_send = 0x01 & r->rts_on_send;
+	info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
+	if (r->delay_rts_before_send >= 1000)
+		info->rs485.delay_rts_before_send = 1000;
+	else
+		info->rs485.delay_rts_before_send = r->delay_rts_before_send;
+	info->rs485.enabled = r->enabled;
+/*	printk("rts: on send = %i, after = %i, enabled = %i",
+		    info->rs485.rts_on_send,
+		    info->rs485.rts_after_sent,
+		    info->rs485.enabled
+	);
+*/
+	return 0;
+}
+
+static int
+e100_write_rs485(struct tty_struct *tty, int from_user,
+                 const unsigned char *buf, int count)
+{
+	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+	int old_enabled = info->rs485.enabled;
+
+	/* rs485 is always implicitly enabled if we're using the ioctl()
+	 * but it doesn't have to be set in the rs485_control
+	 * (to be backward compatible with old apps)
+	 * So we store, set and restore it.
+	 */
+	info->rs485.enabled = 1;
+	/* rs_write now deals with RS485 if enabled */
+	count = rs_write(tty, from_user, buf, count);
+	info->rs485.enabled = old_enabled;
+	return count;
+}
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+/* Timer function to toggle RTS when using FAST_TIMER */
+static void rs485_toggle_rts_timer_function(unsigned long data)
+{
+	struct e100_serial *info = (struct e100_serial *)data;
+
+	fast_timers_rs485[info->line].function = NULL;
+	e100_rts(info, info->rs485.rts_after_sent);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+	e100_enable_rx(info);
+	e100_enable_rx_irq(info);
+#endif
+}
+#endif
+#endif /* CONFIG_ETRAX_RS485 */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void
+rs_stop(struct tty_struct *tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+
+		save_flags(flags); cli();
+		DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
+				CIRC_CNT(info->xmit.head,
+					 info->xmit.tail,SERIAL_XMIT_SIZE)));
+
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		restore_flags(flags);
+	}
+}
+
+static void
+rs_start(struct tty_struct *tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+
+		save_flags(flags); cli();
+		DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
+				CIRC_CNT(info->xmit.head,
+					 info->xmit.tail,SERIAL_XMIT_SIZE)));
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		if (!info->uses_dma_out &&
+		    info->xmit.head != info->xmit.tail && info->xmit.buf)
+			e100_enable_serial_tx_ready_irq(info);
+
+		restore_flags(flags);
+	}
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void
+rs_sched_event(struct e100_serial *info,
+				    int event)
+{
+	if (info->event & (1 << event))
+		return;
+	info->event |= 1 << event;
+	schedule_work(&info->work);
+}
+
+/* The output DMA channel is free - use it to send as many chars as possible
+ * NOTES:
+ *   We don't pay attention to info->x_char, which means if the TTY wants to
+ *   use XON/XOFF it will set info->x_char but we won't send any X char!
+ *
+ *   To implement this, we'd just start a DMA send of 1 byte pointing at a
+ *   buffer containing the X char, and skip updating xmit. We'd also have to
+ *   check if the last sent char was the X char when we enter this function
+ *   the next time, to avoid updating xmit with the sent X value.
+ */
+
+static void
+transmit_chars_dma(struct e100_serial *info)
+{
+	unsigned int c, sentl;
+	struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+	/* This will output too little if tail is not 0 always since
+	 * we don't reloop to send the other part. Anyway this SHOULD be a
+	 * no-op - transmit_chars_dma would never really be called during sim
+	 * since rs_write does not write into the xmit buffer then.
+	 */
+	if (info->xmit.tail)
+		printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
+	if (info->xmit.head != info->xmit.tail) {
+		SIMCOUT(info->xmit.buf + info->xmit.tail,
+			CIRC_CNT(info->xmit.head,
+				 info->xmit.tail,
+				 SERIAL_XMIT_SIZE));
+		info->xmit.head = info->xmit.tail;  /* move back head */
+		info->tr_running = 0;
+	}
+	return;
+#endif
+	/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+	*info->oclrintradr =
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+#ifdef SERIAL_DEBUG_INTR
+	if (info->line == SERIAL_DEBUG_LINE)
+		printk("tc\n");
+#endif
+	if (!info->tr_running) {
+		/* weirdo... we shouldn't get here! */
+		printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
+		return;
+	}
+
+	descr = &info->tr_descr;
+
+	/* first get the amount of bytes sent during the last DMA transfer,
+	   and update xmit accordingly */
+
+	/* if the stop bit was not set, all data has been sent */
+	if (!(descr->status & d_stop)) {
+		sentl = descr->sw_len;
+	} else
+		/* otherwise we find the amount of data sent here */
+		sentl = descr->hw_len;
+
+	DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
+
+	/* update stats */
+	info->icount.tx += sentl;
+
+	/* update xmit buffer */
+	info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
+
+	/* if there is only a few chars left in the buf, wake up the blocked
+	   write if any */
+	if (CIRC_CNT(info->xmit.head,
+		     info->xmit.tail,
+		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+	/* find out the largest amount of consecutive bytes we want to send now */
+
+	c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+
+	/* Don't send all in one DMA transfer - divide it so we wake up
+	 * application before all is sent
+	 */
+
+	if (c >= 4*WAKEUP_CHARS)
+		c = c/2;
+
+	if (c <= 0) {
+		/* our job here is done, don't schedule any new DMA transfer */
+		info->tr_running = 0;
+
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+		if (info->rs485.enabled) {
+			/* Set a short timer to toggle RTS */
+			start_one_shot_timer(&fast_timers_rs485[info->line],
+			                     rs485_toggle_rts_timer_function,
+			                     (unsigned long)info,
+			                     info->char_time_usec*2,
+			                     "RS-485");
+		}
+#endif /* RS485 */
+		return;
+	}
+
+	/* ok we can schedule a dma send of c chars starting at info->xmit.tail */
+	/* set up the descriptor correctly for output */
+	DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
+	descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
+	descr->sw_len = c;
+	descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
+	descr->status = 0;
+
+	*info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
+	*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+	/* DMA is now running (hopefully) */
+} /* transmit_chars_dma */
+
+static void
+start_transmit(struct e100_serial *info)
+{
+#if 0
+	if (info->line == SERIAL_DEBUG_LINE)
+		printk("x\n");
+#endif
+
+	info->tr_descr.sw_len = 0;
+	info->tr_descr.hw_len = 0;
+	info->tr_descr.status = 0;
+	info->tr_running = 1;
+	if (info->uses_dma_out)
+		transmit_chars_dma(info);
+	else
+		e100_enable_serial_tx_ready_irq(info);
+} /* start_transmit */
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static int serial_fast_timer_started = 0;
+static int serial_fast_timer_expired = 0;
+static void flush_timeout_function(unsigned long data);
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
+  unsigned long timer_flags; \
+  save_flags(timer_flags); \
+  cli(); \
+  if (fast_timers[info->line].function == NULL) { \
+    serial_fast_timer_started++; \
+    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
+    start_one_shot_timer(&fast_timers[info->line], \
+                         flush_timeout_function, \
+                         (unsigned long)info, \
+                         (usec), \
+                         string); \
+  } \
+  else { \
+    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+  } \
+  restore_flags(timer_flags); \
+}
+#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
+
+#else
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
+#define START_FLUSH_FAST_TIMER(info, string)
+#endif
+
+static struct etrax_recv_buffer *
+alloc_recv_buffer(unsigned int size)
+{
+	struct etrax_recv_buffer *buffer;
+
+	if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
+		return NULL;
+
+	buffer->next = NULL;
+	buffer->length = 0;
+	buffer->error = TTY_NORMAL;
+
+	return buffer;
+}
+
+static void
+append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	if (!info->first_recv_buffer)
+		info->first_recv_buffer = buffer;
+	else
+		info->last_recv_buffer->next = buffer;
+
+	info->last_recv_buffer = buffer;
+
+	info->recv_cnt += buffer->length;
+	if (info->recv_cnt > info->max_recv_cnt)
+		info->max_recv_cnt = info->recv_cnt;
+
+	restore_flags(flags);
+}
+
+static int
+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
+{
+	struct etrax_recv_buffer *buffer;
+	if (info->uses_dma_in) {
+		if (!(buffer = alloc_recv_buffer(4)))
+			return 0;
+
+		buffer->length = 1;
+		buffer->error = flag;
+		buffer->buffer[0] = data;
+
+		append_recv_buffer(info, buffer);
+
+		info->icount.rx++;
+	} else {
+		struct tty_struct *tty = info->tty;
+		*tty->flip.char_buf_ptr = data;
+		*tty->flip.flag_buf_ptr = flag;
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+		info->icount.rx++;
+	}
+
+	return 1;
+}
+
+extern _INLINE_ unsigned int
+handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
+{
+	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
+
+	if (info->recv_cnt + recvl > 65536) {
+		printk(KERN_CRIT
+		       "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl);
+		return 0;
+	}
+
+	buffer->length = recvl;
+
+	if (info->errorcode == ERRCODE_SET_BREAK)
+		buffer->error = TTY_BREAK;
+	info->errorcode = 0;
+
+	append_recv_buffer(info, buffer);
+
+	if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+		panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+
+	descr->buf = virt_to_phys(buffer->buffer);
+
+	return recvl;
+}
+
+static _INLINE_ unsigned int
+handle_all_descr_data(struct e100_serial *info)
+{
+	struct etrax_dma_descr *descr;
+	unsigned int recvl;
+	unsigned int ret = 0;
+
+	while (1)
+	{
+		descr = &info->rec_descr[info->cur_rec_descr];
+
+		if (descr == phys_to_virt(*info->idescradr))
+			break;
+
+		if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
+			info->cur_rec_descr = 0;
+
+		/* find out how many bytes were read */
+
+		/* if the eop bit was not set, all data has been received */
+		if (!(descr->status & d_eop)) {
+			recvl = descr->sw_len;
+		} else {
+			/* otherwise we find the amount of data received here */
+			recvl = descr->hw_len;
+		}
+
+		/* Reset the status information */
+		descr->status = 0;
+
+		DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
+			if (info->tty->stopped) {
+				unsigned char *buf = phys_to_virt(descr->buf);
+				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
+				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
+				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
+			}
+			);
+
+		/* update stats */
+		info->icount.rx += recvl;
+
+		ret += handle_descr_data(info, descr, recvl);
+	}
+
+	return ret;
+}
+
+static _INLINE_ void
+receive_chars_dma(struct e100_serial *info)
+{
+	struct tty_struct *tty;
+	unsigned char rstat;
+
+#ifdef CONFIG_SVINTO_SIM
+	/* No receive in the simulator.  Will probably be when the rest of
+	 * the serial interface works, and this piece will just be removed.
+	 */
+	return;
+#endif
+
+	/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+	*info->iclrintradr =
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+	tty = info->tty;
+	if (!tty) /* Something wrong... */
+		return;
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+	if (info->uses_dma_in)
+		e100_enable_serial_data_irq(info);
+#endif
+
+	if (info->errorcode == ERRCODE_INSERT_BREAK)
+		add_char_and_flag(info, '\0', TTY_BREAK);
+
+	handle_all_descr_data(info);
+
+	/* Read the status register to detect errors */
+	rstat = info->port[REG_STATUS];
+	if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+		DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
+	}
+
+	if (rstat & SER_ERROR_MASK) {
+		/* If we got an error, we must reset it by reading the
+		 * data_in field
+		 */
+		unsigned char data = info->port[REG_DATA];
+
+		PROCSTAT(ser_stat[info->line].errors_cnt++);
+		DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
+			  ((rstat & SER_ERROR_MASK) << 8) | data);
+
+		if (rstat & SER_PAR_ERR_MASK)
+			add_char_and_flag(info, data, TTY_PARITY);
+		else if (rstat & SER_OVERRUN_MASK)
+			add_char_and_flag(info, data, TTY_OVERRUN);
+		else if (rstat & SER_FRAMING_ERR_MASK)
+			add_char_and_flag(info, data, TTY_FRAME);
+	}
+
+	START_FLUSH_FAST_TIMER(info, "receive_chars");
+
+	/* Restart the receiving DMA */
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+}
+
+static _INLINE_ int
+start_recv_dma(struct e100_serial *info)
+{
+	struct etrax_dma_descr *descr = info->rec_descr;
+	struct etrax_recv_buffer *buffer;
+        int i;
+
+	/* Set up the receiving descriptors */
+	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
+		if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+			panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+
+		descr[i].ctrl = d_int;
+		descr[i].buf = virt_to_phys(buffer->buffer);
+		descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
+		descr[i].hw_len = 0;
+		descr[i].status = 0;
+		descr[i].next = virt_to_phys(&descr[i+1]);
+	}
+
+	/* Link the last descriptor to the first */
+	descr[i-1].next = virt_to_phys(&descr[0]);
+
+	/* Start with the first descriptor in the list */
+	info->cur_rec_descr = 0;
+
+	/* Start the DMA */
+	*info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+	/* Input DMA should be running now */
+	return 1;
+}
+
+static void
+start_receive(struct e100_serial *info)
+{
+#ifdef CONFIG_SVINTO_SIM
+	/* No receive in the simulator.  Will probably be when the rest of
+	 * the serial interface works, and this piece will just be removed.
+	 */
+	return;
+#endif
+	info->tty->flip.count = 0;
+	if (info->uses_dma_in) {
+		/* reset the input dma channel to be sure it works */
+
+		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+		start_recv_dma(info);
+	}
+}
+
+
+static _INLINE_ void
+status_handle(struct e100_serial *info, unsigned short status)
+{
+}
+
+/* the bits in the MASK2 register are laid out like this:
+   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
+   where I is the input channel and O is the output channel for the port.
+   info->irq is the bit number for the DMAO_DESCR so to check the others we
+   shift info->irq to the left.
+*/
+
+/* dma output channel interrupt handler
+   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
+   DMA8(ser1) when they have finished a descriptor with the intr flag set.
+*/
+
+static irqreturn_t
+tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct e100_serial *info;
+	unsigned long ireg;
+	int i;
+	int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+	/* No receive in the simulator.  Will probably be when the rest of
+	 * the serial interface works, and this piece will just be removed.
+	 */
+	{
+		const char *s = "What? tr_interrupt in simulator??\n";
+		SIMCOUT(s,strlen(s));
+	}
+	return IRQ_HANDLED;
+#endif
+
+	/* find out the line that caused this irq and get it from rs_table */
+
+	ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+	for (i = 0; i < NR_PORTS; i++) {
+		info = rs_table + i;
+		if (!info->enabled || !info->uses_dma_out)
+			continue;
+		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
+		if (ireg & info->irq) {
+			handled = 1;
+			/* we can send a new dma bunch. make it so. */
+			DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
+			/* Read jiffies_usec first,
+			 * we want this time to be as late as possible
+			 */
+ 			PROCSTAT(ser_stat[info->line].tx_dma_ints++);
+			info->last_tx_active_usec = GET_JIFFIES_USEC();
+			info->last_tx_active = jiffies;
+			transmit_chars_dma(info);
+		}
+
+		/* FIXME: here we should really check for a change in the
+		   status lines and if so call status_handle(info) */
+	}
+	return IRQ_RETVAL(handled);
+} /* tr_interrupt */
+
+/* dma input channel interrupt handler */
+
+static irqreturn_t
+rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct e100_serial *info;
+	unsigned long ireg;
+	int i;
+	int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+	/* No receive in the simulator.  Will probably be when the rest of
+	 * the serial interface works, and this piece will just be removed.
+	 */
+	{
+		const char *s = "What? rec_interrupt in simulator??\n";
+		SIMCOUT(s,strlen(s));
+	}
+	return IRQ_HANDLED;
+#endif
+
+	/* find out the line that caused this irq and get it from rs_table */
+
+	ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+	for (i = 0; i < NR_PORTS; i++) {
+		info = rs_table + i;
+		if (!info->enabled || !info->uses_dma_in)
+			continue;
+		/* check for both dma_eop and dma_descr for the input dma channel */
+		if (ireg & ((info->irq << 2) | (info->irq << 3))) {
+			handled = 1;
+			/* we have received something */
+			receive_chars_dma(info);
+		}
+
+		/* FIXME: here we should really check for a change in the
+		   status lines and if so call status_handle(info) */
+	}
+	return IRQ_RETVAL(handled);
+} /* rec_interrupt */
+
+static _INLINE_ int
+force_eop_if_needed(struct e100_serial *info)
+{
+	/* We check data_avail bit to determine if data has
+	 * arrived since last time
+	 */
+	unsigned char rstat = info->port[REG_STATUS];
+
+	/* error or datavail? */
+	if (rstat & SER_ERROR_MASK) {
+		/* Some error has occurred. If there has been valid data, an
+		 * EOP interrupt will be made automatically. If no data, the
+		 * normal ser_interrupt should be enabled and handle it.
+		 * So do nothing!
+		 */
+		DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
+		          rstat | (info->line << 8));
+		return 0;
+	}
+
+	if (rstat & SER_DATA_AVAIL_MASK) {
+		/* Ok data, no error, count it */
+		TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
+		          rstat | (info->line << 8)));
+		/* Read data to clear status flags */
+		(void)info->port[REG_DATA];
+
+		info->forced_eop = 0;
+		START_FLUSH_FAST_TIMER(info, "magic");
+		return 0;
+	}
+
+	/* hit the timeout, force an EOP for the input
+	 * dma channel if we haven't already
+	 */
+	if (!info->forced_eop) {
+		info->forced_eop = 1;
+		PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
+		TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
+		FORCE_EOP(info);
+	}
+
+	return 1;
+}
+
+extern _INLINE_ void
+flush_to_flip_buffer(struct e100_serial *info)
+{
+	struct tty_struct *tty;
+	struct etrax_recv_buffer *buffer;
+	unsigned int length;
+	unsigned long flags;
+	int max_flip_size;
+
+	if (!info->first_recv_buffer)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	if (!(tty = info->tty)) {
+		restore_flags(flags);
+		return;
+	}
+
+	length = tty->flip.count;
+	/* Don't flip more than the ldisc has room for.
+	 * The return value from ldisc.receive_room(tty) - might not be up to
+	 * date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the
+	 * processed and not accounted for yet.
+	 * Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way.
+	 * Lets buffer data here and let flow control take care of it.
+	 * Since we normally flip large chunks, the ldisc don't react
+	 * with throttle until too late if we flip to much.
+	 */
+	max_flip_size = tty->ldisc.receive_room(tty);
+	if (max_flip_size < 0)
+		max_flip_size = 0;
+	if (max_flip_size <= (TTY_FLIPBUF_SIZE +         /* Maybe not accounted for */
+			      length + info->recv_cnt +  /* We have this queued */
+			      2*SERIAL_DESCR_BUF_SIZE +    /* This could be on the way */
+			      TTY_THRESHOLD_THROTTLE)) { /* Some slack */
+		/* check TTY_THROTTLED first so it indicates our state */
+		if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
+			DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size));
+			rs_throttle(tty);
+		}
+#if 0
+		else if (max_flip_size <= (TTY_FLIPBUF_SIZE +         /* Maybe not accounted for */
+					   length + info->recv_cnt +  /* We have this queued */
+					   SERIAL_DESCR_BUF_SIZE +    /* This could be on the way */
+					   TTY_THRESHOLD_THROTTLE)) { /* Some slack */
+			DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size));
+			rs_throttle(tty);
+		}
+#endif
+	}
+
+	if (max_flip_size > TTY_FLIPBUF_SIZE)
+		max_flip_size = TTY_FLIPBUF_SIZE;
+
+	while ((buffer = info->first_recv_buffer) && length < max_flip_size) {
+		unsigned int count = buffer->length;
+
+		if (length + count > max_flip_size)
+			count = max_flip_size - length;
+
+		memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count);
+		memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count);
+		tty->flip.flag_buf_ptr[length] = buffer->error;
+
+		length += count;
+		info->recv_cnt -= count;
+		DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length));
+
+		if (count == buffer->length) {
+			info->first_recv_buffer = buffer->next;
+			kfree(buffer);
+		} else {
+			buffer->length -= count;
+			memmove(buffer->buffer, buffer->buffer + count, buffer->length);
+			buffer->error = TTY_NORMAL;
+		}
+	}
+
+	if (!info->first_recv_buffer)
+		info->last_recv_buffer = NULL;
+
+	tty->flip.count = length;
+	DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) {
+		DEBUG_LOG(info->line, "ldisc %lu\n",
+			  tty->ldisc.chars_in_buffer(tty));
+		DEBUG_LOG(info->line, "flip.count %lu\n",
+			  tty->flip.count);
+	      }
+	      );
+	restore_flags(flags);
+
+	DFLIP(
+	  if (1) {
+
+		  if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+			  DEBUG_LOG(info->line, "*** TTY_DONT_FLIP set flip.count %i ***\n", tty->flip.count);
+			  DEBUG_LOG(info->line, "*** recv_cnt %i\n", info->recv_cnt);
+		  } else {
+		  }
+		  DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
+		  DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
+		  DEBUG_LOG(info->line, "room  %lu\n", tty->ldisc.receive_room(tty));
+	  }
+
+	);
+
+	/* this includes a check for low-latency */
+	tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void
+check_flush_timeout(struct e100_serial *info)
+{
+	/* Flip what we've got (if we can) */
+	flush_to_flip_buffer(info);
+
+	/* We might need to flip later, but not to fast
+	 * since the system is busy processing input... */
+	if (info->first_recv_buffer)
+		START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
+
+	/* Force eop last, since data might have come while we're processing
+	 * and if we started the slow timer above, we won't start a fast
+	 * below.
+	 */
+	force_eop_if_needed(info);
+}
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static void flush_timeout_function(unsigned long data)
+{
+	struct e100_serial *info = (struct e100_serial *)data;
+
+	fast_timers[info->line].function = NULL;
+	serial_fast_timer_expired++;
+	TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
+	TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
+	check_flush_timeout(info);
+}
+
+#else
+
+/* dma fifo/buffer timeout handler
+   forces an end-of-packet for the dma input channel if no chars
+   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
+*/
+
+static struct timer_list flush_timer;
+
+static void
+timed_flush_handler(unsigned long ptr)
+{
+	struct e100_serial *info;
+	int i;
+
+#ifdef CONFIG_SVINTO_SIM
+	return;
+#endif
+
+	for (i = 0; i < NR_PORTS; i++) {
+		info = rs_table + i;
+		if (info->uses_dma_in)
+			check_flush_timeout(info);
+	}
+
+	/* restart flush timer */
+	mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+}
+#endif
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+
+/* If there is an error (ie break) when the DMA is running and
+ * there are no bytes in the fifo the DMA is stopped and we get no
+ * eop interrupt. Thus we have to monitor the first bytes on a DMA
+ * transfer, and if it is without error we can turn the serial
+ * interrupts off.
+ */
+
+/*
+BREAK handling on ETRAX 100:
+ETRAX will generate interrupt although there is no stop bit between the
+characters.
+
+Depending on how long the break sequence is, the end of the breaksequence
+will look differently:
+| indicates start/end of a character.
+
+B= Break character (0x00) with framing error.
+E= Error byte with parity error received after B characters.
+F= "Faked" valid byte received immediately after B characters.
+V= Valid byte
+
+1.
+    B          BL         ___________________________ V
+.._|__________|__________|                           |valid data |
+
+Multiple frame errors with data == 0x00 (B),
+the timing matches up "perfectly" so no extra ending char is detected.
+The RXD pin is 1 in the last interrupt, in that case
+we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
+know if another byte will come and this really is case 2. below
+(e.g F=0xFF or 0xFE)
+If RXD pin is 0 we can expect another character (see 2. below).
+
+
+2.
+
+    B          B          E or F__________________..__ V
+.._|__________|__________|______    |                 |valid data
+                          "valid" or
+                          parity error
+
+Multiple frame errors with data == 0x00 (B),
+but the part of the break trigs is interpreted as a start bit (and possibly
+some 0 bits followed by a number of 1 bits and a stop bit).
+Depending on parity settings etc. this last character can be either
+a fake "valid" char (F) or have a parity error (E).
+
+If the character is valid it will be put in the buffer,
+we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
+will set the flags so the tty will handle it,
+if it's an error byte it will not be put in the buffer
+and we set info->errorcode = ERRCODE_INSERT_BREAK.
+
+To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
+of the last faulty char (B) and compares it with the current time:
+If the time elapsed time is less then 2*char_time_usec we will assume
+it's a faked F char and not a Valid char and set
+info->errorcode = ERRCODE_SET_BREAK.
+
+Flaws in the above solution:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We use the timer to distinguish a F character from a V character,
+if a V character is to close after the break we might make the wrong decision.
+
+TODO: The break will be delayed until an F or V character is received.
+
+*/
+
+extern _INLINE_
+struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
+{
+	unsigned long data_read;
+	struct tty_struct *tty = info->tty;
+
+	if (!tty) {
+		printk("!NO TTY!\n");
+		return info;
+	}
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) {
+		/* check TTY_THROTTLED first so it indicates our state */
+		if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
+			DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count));
+			rs_throttle(tty);
+		}
+	}
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+		DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count);
+		tty->flip.work.func((void *) tty);
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count);
+			return info;		/* if TTY_DONT_FLIP is set */
+		}
+	}
+	/* Read data and status at the same time */
+	data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
+more_data:
+	if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
+		DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+	}
+	DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
+
+	if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
+			  IO_MASK(R_SERIAL0_READ, par_err) |
+			  IO_MASK(R_SERIAL0_READ, overrun) )) {
+		/* An error */
+		info->last_rx_active_usec = GET_JIFFIES_USEC();
+		info->last_rx_active = jiffies;
+		DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
+		DLOG_INT_TRIG(
+		if (!log_int_trig1_pos) {
+			log_int_trig1_pos = log_int_pos;
+			log_int(rdpc(), 0, 0);
+		}
+		);
+
+
+		if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
+		     (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
+			/* Most likely a break, but we get interrupts over and
+			 * over again.
+			 */
+
+			if (!info->break_detected_cnt) {
+				DEBUG_LOG(info->line, "#BRK start\n", 0);
+			}
+			if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
+				/* The RX pin is high now, so the break
+				 * must be over, but....
+				 * we can't really know if we will get another
+				 * last byte ending the break or not.
+				 * And we don't know if the byte (if any) will
+				 * have an error or look valid.
+				 */
+				DEBUG_LOG(info->line, "# BL BRK\n", 0);
+				info->errorcode = ERRCODE_INSERT_BREAK;
+			}
+			info->break_detected_cnt++;
+		} else {
+			/* The error does not look like a break, but could be
+			 * the end of one
+			 */
+			if (info->break_detected_cnt) {
+				DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+				info->errorcode = ERRCODE_INSERT_BREAK;
+			} else {
+				if (info->errorcode == ERRCODE_INSERT_BREAK) {
+					info->icount.brk++;
+					*tty->flip.char_buf_ptr = 0;
+					*tty->flip.flag_buf_ptr = TTY_BREAK;
+					tty->flip.flag_buf_ptr++;
+					tty->flip.char_buf_ptr++;
+					tty->flip.count++;
+					info->icount.rx++;
+				}
+				*tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
+
+				if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
+					info->icount.parity++;
+					*tty->flip.flag_buf_ptr = TTY_PARITY;
+				} else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
+					info->icount.overrun++;
+					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+				} else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
+					info->icount.frame++;
+					*tty->flip.flag_buf_ptr = TTY_FRAME;
+				}
+				info->errorcode = 0;
+			}
+			info->break_detected_cnt = 0;
+		}
+	} else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+		/* No error */
+		DLOG_INT_TRIG(
+		if (!log_int_trig1_pos) {
+			if (log_int_pos >= log_int_size) {
+				log_int_pos = 0;
+			}
+			log_int_trig0_pos = log_int_pos;
+			log_int(rdpc(), 0, 0);
+		}
+		);
+		*tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
+		*tty->flip.flag_buf_ptr = 0;
+	} else {
+		DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
+	}
+
+
+	tty->flip.flag_buf_ptr++;
+	tty->flip.char_buf_ptr++;
+	tty->flip.count++;
+	info->icount.rx++;
+	data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
+	if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+		DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
+		goto more_data;
+	}
+
+	tty_flip_buffer_push(info->tty);
+	return info;
+}
+
+extern _INLINE_
+struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
+{
+	unsigned char rstat;
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("Interrupt from serport %d\n", i);
+#endif
+/*	DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
+	if (!info->uses_dma_in) {
+		return handle_ser_rx_interrupt_no_dma(info);
+	}
+	/* DMA is used */
+	rstat = info->port[REG_STATUS];
+	if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+		DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+	}
+
+	if (rstat & SER_ERROR_MASK) {
+		unsigned char data;
+
+		info->last_rx_active_usec = GET_JIFFIES_USEC();
+		info->last_rx_active = jiffies;
+		/* If we got an error, we must reset it by reading the
+		 * data_in field
+		 */
+		data = info->port[REG_DATA];
+		DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
+		DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
+		if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
+			/* Most likely a break, but we get interrupts over and
+			 * over again.
+			 */
+
+			if (!info->break_detected_cnt) {
+				DEBUG_LOG(info->line, "#BRK start\n", 0);
+			}
+			if (rstat & SER_RXD_MASK) {
+				/* The RX pin is high now, so the break
+				 * must be over, but....
+				 * we can't really know if we will get another
+				 * last byte ending the break or not.
+				 * And we don't know if the byte (if any) will
+				 * have an error or look valid.
+				 */
+				DEBUG_LOG(info->line, "# BL BRK\n", 0);
+				info->errorcode = ERRCODE_INSERT_BREAK;
+			}
+			info->break_detected_cnt++;
+		} else {
+			/* The error does not look like a break, but could be
+			 * the end of one
+			 */
+			if (info->break_detected_cnt) {
+				DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+				info->errorcode = ERRCODE_INSERT_BREAK;
+			} else {
+				if (info->errorcode == ERRCODE_INSERT_BREAK) {
+					info->icount.brk++;
+					add_char_and_flag(info, '\0', TTY_BREAK);
+				}
+
+				if (rstat & SER_PAR_ERR_MASK) {
+					info->icount.parity++;
+					add_char_and_flag(info, data, TTY_PARITY);
+				} else if (rstat & SER_OVERRUN_MASK) {
+					info->icount.overrun++;
+					add_char_and_flag(info, data, TTY_OVERRUN);
+				} else if (rstat & SER_FRAMING_ERR_MASK) {
+					info->icount.frame++;
+					add_char_and_flag(info, data, TTY_FRAME);
+				}
+
+				info->errorcode = 0;
+			}
+			info->break_detected_cnt = 0;
+			DEBUG_LOG(info->line, "#iERR s d %04X\n",
+			          ((rstat & SER_ERROR_MASK) << 8) | data);
+		}
+		PROCSTAT(ser_stat[info->line].early_errors_cnt++);
+	} else { /* It was a valid byte, now let the DMA do the rest */
+		unsigned long curr_time_u = GET_JIFFIES_USEC();
+		unsigned long curr_time = jiffies;
+
+		if (info->break_detected_cnt) {
+			/* Detect if this character is a new valid char or the
+			 * last char in a break sequence: If LSBits are 0 and
+			 * MSBits are high AND the time is close to the
+			 * previous interrupt we should discard it.
+			 */
+			long elapsed_usec =
+			  (curr_time - info->last_rx_active) * (1000000/HZ) +
+			  curr_time_u - info->last_rx_active_usec;
+			if (elapsed_usec < 2*info->char_time_usec) {
+				DEBUG_LOG(info->line, "FBRK %i\n", info->line);
+				/* Report as BREAK (error) and let
+				 * receive_chars_dma() handle it
+				 */
+				info->errorcode = ERRCODE_SET_BREAK;
+			} else {
+				DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
+			}
+			DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
+		}
+
+#ifdef SERIAL_DEBUG_INTR
+		printk("** OK, disabling ser_interrupts\n");
+#endif
+		e100_disable_serial_data_irq(info);
+		DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
+		info->break_detected_cnt = 0;
+
+		PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
+	}
+	/* Restarting the DMA never hurts */
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+	START_FLUSH_FAST_TIMER(info, "ser_int");
+	return info;
+} /* handle_ser_rx_interrupt */
+
+extern _INLINE_ void handle_ser_tx_interrupt(struct e100_serial *info)
+{
+	unsigned long flags;
+
+	if (info->x_char) {
+		unsigned char rstat;
+		DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
+		save_flags(flags); cli();
+		rstat = info->port[REG_STATUS];
+		DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+
+		info->port[REG_TR_DATA] = info->x_char;
+		info->icount.tx++;
+		info->x_char = 0;
+		/* We must enable since it is disabled in ser_interrupt */
+		e100_enable_serial_tx_ready_irq(info);
+		restore_flags(flags);
+		return;
+	}
+	if (info->uses_dma_out) {
+		unsigned char rstat;
+		int i;
+		/* We only use normal tx interrupt when sending x_char */
+		DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
+		save_flags(flags); cli();
+		rstat = info->port[REG_STATUS];
+		DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+		e100_disable_serial_tx_ready_irq(info);
+		if (info->tty->stopped)
+			rs_stop(info->tty);
+		/* Enable the DMA channel and tell it to continue */
+		e100_enable_txdma_channel(info);
+		/* Wait 12 cycles before doing the DMA command */
+		for(i = 6;  i > 0; i--)
+			nop();
+
+		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
+		restore_flags(flags);
+		return;
+	}
+	/* Normal char-by-char interrupt */
+	if (info->xmit.head == info->xmit.tail
+	    || info->tty->stopped
+	    || info->tty->hw_stopped) {
+		DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", info->tty->stopped));
+		e100_disable_serial_tx_ready_irq(info);
+		info->tr_running = 0;
+		return;
+	}
+	DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
+	/* Send a byte, rs485 timing is critical so turn of ints */
+	save_flags(flags); cli();
+	info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
+	info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+	info->icount.tx++;
+	if (info->xmit.head == info->xmit.tail) {
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+		if (info->rs485.enabled) {
+			/* Set a short timer to toggle RTS */
+			start_one_shot_timer(&fast_timers_rs485[info->line],
+			                     rs485_toggle_rts_timer_function,
+			                     (unsigned long)info,
+			                     info->char_time_usec*2,
+			                     "RS-485");
+		}
+#endif /* RS485 */
+		info->last_tx_active_usec = GET_JIFFIES_USEC();
+		info->last_tx_active = jiffies;
+		e100_disable_serial_tx_ready_irq(info);
+		info->tr_running = 0;
+		DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
+	} else {
+		/* We must enable since it is disabled in ser_interrupt */
+		e100_enable_serial_tx_ready_irq(info);
+	}
+	restore_flags(flags);
+
+	if (CIRC_CNT(info->xmit.head,
+		     info->xmit.tail,
+		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+} /* handle_ser_tx_interrupt */
+
+/* result of time measurements:
+ * RX duration 54-60 us when doing something, otherwise 6-9 us
+ * ser_int duration: just sending: 8-15 us normally, up to 73 us
+ */
+static irqreturn_t
+ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	static volatile int tx_started = 0;
+	struct e100_serial *info;
+	int i;
+	unsigned long flags;
+	unsigned long irq_mask1_rd;
+	unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
+	int handled = 0;
+	static volatile unsigned long reentered_ready_mask = 0;
+
+	save_flags(flags); cli();
+	irq_mask1_rd = *R_IRQ_MASK1_RD;
+	/* First handle all rx interrupts with ints disabled */
+	info = rs_table;
+	irq_mask1_rd &= e100_ser_int_mask;
+	for (i = 0; i < NR_PORTS; i++) {
+		/* Which line caused the data irq? */
+		if (irq_mask1_rd & data_mask) {
+			handled = 1;
+			handle_ser_rx_interrupt(info);
+		}
+		info += 1;
+		data_mask <<= 2;
+	}
+	/* Handle tx interrupts with interrupts enabled so we
+	 * can take care of new data interrupts while transmitting
+	 * We protect the tx part with the tx_started flag.
+	 * We disable the tr_ready interrupts we are about to handle and
+	 * unblock the serial interrupt so new serial interrupts may come.
+	 *
+	 * If we get a new interrupt:
+	 *  - it migth be due to synchronous serial ports.
+	 *  - serial irq will be blocked by general irq handler.
+	 *  - async data will be handled above (sync will be ignored).
+	 *  - tx_started flag will prevent us from trying to send again and
+	 *    we will exit fast - no need to unblock serial irq.
+	 *  - Next (sync) serial interrupt handler will be runned with
+	 *    disabled interrupt due to restore_flags() at end of function,
+	 *    so sync handler will not be preempted or reentered.
+	 */
+	if (!tx_started) {
+		unsigned long ready_mask;
+		unsigned long
+		tx_started = 1;
+		/* Only the tr_ready interrupts left */
+		irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+				 IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+				 IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+				 IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+		while (irq_mask1_rd) {
+			/* Disable those we are about to handle */
+			*R_IRQ_MASK1_CLR = irq_mask1_rd;
+			/* Unblock the serial interrupt */
+			*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+			sti();
+			ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
+			info = rs_table;
+			for (i = 0; i < NR_PORTS; i++) {
+				/* Which line caused the ready irq? */
+				if (irq_mask1_rd & ready_mask) {
+					handled = 1;
+					handle_ser_tx_interrupt(info);
+				}
+				info += 1;
+				ready_mask <<= 2;
+			}
+			/* handle_ser_tx_interrupt enables tr_ready interrupts */
+			cli();
+			/* Handle reentered TX interrupt */
+			irq_mask1_rd = reentered_ready_mask;
+		}
+		cli();
+		tx_started = 0;
+	} else {
+		unsigned long ready_mask;
+		ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+					     IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+					     IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+					     IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+		if (ready_mask) {
+			reentered_ready_mask |= ready_mask;
+			/* Disable those we are about to handle */
+			*R_IRQ_MASK1_CLR = ready_mask;
+			DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
+		}
+	}
+
+	restore_flags(flags);
+	return IRQ_RETVAL(handled);
+} /* ser_interrupt */
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void
+do_softint(void *private_)
+{
+	struct e100_serial	*info = (struct e100_serial *) private_;
+	struct tty_struct	*tty;
+
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+static int
+startup(struct e100_serial * info)
+{
+	unsigned long flags;
+	unsigned long xmit_page;
+	int i;
+
+	xmit_page = get_zeroed_page(GFP_KERNEL);
+	if (!xmit_page)
+		return -ENOMEM;
+
+	save_flags(flags);
+	cli();
+
+	/* if it was already initialized, skip this */
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		restore_flags(flags);
+		free_page(xmit_page);
+		return 0;
+	}
+
+	if (info->xmit.buf)
+		free_page(xmit_page);
+	else
+		info->xmit.buf = (unsigned char *) xmit_page;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+	/* Bits and pieces collected from below.  Better to have them
+	   in one ifdef:ed clause than to mix in a lot of ifdefs,
+	   right? */
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->xmit.head = info->xmit.tail = 0;
+	info->first_recv_buffer = info->last_recv_buffer = NULL;
+	info->recv_cnt = info->max_recv_cnt = 0;
+
+	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+		info->rec_descr[i].buf = NULL;
+
+	/* No real action in the simulator, but may set info important
+	   to ioctl. */
+	change_speed(info);
+#else
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+
+	/*
+	 * Reset the DMA channels and make sure their interrupts are cleared
+	 */
+
+	if (info->dma_in_enabled) {
+		info->uses_dma_in = 1;
+		e100_enable_rxdma_channel(info);
+
+		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+		/* Wait until reset cycle is complete */
+		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+		/* Make sure the irqs are cleared */
+		*info->iclrintradr =
+			IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+			IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+	} else {
+		e100_disable_rxdma_channel(info);
+	}
+
+	if (info->dma_out_enabled) {
+		info->uses_dma_out = 1;
+		e100_enable_txdma_channel(info);
+		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
+		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+		/* Make sure the irqs are cleared */
+		*info->oclrintradr =
+			IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+			IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+	} else {
+		e100_disable_txdma_channel(info);
+	}
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->xmit.head = info->xmit.tail = 0;
+	info->first_recv_buffer = info->last_recv_buffer = NULL;
+	info->recv_cnt = info->max_recv_cnt = 0;
+
+	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+		info->rec_descr[i].buf = 0;
+
+	/*
+	 * and set the speed and other flags of the serial port
+	 * this will start the rx/tx as well
+	 */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+	e100_enable_serial_data_irq(info);
+#endif
+	change_speed(info);
+
+	/* dummy read to reset any serial errors */
+
+	(void)info->port[REG_DATA];
+
+	/* enable the interrupts */
+	if (info->uses_dma_out)
+		e100_enable_txdma_irq(info);
+
+	e100_enable_rx_irq(info);
+
+	info->tr_running = 0; /* to be sure we don't lock up the transmitter */
+
+	/* setup the dma input descriptor and start dma */
+
+	start_receive(info);
+
+	/* for safety, make sure the descriptors last result is 0 bytes written */
+
+	info->tr_descr.sw_len = 0;
+	info->tr_descr.hw_len = 0;
+	info->tr_descr.status = 0;
+
+	/* enable RTS/DTR last */
+
+	e100_rts(info, 1);
+	e100_dtr(info, 1);
+
+#endif /* CONFIG_SVINTO_SIM */
+
+	info->flags |= ASYNC_INITIALIZED;
+
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void
+shutdown(struct e100_serial * info)
+{
+	unsigned long flags;
+	struct etrax_dma_descr *descr = info->rec_descr;
+	struct etrax_recv_buffer *buffer;
+	int i;
+
+#ifndef CONFIG_SVINTO_SIM
+	/* shut down the transmitter and receiver */
+	DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
+	e100_disable_rx(info);
+	info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
+
+	/* disable interrupts, reset dma channels */
+	if (info->uses_dma_in) {
+		e100_disable_rxdma_irq(info);
+		*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+		info->uses_dma_in = 0;
+	} else {
+		e100_disable_serial_data_irq(info);
+	}
+
+	if (info->uses_dma_out) {
+		e100_disable_txdma_irq(info);
+		info->tr_running = 0;
+		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+		info->uses_dma_out = 0;
+	} else {
+		e100_disable_serial_tx_ready_irq(info);
+		info->tr_running = 0;
+	}
+
+#endif /* CONFIG_SVINTO_SIM */
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....\n", info->line,
+	       info->irq);
+#endif
+
+	save_flags(flags);
+	cli(); /* Disable interrupts */
+
+	if (info->xmit.buf) {
+		free_page((unsigned long)info->xmit.buf);
+		info->xmit.buf = NULL;
+	}
+
+	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+		if (descr[i].buf) {
+			buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
+			kfree(buffer);
+			descr[i].buf = 0;
+		}
+
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+		/* hang up DTR and RTS if HUPCL is enabled */
+		e100_dtr(info, 0);
+		e100_rts(info, 0); /* could check CRTSCTS before doing this */
+	}
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+
+/* change baud rate and other assorted parameters */
+
+static void
+change_speed(struct e100_serial *info)
+{
+	unsigned int cflag;
+	unsigned long xoff;
+	unsigned long flags;
+	/* first some safety checks */
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	if (!info->port)
+		return;
+
+	cflag = info->tty->termios->c_cflag;
+
+	/* possibly, the tx/rx should be disabled first to do this safely */
+
+	/* change baud-rate and write it to the hardware */
+	if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+		/* Special baudrate */
+		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+		unsigned long alt_source =
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+		/* R_ALT_SER_BAUDRATE selects the source */
+		DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
+		       (unsigned long)info->baud_base, info->custom_divisor));
+		if (info->baud_base == SERIAL_PRESCALE_BASE) {
+			/* 0, 2-65535 (0=65536) */
+			u16 divisor = info->custom_divisor;
+			/* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
+			/* baudrate is 3.125MHz/custom_divisor */
+			alt_source =
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
+			alt_source = 0x11;
+			DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
+			*R_SERIAL_PRESCALE = divisor;
+			info->baud = SERIAL_PRESCALE_BASE/divisor;
+		}
+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
+		else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
+			  info->custom_divisor == 1) ||
+			 (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
+			  info->custom_divisor == 8)) {
+				/* ext_clk selected */
+				alt_source =
+					IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
+					IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
+				DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
+				info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
+			}
+		}
+#endif
+		else
+		{
+			/* Bad baudbase, we don't support using timer0
+			 * for baudrate.
+			 */
+			printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
+			       (unsigned long)info->baud_base, info->custom_divisor);
+		}
+		r_alt_ser_baudrate_shadow &= ~mask;
+		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+	} else {
+		/* Normal baudrate */
+		/* Make sure we use normal baudrate */
+		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+		unsigned long alt_source =
+			IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+			IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+		r_alt_ser_baudrate_shadow &= ~mask;
+		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+#ifndef CONFIG_SVINTO_SIM
+		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+#endif /* CONFIG_SVINTO_SIM */
+
+		info->baud = cflag_to_baud(cflag);
+#ifndef CONFIG_SVINTO_SIM
+		info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
+#endif /* CONFIG_SVINTO_SIM */
+	}
+
+#ifndef CONFIG_SVINTO_SIM
+	/* start with default settings and then fill in changes */
+	save_flags(flags);
+	cli();
+	/* 8 bit, no/even parity */
+	info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
+			   IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
+			   IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
+
+	/* 8 bit, no/even parity, 1 stop bit, no cts */
+	info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
+
+	if ((cflag & CSIZE) == CS7) {
+		/* set 7 bit mode */
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
+	}
+
+	if (cflag & CSTOPB) {
+		/* set 2 stop bit mode */
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
+	}
+
+	if (cflag & PARENB) {
+		/* enable parity */
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+	}
+
+	if (cflag & CMSPAR) {
+		/* enable stick parity, PARODD mean Mark which matches ETRAX */
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
+	}
+	if (cflag & PARODD) {
+		/* set odd parity (or Mark if CMSPAR) */
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
+	}
+
+	if (cflag & CRTSCTS) {
+		/* enable automatic CTS handling */
+		DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
+	}
+
+	/* make sure the tx and rx are enabled */
+
+	info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
+	info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+
+	/* actually write the control regs to the hardware */
+
+	info->port[REG_TR_CTRL] = info->tx_ctrl;
+	info->port[REG_REC_CTRL] = info->rx_ctrl;
+	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+	if (info->tty->termios->c_iflag & IXON ) {
+		DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->tty)));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+	}
+
+	*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+	restore_flags(flags);
+#endif /* !CONFIG_SVINTO_SIM */
+
+	update_char_time(info);
+
+} /* change_speed */
+
+/* start transmitting chars NOW */
+
+static void
+rs_flush_chars(struct tty_struct *tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (info->tr_running ||
+	    info->xmit.head == info->xmit.tail ||
+	    tty->stopped ||
+	    tty->hw_stopped ||
+	    !info->xmit.buf)
+		return;
+
+#ifdef SERIAL_DEBUG_FLOW
+	printk("rs_flush_chars\n");
+#endif
+
+	/* this protection might not exactly be necessary here */
+
+	save_flags(flags);
+	cli();
+	start_transmit(info);
+	restore_flags(flags);
+}
+
+extern _INLINE_ int
+rs_raw_write(struct tty_struct * tty, int from_user,
+	  const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	unsigned long flags;
+
+	/* first some sanity checks */
+
+	if (!tty || !info->xmit.buf || !tmp_buf)
+		return 0;
+
+#ifdef SERIAL_DEBUG_DATA
+	if (info->line == SERIAL_DEBUG_LINE)
+		printk("rs_raw_write (%d), status %d\n",
+		       count, info->port[REG_STATUS]);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+	/* Really simple.  The output is here and now. */
+	SIMCOUT(buf, count);
+	return count;
+#endif
+	save_flags(flags);
+	DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
+	DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+
+
+	/* the cli/restore_flags pairs below are needed because the
+	 * DMA interrupt handler moves the info->xmit values. the memcpy
+	 * needs to be in the critical region unfortunately, because we
+	 * need to read xmit values, memcpy, write xmit values in one
+	 * atomic operation... this could perhaps be avoided by more clever
+	 * design.
+	 */
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			cli();
+			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+					       info->xmit.tail,
+					       SERIAL_XMIT_SIZE);
+			if (c1 < c)
+				c = c1;
+			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		cli();
+		while (count) {
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+			info->xmit.head = (info->xmit.head + c) &
+				(SERIAL_XMIT_SIZE-1);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		restore_flags(flags);
+	}
+
+	/* enable transmitter if not running, unless the tty is stopped
+	 * this does not need IRQ protection since if tr_running == 0
+	 * the IRQ's are not running anyway for this port.
+	 */
+	DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
+
+	if (info->xmit.head != info->xmit.tail &&
+	    !tty->stopped &&
+	    !tty->hw_stopped &&
+	    !info->tr_running) {
+		start_transmit(info);
+	}
+
+	return ret;
+} /* raw_raw_write() */
+
+static int
+rs_write(struct tty_struct * tty, int from_user,
+	 const unsigned char *buf, int count)
+{
+#if defined(CONFIG_ETRAX_RS485)
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+	if (info->rs485.enabled)
+	{
+		/* If we are in RS-485 mode, we need to toggle RTS and disable
+		 * the receiver before initiating a DMA transfer
+		 */
+#ifdef CONFIG_ETRAX_FAST_TIMER
+		/* Abort any started timer */
+		fast_timers_rs485[info->line].function = NULL;
+		del_fast_timer(&fast_timers_rs485[info->line]);
+#endif
+		e100_rts(info, info->rs485.rts_on_send);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+		e100_disable_rx(info);
+		e100_enable_rx_irq(info);
+#endif
+
+		if (info->rs485.delay_rts_before_send > 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000);
+		}
+	}
+#endif /* CONFIG_ETRAX_RS485 */
+
+	count = rs_raw_write(tty, from_user, buf, count);
+
+#if defined(CONFIG_ETRAX_RS485)
+	if (info->rs485.enabled)
+	{
+		unsigned int val;
+		/* If we are in RS-485 mode the following has to be done:
+		 * wait until DMA is ready
+		 * wait on transmit shift register
+		 * toggle RTS
+		 * enable the receiver
+		 */
+
+		/* Sleep until all sent */
+		tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_FAST_TIMER
+		/* Now sleep a little more so that shift register is empty */
+		schedule_usleep(info->char_time_usec * 2);
+#endif
+		/* wait on transmit shift register */
+		do{
+			get_lsr_info(info, &val);
+		}while (!(val & TIOCSER_TEMT));
+
+		e100_rts(info, info->rs485.rts_after_sent);
+
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+		e100_enable_rx(info);
+		e100_enable_rxdma_irq(info);
+#endif
+	}
+#endif /* CONFIG_ETRAX_RS485 */
+
+	return count;
+} /* rs_write */
+
+
+/* how much space is available in the xmit buffer? */
+
+static int
+rs_write_room(struct tty_struct *tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* How many chars are in the xmit buffer?
+ * This does not include any chars in the transmitter FIFO.
+ * Use wait_until_sent for waiting for FIFO drain.
+ */
+
+static int
+rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* discard everything in the xmit buffer */
+
+static void
+rs_flush_buffer(struct tty_struct *tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	info->xmit.head = info->xmit.tail = 0;
+	restore_flags(flags);
+
+	wake_up_interruptible(&tty->write_wait);
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ *
+ * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
+ * but we do it in handle_ser_tx_interrupt().
+ * We disable DMA channel and enable tx ready interrupt and write the
+ * character when possible.
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	unsigned long flags;
+	save_flags(flags); cli();
+	if (info->uses_dma_out) {
+		/* Put the DMA on hold and disable the channel */
+		*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
+		while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
+		       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
+		e100_disable_txdma_channel(info);
+	}
+
+	/* Must make sure transmitter is not stopped before we can transmit */
+	if (tty->stopped)
+		rs_start(tty);
+
+	/* Enable manual transmit interrupt and send from there */
+	DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
+	info->x_char = ch;
+	e100_enable_serial_tx_ready_irq(info);
+	restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+rs_throttle(struct tty_struct * tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+
+	printk("throttle %s: %lu....\n", tty_name(tty, buf),
+	       (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+	DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+
+	/* Do RTS before XOFF since XOFF might take some time */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		/* Turn off RTS line */
+		e100_rts(info, 0);
+	}
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+
+}
+
+static void
+rs_unthrottle(struct tty_struct * tty)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+
+	printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
+	       (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+	DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+	DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
+	/* Do RTS before XOFF since XOFF might take some time */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		/* Assert RTS line  */
+		e100_rts(info, 1);
+	}
+
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_send_xchar(tty, START_CHAR(tty));
+	}
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+get_serial_info(struct e100_serial * info,
+		struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+
+	/* this is all probably wrong, there are a lot of fields
+	 * here that we don't have in e100_serial and maybe we
+	 * should set them to something else than 0.
+	 */
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = (int)info->port;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int
+set_serial_info(struct e100_serial *info,
+		struct serial_struct *new_info)
+{
+	struct serial_struct new_serial;
+	struct e100_serial old_info;
+	int retval = 0;
+
+	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+		return -EFAULT;
+
+	old_info = *info;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (info->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~ASYNC_FLAGS) |
+		       (new_serial.flags & ASYNC_FLAGS));
+	info->custom_divisor = new_serial.custom_divisor;
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+	if (info->flags & ASYNC_INITIALIZED) {
+		change_speed(info);
+	} else
+		retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space.
+ */
+static int
+get_lsr_info(struct e100_serial * info, unsigned int *value)
+{
+	unsigned int result = TIOCSER_TEMT;
+#ifndef CONFIG_SVINTO_SIM
+	unsigned long curr_time = jiffies;
+	unsigned long curr_time_usec = GET_JIFFIES_USEC();
+	unsigned long elapsed_usec =
+		(curr_time - info->last_tx_active) * 1000000/HZ +
+		curr_time_usec - info->last_tx_active_usec;
+
+	if (info->xmit.head != info->xmit.tail ||
+	    elapsed_usec < 2*info->char_time_usec) {
+		result = 0;
+	}
+#endif
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+#ifdef SERIAL_DEBUG_IO
+struct state_str
+{
+	int state;
+	const char *str;
+};
+
+const struct state_str control_state_str[] = {
+	{TIOCM_DTR, "DTR" },
+	{TIOCM_RTS, "RTS"},
+	{TIOCM_ST, "ST?" },
+	{TIOCM_SR, "SR?" },
+	{TIOCM_CTS, "CTS" },
+	{TIOCM_CD, "CD" },
+	{TIOCM_RI, "RI" },
+	{TIOCM_DSR, "DSR" },
+	{0, NULL }
+};
+
+char *get_control_state_str(int MLines, char *s)
+{
+	int i = 0;
+
+	s[0]='\0';
+	while (control_state_str[i].str != NULL) {
+		if (MLines & control_state_str[i].state) {
+			if (s[0] != '\0') {
+				strcat(s, ", ");
+			}
+			strcat(s, control_state_str[i].str);
+		}
+		i++;
+	}
+	return s;
+}
+#endif
+
+static int
+get_modem_info(struct e100_serial * info, unsigned int *value)
+{
+	unsigned int result;
+	/* Polarity isn't verified */
+#if 0 /*def SERIAL_DEBUG_IO  */
+
+	printk("get_modem_info: RTS: %i DTR: %i CD: %i RI: %i DSR: %i CTS: %i\n",
+	       E100_RTS_GET(info),
+	       E100_DTR_GET(info),
+	       E100_CD_GET(info),
+	       E100_RI_GET(info),
+	       E100_DSR_GET(info),
+	       E100_CTS_GET(info));
+#endif
+
+	result =
+		(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
+		| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
+		| (!E100_RI_GET(info) ? TIOCM_RNG : 0)
+		| (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
+		| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
+
+#ifdef SERIAL_DEBUG_IO
+	printk("e100ser: modem state: %i 0x%08X\n", result, result);
+	{
+		char s[100];
+
+		get_control_state_str(result, s);
+		printk("state: %s\n", s);
+	}
+#endif
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+
+static int
+set_modem_info(struct e100_serial * info, unsigned int cmd,
+	       unsigned int *value)
+{
+	unsigned int arg;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case TIOCMBIS:
+		if (arg & TIOCM_RTS) {
+			e100_rts(info, 1);
+		}
+		if (arg & TIOCM_DTR) {
+			e100_dtr(info, 1);
+		}
+		/* Handle FEMALE behaviour */
+		if (arg & TIOCM_RI) {
+			e100_ri_out(info, 1);
+		}
+		if (arg & TIOCM_CD) {
+			e100_cd_out(info, 1);
+		}
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS) {
+			e100_rts(info, 0);
+		}
+		if (arg & TIOCM_DTR) {
+			e100_dtr(info, 0);
+		}
+		/* Handle FEMALE behaviour */
+		if (arg & TIOCM_RI) {
+			e100_ri_out(info, 0);
+		}
+		if (arg & TIOCM_CD) {
+			e100_cd_out(info, 0);
+		}
+		break;
+	case TIOCMSET:
+		e100_rts(info, arg & TIOCM_RTS);
+		e100_dtr(info, arg & TIOCM_DTR);
+		/* Handle FEMALE behaviour */
+		e100_ri_out(info, arg & TIOCM_RI);
+		e100_cd_out(info, arg & TIOCM_CD);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static void
+rs_break(struct tty_struct *tty, int break_state)
+{
+	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (!info->port)
+		return;
+
+	save_flags(flags);
+	cli();
+	if (break_state == -1) {
+		/* Go to manual mode and set the txd pin to 0 */
+		info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */
+	} else {
+		info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
+	}
+	info->port[REG_TR_CTRL] = info->tx_ctrl;
+	restore_flags(flags);
+}
+
+static int
+rs_ioctl(struct tty_struct *tty, struct file * file,
+	 unsigned int cmd, unsigned long arg)
+{
+	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return -EIO;
+	}
+
+	switch (cmd) {
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct e100_serial *) arg,
+					 info, sizeof(struct e100_serial)))
+				return -EFAULT;
+			return 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+		case TIOCSERSETRS485:
+		{
+			struct rs485_control rs485ctrl;
+			if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl)))
+				return -EFAULT;
+
+			return e100_enable_rs485(tty, &rs485ctrl);
+		}
+
+		case TIOCSERWRRS485:
+		{
+			struct rs485_write rs485wr;
+			if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr)))
+				return -EFAULT;
+
+			return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size);
+		}
+#endif
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static void
+rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag &&
+	    tty->termios->c_iflag == old_termios->c_iflag)
+		return;
+
+	change_speed(info);
+
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+
+}
+
+/* In debugport.c - register a console write function that uses the normal
+ * serial driver
+ */
+typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
+
+extern debugport_write_function debug_write_function;
+
+static int rs_debug_write_function(int i, const char *buf, unsigned int len)
+{
+	int cnt;
+	int written = 0;
+        struct tty_struct *tty;
+        static int recurse_cnt = 0;
+
+        tty = rs_table[i].tty;
+        if (tty)  {
+		unsigned long flags;
+		if (recurse_cnt > 5) /* We skip this debug output */
+			return 1;
+
+		local_irq_save(flags);
+		recurse_cnt++;
+		local_irq_restore(flags);
+                do {
+                        cnt = rs_write(tty, 0, buf + written, len);
+                        if (cnt >= 0) {
+				written += cnt;
+                                buf += cnt;
+                                len -= cnt;
+                        } else
+                                len = cnt;
+                } while(len > 0);
+		local_irq_save(flags);
+		recurse_cnt--;
+		local_irq_restore(flags);
+                return 1;
+        }
+        return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void
+rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (!info)
+		return;
+
+	/* interrupts are disabled for this entire function */
+
+	save_flags(flags);
+	cli();
+
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		return;
+	}
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
+	       info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk(KERN_CRIT
+		       "rs_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the serial receiver and the DMA receive interrupt.
+	 */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+	e100_disable_serial_data_irq(info);
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+	e100_disable_rx(info);
+	e100_disable_rx_irq(info);
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important as we have a transmit FIFO!
+		 */
+		rs_wait_until_sent(tty, HZ);
+	}
+#endif
+
+	shutdown(info);
+	if (tty->driver->flush_buffer)
+		tty->driver->flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+
+	/* port closed */
+
+#if defined(CONFIG_ETRAX_RS485)
+	if (info->rs485.enabled) {
+		info->rs485.enabled = 0;
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+		*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+		REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+			       rs485_port_g_bit, 0);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+		REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+			       CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
+		REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+			       CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
+#endif
+	}
+#endif
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	unsigned long orig_jiffies;
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	unsigned long curr_time = jiffies;
+	unsigned long curr_time_usec = GET_JIFFIES_USEC();
+	long elapsed_usec =
+		(curr_time - info->last_tx_active) * (1000000/HZ) +
+		curr_time_usec - info->last_tx_active_usec;
+
+	/*
+	 * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+	 * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+	 */
+	orig_jiffies = jiffies;
+	while (info->xmit.head != info->xmit.tail || /* More in send queue */
+	       (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
+	       (elapsed_usec < 2*info->char_time_usec)) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(1);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+		curr_time = jiffies;
+		curr_time_usec = GET_JIFFIES_USEC();
+		elapsed_usec =
+			(curr_time - info->last_tx_active) * (1000000/HZ) +
+			curr_time_usec - info->last_tx_active_usec;
+	}
+	set_current_state(TASK_RUNNING);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void
+rs_hangup(struct tty_struct *tty)
+{
+	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+		struct e100_serial *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long	flags;
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (tty->termios->c_cflag & CLOCAL) {
+			do_clocal = 1;
+	}
+
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttyS%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	save_flags(flags);
+	cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count++;
+		info->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		save_flags(flags);
+		cli();
+		/* assert RTS and DTR */
+		e100_rts(info, 1);
+		e100_dtr(info, 1);
+		restore_flags(flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CLOSING) && do_clocal)
+			/* && (do_clocal || DCD_IS_ASSERTED) */
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttyS%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+	if (extra_count)
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttyS%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.
+ * It performs the serial-specific initialization for the tty structure.
+ */
+static int
+rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct e100_serial	*info;
+	int 			retval, line;
+	unsigned long           page;
+
+	/* find which port we want to open */
+
+	line = tty->index;
+
+	if (line < 0 || line >= NR_PORTS)
+		return -ENODEV;
+
+	/* find the corresponding e100_serial struct in the table */
+	info = rs_table + line;
+
+	/* don't allow the opening of ports that are not enabled in the HW config */
+	if (!info->enabled)
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
+ 	       info->count);
+#endif
+
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	if (!tmp_buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		if (!page) {
+			return -ENOMEM;
+		}
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+
+	/*
+	 * If the port is in the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up the serial port
+	 */
+
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		*tty->termios = info->normal_termios;
+		change_speed(info);
+	}
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttyS%d successful...\n", info->line);
+#endif
+	DLOG_INT_TRIG( log_int_pos = 0);
+
+	DFLIP(	if (info->line == SERIAL_DEBUG_LINE) {
+			info->icount.rx = 0;
+		} );
+
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+extern _INLINE_ int line_info(char *buf, struct e100_serial *info)
+{
+	char	stat_buf[30];
+	int	ret;
+	unsigned long tmp;
+
+	ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
+		      info->line, (unsigned long)info->port, info->irq);
+
+	if (!info->port || (info->type == PORT_UNKNOWN)) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (!E100_RTS_GET(info))
+		strcat(stat_buf, "|RTS");
+	if (!E100_CTS_GET(info))
+		strcat(stat_buf, "|CTS");
+	if (!E100_DTR_GET(info))
+		strcat(stat_buf, "|DTR");
+	if (!E100_DSR_GET(info))
+		strcat(stat_buf, "|DSR");
+	if (!E100_CD_GET(info))
+		strcat(stat_buf, "|CD");
+	if (!E100_RI_GET(info))
+		strcat(stat_buf, "|RI");
+
+	ret += sprintf(buf+ret, " baud:%d", info->baud);
+
+	ret += sprintf(buf+ret, " tx:%lu rx:%lu",
+		       (unsigned long)info->icount.tx,
+		       (unsigned long)info->icount.rx);
+	tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+	if (tmp) {
+		ret += sprintf(buf+ret, " tx_pend:%lu/%lu",
+			       (unsigned long)tmp,
+			       (unsigned long)SERIAL_XMIT_SIZE);
+	}
+
+	ret += sprintf(buf+ret, " rx_pend:%lu/%lu",
+		       (unsigned long)info->recv_cnt,
+		       (unsigned long)info->max_recv_cnt);
+
+#if 1
+	if (info->tty) {
+
+		if (info->tty->stopped)
+			ret += sprintf(buf+ret, " stopped:%i",
+				       (int)info->tty->stopped);
+		if (info->tty->hw_stopped)
+			ret += sprintf(buf+ret, " hw_stopped:%i",
+				       (int)info->tty->hw_stopped);
+	}
+
+	{
+		unsigned char rstat = info->port[REG_STATUS];
+		if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) )
+			ret += sprintf(buf+ret, " xoff_detect:1");
+	}
+
+#endif
+
+
+
+
+	if (info->icount.frame)
+		ret += sprintf(buf+ret, " fe:%lu",
+			       (unsigned long)info->icount.frame);
+
+	if (info->icount.parity)
+		ret += sprintf(buf+ret, " pe:%lu",
+			       (unsigned long)info->icount.parity);
+
+	if (info->icount.brk)
+		ret += sprintf(buf+ret, " brk:%lu",
+			       (unsigned long)info->icount.brk);
+
+	if (info->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%lu",
+			       (unsigned long)info->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	return ret;
+}
+
+int rs_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int i, len = 0, l;
+	off_t	begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s\n",
+		       serial_version);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		if (!rs_table[i].enabled)
+			continue;
+		l = line_info(page + len, &rs_table[i]);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+#ifdef DEBUG_LOG_INCLUDED
+	for (i = 0; i < debug_log_pos; i++) {
+		len += sprintf(page + len, "%-4i %lu.%lu ", i, debug_log[i].time, timer_data_to_ns(debug_log[i].timer_data));
+		len += sprintf(page + len, debug_log[i].string, debug_log[i].value);
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	len += sprintf(page + len, "debug_log %i/%i  %li bytes\n",
+		       i, DEBUG_LOG_SIZE, begin+len);
+	debug_log_pos = 0;
+#endif
+
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void
+show_serial_version(void)
+{
+	printk(KERN_INFO
+	       "ETRAX 100LX serial-driver %s, (c) 2000-2004 Axis Communications AB\r\n",
+	       &serial_version[11]); /* "$Revision: x.yy" */
+}
+
+/* rs_init inits the driver at boot (using the module_init chain) */
+
+static struct tty_operations rs_ops = {
+	.open = rs_open,
+	.close = rs_close,
+	.write = rs_write,
+	.flush_chars = rs_flush_chars,
+	.write_room = rs_write_room,
+	.chars_in_buffer = rs_chars_in_buffer,
+	.flush_buffer = rs_flush_buffer,
+	.ioctl = rs_ioctl,
+	.throttle = rs_throttle,
+        .unthrottle = rs_unthrottle,
+	.set_termios = rs_set_termios,
+	.stop = rs_stop,
+	.start = rs_start,
+	.hangup = rs_hangup,
+	.break_ctl = rs_break,
+	.send_xchar = rs_send_xchar,
+	.wait_until_sent = rs_wait_until_sent,
+	.read_proc = rs_read_proc,
+};
+
+static int __init
+rs_init(void)
+{
+	int i;
+	struct e100_serial *info;
+	struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
+
+	if (!driver)
+		return -ENOMEM;
+
+	show_serial_version();
+
+	/* Setup the timed flush handler system */
+
+#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
+	init_timer(&flush_timer);
+	flush_timer.function = timed_flush_handler;
+	mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+#endif
+
+	/* Initialize the tty_driver structure */
+
+	driver->driver_name = "serial";
+	driver->name = "ttyS";
+	driver->major = TTY_MAJOR;
+	driver->minor_start = 64;
+	driver->type = TTY_DRIVER_TYPE_SERIAL;
+	driver->subtype = SERIAL_TYPE_NORMAL;
+	driver->init_termios = tty_std_termios;
+	driver->init_termios.c_cflag =
+		B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+	driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	driver->termios = serial_termios;
+	driver->termios_locked = serial_termios_locked;
+
+	tty_set_operations(driver, &rs_ops);
+        serial_driver = driver;
+	if (tty_register_driver(driver))
+		panic("Couldn't register serial driver\n");
+	/* do some initializing for the separate ports */
+
+	for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+		info->uses_dma_in = 0;
+		info->uses_dma_out = 0;
+		info->line = i;
+		info->tty = 0;
+		info->type = PORT_ETRAX;
+		info->tr_running = 0;
+		info->forced_eop = 0;
+		info->baud_base = DEF_BAUD_BASE;
+		info->custom_divisor = 0;
+		info->flags = 0;
+		info->close_delay = 5*HZ/10;
+		info->closing_wait = 30*HZ;
+		info->x_char = 0;
+		info->event = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		info->normal_termios = driver->init_termios;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		info->xmit.buf = NULL;
+		info->xmit.tail = info->xmit.head = 0;
+		info->first_recv_buffer = info->last_recv_buffer = NULL;
+		info->recv_cnt = info->max_recv_cnt = 0;
+		info->last_tx_active_usec = 0;
+		info->last_tx_active = 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+		/* Set sane defaults */
+		info->rs485.rts_on_send = 0;
+		info->rs485.rts_after_sent = 1;
+		info->rs485.delay_rts_before_send = 0;
+		info->rs485.enabled = 0;
+#endif
+		INIT_WORK(&info->work, do_softint, info);
+
+		if (info->enabled) {
+			printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
+			       serial_driver->name, info->line, (unsigned int)info->port);
+		}
+	}
+#ifdef CONFIG_ETRAX_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+	memset(fast_timers, 0, sizeof(fast_timers));
+#endif
+#ifdef CONFIG_ETRAX_RS485
+	memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
+#endif
+	fast_timer_init();
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+	/* Not needed in simulator.  May only complicate stuff. */
+	/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
+
+	if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
+		panic("irq8");
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+	if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
+		panic("irq22");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+	if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
+		panic("irq23");
+#endif
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+	if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
+		panic("irq24");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+	if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
+		panic("irq25");
+#endif
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	/* DMA Shared with par0 (and SCSI0 and ATA) */
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+	if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma tr", NULL))
+		panic("irq18");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+	if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma rec", NULL))
+		panic("irq19");
+#endif
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+	/* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+	if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma tr", NULL))
+		panic("irq20");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+	if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma rec", NULL))
+		panic("irq21");
+#endif
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+	if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT,
+		       "fast serial dma timeout", NULL)) {
+		printk(KERN_CRIT "err: timer1 irq\n");
+	}
+#endif
+#endif /* CONFIG_SVINTO_SIM */
+	debug_write_function = rs_debug_write_function;
+	return 0;
+}
+
+/* this makes sure that rs_init is called during kernel boot */
+
+module_init(rs_init);
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+int
+register_serial(struct serial_struct *req)
+{
+	return -1;
+}
+
+void unregister_serial(int line)
+{
+}
diff -puN /dev/null drivers/serial/crisv10.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/serial/crisv10.h	Mon Nov  8 14:19:37 2004
@@ -0,0 +1,137 @@
+/*
+ * serial.h: Arch-dep definitions for the Etrax100 serial driver.
+ *
+ * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ */
+
+#ifndef _ETRAX_SERIAL_H
+#define _ETRAX_SERIAL_H
+
+#include <linux/config.h>
+#include <linux/circ_buf.h>
+#include <asm/termios.h>
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+#define SERIAL_RECV_DESCRIPTORS 8
+
+struct etrax_recv_buffer {
+	struct etrax_recv_buffer *next;
+	unsigned short length;
+	unsigned char error;
+	unsigned char pad;
+
+	unsigned char buffer[0];
+};
+
+struct e100_serial {
+	int			baud;
+	volatile u8		*port; /* R_SERIALx_CTRL */
+	u32			irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+	/* Output registers */
+	volatile u8		*oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+	volatile u32		*ofirstadr;   /* adr to R_DMA_CHx_FIRST */
+	volatile u8		*ocmdadr;     /* adr to R_DMA_CHx_CMD */
+	const volatile u8	*ostatusadr;  /* adr to R_DMA_CHx_STATUS */
+
+	/* Input registers */
+	volatile u8		*iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+	volatile u32		*ifirstadr;   /* adr to R_DMA_CHx_FIRST */
+	volatile u8		*icmdadr;     /* adr to R_DMA_CHx_CMD */
+	volatile u32		*idescradr;   /* adr to R_DMA_CHx_DESCR */
+
+	int			flags;	/* defined in tty.h */
+
+	u8			rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+	u8			tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+	u8			iseteop; /* bit number for R_SET_EOP for the input dma */
+	int			enabled; /* Set to 1 if the port is enabled in HW config */
+
+	u8		dma_out_enabled:1; /* Set to 1 if DMA should be used */
+	u8		dma_in_enabled:1;  /* Set to 1 if DMA should be used */
+
+	/* end of fields defined in rs_table[] in .c-file */
+	u8		uses_dma_in;  /* Set to 1 if DMA is used */
+	u8		uses_dma_out; /* Set to 1 if DMA is used */
+	u8		forced_eop;   /* a fifo eop has been forced */
+	int			baud_base;     /* For special baudrates */
+	int			custom_divisor; /* For special baudrates */
+	struct etrax_dma_descr	tr_descr;
+	struct etrax_dma_descr	rec_descr[SERIAL_RECV_DESCRIPTORS];
+	int			cur_rec_descr;
+
+	volatile int		tr_running; /* 1 if output is running */
+
+	struct tty_struct	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			type;  /* PORT_ETRAX */
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	struct circ_buf		xmit;
+	struct etrax_recv_buffer *first_recv_buffer;
+	struct etrax_recv_buffer *last_recv_buffer;
+	unsigned int		recv_cnt;
+	unsigned int		max_recv_cnt;
+
+	struct work_struct	work;
+	struct async_icount	icount;   /* error-statistics etc.*/
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+#ifdef DECLARE_WAITQUEUE
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+#else
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+#endif
+
+	unsigned long		char_time_usec;       /* The time for 1 char, in usecs */
+	unsigned long		flush_time_usec;      /* How often we should flush */
+	unsigned long		last_tx_active_usec;  /* Last tx usec in the jiffies */
+	unsigned long		last_tx_active;       /* Last tx time in jiffies */
+	unsigned long		last_rx_active_usec;  /* Last rx usec in the jiffies */
+	unsigned long		last_rx_active;       /* Last rx time in jiffies */
+
+	int			break_detected_cnt;
+	int			errorcode;
+
+#ifdef CONFIG_ETRAX_RS485
+	struct rs485_control	rs485;  /* RS-485 support */
+#endif
+};
+
+/* this PORT is not in the standard serial.h. it's not actually used for
+ * anything since we only have one type of async serial-port anyway in this
+ * system.
+ */
+
+#define PORT_ETRAX 1
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+#endif /* __KERNEL__ */
+
+#endif /* !_ETRAX_SERIAL_H */
diff -puN /dev/null drivers/usb/host/hc_crisv10.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/usb/host/hc_crisv10.c	Mon Nov  8 14:19:37 2004
@@ -0,0 +1,4574 @@
+/*
+ * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
+ *
+ * Copyright (c) 2002, 2003 Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+
+#include <linux/usb.h>
+/* Ugly include because we don't live with the other host drivers. */
+#include <../drivers/usb/core/hcd.h>
+#include <../drivers/usb/core/usb.h>
+
+#include "usb-host.h"
+
+#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
+#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
+#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
+
+static const char *usb_hcd_version = "$Revision: 1.2 $";
+
+#undef KERN_DEBUG
+#define KERN_DEBUG ""
+
+
+#undef USB_DEBUG_RH
+#undef USB_DEBUG_EPID
+#undef USB_DEBUG_SB
+#undef USB_DEBUG_DESC
+#undef USB_DEBUG_URB
+#undef USB_DEBUG_TRACE
+#undef USB_DEBUG_BULK
+#undef USB_DEBUG_CTRL
+#undef USB_DEBUG_INTR
+#undef USB_DEBUG_ISOC
+
+#ifdef USB_DEBUG_RH
+#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
+#else
+#define dbg_rh(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_EPID
+#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)
+#else
+#define dbg_epid(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_SB
+#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)
+#else
+#define dbg_sb(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_CTRL
+#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
+#else
+#define dbg_ctrl(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_BULK
+#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
+#else
+#define dbg_bulk(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_INTR
+#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
+#else
+#define dbg_intr(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_ISOC
+#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)
+#else
+#define dbg_isoc(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_TRACE
+#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
+#define DBFEXIT  (printk(": Exiting:  %s\n", __FUNCTION__))
+#else
+#define DBFENTER do {} while (0)
+#define DBFEXIT  do {} while (0)
+#endif
+
+#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+static __u8 root_hub_dev_des[] =
+{
+	0x12,  /*  __u8  bLength; */
+	0x01,  /*  __u8  bDescriptorType; Device */
+	0x00,  /*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,  /*  __u8  bDeviceSubClass; */
+	0x00,  /*  __u8  bDeviceProtocol; */
+	0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,  /*  __u16 idVendor; */
+	0x00,
+	0x00,  /*  __u16 idProduct; */
+	0x00,
+	0x00,  /*  __u16 bcdDevice; */
+	0x00,
+	0x00,  /*  __u8  iManufacturer; */
+	0x02,  /*  __u8  iProduct; */
+	0x01,  /*  __u8  iSerialNumber; */
+	0x01   /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,  /*  __u8  bLength; */
+	0x02,  /*  __u8  bDescriptorType; Configuration */
+	0x19,  /*  __u16 wTotalLength; */
+	0x00,
+	0x01,  /*  __u8  bNumInterfaces; */
+	0x01,  /*  __u8  bConfigurationValue; */
+	0x00,  /*  __u8  iConfiguration; */
+	0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */
+	0x00,  /*  __u8  MaxPower; */
+
+     /* interface */
+	0x09,  /*  __u8  if_bLength; */
+	0x04,  /*  __u8  if_bDescriptorType; Interface */
+	0x00,  /*  __u8  if_bInterfaceNumber; */
+	0x00,  /*  __u8  if_bAlternateSetting; */
+	0x01,  /*  __u8  if_bNumEndpoints; */
+	0x09,  /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,  /*  __u8  if_bInterfaceSubClass; */
+	0x00,  /*  __u8  if_bInterfaceProtocol; */
+	0x00,  /*  __u8  if_iInterface; */
+
+     /* endpoint */
+	0x07,  /*  __u8  ep_bLength; */
+	0x05,  /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,  /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,  /*  __u8  ep_bmAttributes; Interrupt */
+	0x08,  /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff   /*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+	0x09,  /*  __u8  bLength; */
+	0x29,  /*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,  /*  __u8  bNbrPorts; */
+	0x00,  /* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,  /*  __u8  bHubContrCurrent; 0 mA */
+	0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0);
+
+/* We want the start timer to expire before the eot timer, because the former might start
+   traffic, thus making it unnecessary for the latter to time out. */
+#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */
+#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */
+
+#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break
+#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
+{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
+
+#define SLAB_FLAG     (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
+
+/* Most helpful debugging aid */
+#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
+
+/* Alternative assert define which stops after a failed assert. */
+/*
+#define assert(expr)                                      \
+{                                                         \
+        if (!(expr)) {                                    \
+                err("assert failed at line %d",__LINE__); \
+                while (1);                                \
+        }                                                 \
+}
+*/
+
+
+/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?
+   To adjust it dynamically we would have to get an interrupt when we reach the end
+   of the rx descriptor list, or when we get close to the end, and then allocate more
+   descriptors. */
+
+#define NBR_OF_RX_DESC     512
+#define RX_DESC_BUF_SIZE   1024
+#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
+
+/* The number of epids is, among other things, used for pre-allocating
+   ctrl, bulk and isoc EP descriptors (one for each epid).
+   Assumed to be > 1 when initiating the DMA lists. */
+#define NBR_OF_EPIDS       32
+
+/* Support interrupt traffic intervals up to 128 ms. */
+#define MAX_INTR_INTERVAL 128
+
+/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table
+   must be "invalid". By this we mean that we shouldn't care about epid attentions
+   for this epid, or at least handle them differently from epid attentions for "valid"
+   epids. This define determines which one to use (don't change it). */
+#define INVALID_EPID     31
+/* A special epid for the bulk dummys. */
+#define DUMMY_EPID       30
+
+/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */
+static __u32 epid_usage_bitmask;
+
+/* A bitfield to keep information on in/out traffic is needed to uniquely identify
+   an endpoint on a device, since the most significant bit which indicates traffic
+   direction is lacking in the ep_id field (ETRAX epids can handle both in and
+   out traffic on endpoints that are otherwise identical). The USB framework, however,
+   relies on them to be handled separately.  For example, bulk IN and OUT urbs cannot
+   be queued in the same list, since they would block each other. */
+static __u32 epid_out_traffic;
+
+/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
+   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */
+static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
+static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
+
+/* Pointers into RxDescList. */
+static volatile USB_IN_Desc_t *myNextRxDesc;
+static volatile USB_IN_Desc_t *myLastRxDesc;
+static volatile USB_IN_Desc_t *myPrevRxDesc;
+
+/* EP descriptors must be 32-bit aligned. */
+static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,
+   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
+   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
+   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
+   in each frame. */
+static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
+
+static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));
+
+static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
+static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
+
+/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting
+   this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0
+   results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point
+   it to this buffer. */
+static int zout_buffer[4] __attribute__ ((aligned (4)));
+
+/* Cache for allocating new EP and SB descriptors. */
+static kmem_cache_t *usb_desc_cache;
+
+/* Cache for the registers allocated in the top half. */
+static kmem_cache_t *top_half_reg_cache;
+
+/* Cache for the data allocated in the isoc descr top half. */
+static kmem_cache_t *isoc_compl_cache;
+
+static struct usb_bus *etrax_usb_bus;
+
+/* This is a circular (double-linked) list of the active urbs for each epid.
+   The head is never removed, and new urbs are linked onto the list as
+   urb_entry_t elements. Don't reference urb_list directly; use the wrapper
+   functions instead. Note that working with these lists might require spinlock
+   protection. */
+static struct list_head urb_list[NBR_OF_EPIDS];
+
+/* Read about the need and usage of this lock in submit_ctrl_urb. */
+static spinlock_t urb_list_lock;
+
+/* Used when unlinking asynchronously. */
+static struct list_head urb_unlink_list;
+
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *ascii++ & 0x7f;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+	char buf [30];
+
+	// assert (len > (2 * (sizeof (buf) + 1)));
+	// assert (strlen (type) <= 8);
+
+	// language ids
+	if (id == 0) {
+		*data++ = 4; *data++ = 3;	/* 4 bytes data */
+		*data++ = 0; *data++ = 0;	/* some language id */
+		return 4;
+
+	// serial number
+	} else if (id == 1) {
+		sprintf (buf, "%x", serial);
+
+	// product description
+	} else if (id == 2) {
+		sprintf (buf, "USB %s Root Hub", type);
+
+	// id 3 == vendor description
+
+	// unsupported IDs --> "stall"
+	} else
+	    return 0;
+
+	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [1] = 3;
+	return data [0];
+}
+
+/* Wrappers around the list functions (include/linux/list.h). */
+
+static inline int urb_list_empty(int epid)
+{
+	return list_empty(&urb_list[epid]);
+}
+
+/* Returns first urb for this epid, or NULL if list is empty. */
+static inline struct urb *urb_list_first(int epid)
+{
+	struct urb *first_urb = 0;
+
+	if (!urb_list_empty(epid)) {
+		/* Get the first urb (i.e. head->next). */
+		urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
+		first_urb = urb_entry->urb;
+	}
+	return first_urb;
+}
+
+/* Adds an urb_entry last in the list for this epid. */
+static inline void urb_list_add(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
+	assert(urb_entry);
+
+	urb_entry->urb = urb;
+	list_add_tail(&urb_entry->list, &urb_list[epid]);
+}
+
+/* Search through the list for an element that contains this urb. (The list
+   is expected to be short and the one we are about to delete will often be
+   the first in the list.) */
+static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid)
+{
+	struct list_head *entry;
+	struct list_head *tmp;
+	urb_entry_t *urb_entry;
+
+	list_for_each_safe(entry, tmp, &urb_list[epid]) {
+		urb_entry = list_entry(entry, urb_entry_t, list);
+		assert(urb_entry);
+		assert(urb_entry->urb);
+
+		if (urb_entry->urb == urb) {
+			return urb_entry;
+		}
+	}
+	return 0;
+}
+
+/* Delete an urb from the list. */
+static inline void urb_list_del(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+	assert(urb_entry);
+
+	/* Delete entry and free. */
+	list_del(&urb_entry->list);
+	kfree(urb_entry);
+}
+
+/* Move an urb to the end of the list. */
+static inline void urb_list_move_last(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+	assert(urb_entry);
+
+	list_del(&urb_entry->list);
+	list_add_tail(&urb_entry->list, &urb_list[epid]);
+}
+
+/* Get the next urb in the list. */
+static inline struct urb *urb_list_next(struct urb *urb, int epid)
+{
+	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+
+	assert(urb_entry);
+
+	if (urb_entry->list.next != &urb_list[epid]) {
+		struct list_head *elem = urb_entry->list.next;
+		urb_entry = list_entry(elem, urb_entry_t, list);
+		return urb_entry->urb;
+	} else {
+		return NULL;
+	}
+}
+
+
+
+/* For debug purposes only. */
+static inline void urb_list_dump(int epid)
+{
+	struct list_head *entry;
+	struct list_head *tmp;
+	urb_entry_t *urb_entry;
+	int i = 0;
+
+	info("Dumping urb list for epid %d", epid);
+
+	list_for_each_safe(entry, tmp, &urb_list[epid]) {
+		urb_entry = list_entry(entry, urb_entry_t, list);
+		info("   entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb);
+	}
+}
+
+static void init_rx_buffers(void);
+static int etrax_rh_unlink_urb(struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
+static void etrax_rh_int_timer_do(unsigned long ptr);
+
+static int etrax_usb_setup_epid(struct urb *urb);
+static int etrax_usb_lookup_epid(struct urb *urb);
+static int etrax_usb_allocate_epid(void);
+static void etrax_usb_free_epid(int epid);
+
+static int etrax_remove_from_sb_list(struct urb *urb);
+
+static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma);
+static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);
+
+static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid);
+
+static int etrax_usb_submit_bulk_urb(struct urb *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
+static int etrax_usb_submit_intr_urb(struct urb *urb);
+static int etrax_usb_submit_isoc_urb(struct urb *urb);
+
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags);
+static int etrax_usb_unlink_urb(struct urb *urb, int status);
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
+static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
+static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
+
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
+static void etrax_usb_hc_interrupt_bottom_half(void *data);
+
+static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
+
+
+/* The following is a list of interrupt handlers for the host controller interrupts we use.
+   They are called from etrax_usb_hc_interrupt_bottom_half. */
+static void etrax_usb_hc_isoc_eof_interrupt(void);
+static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);
+static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);
+static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);
+static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);
+
+static int etrax_rh_submit_urb (struct urb *urb);
+
+/* Forward declaration needed because they are used in the rx interrupt routine. */
+static void etrax_usb_complete_urb(struct urb *urb, int status);
+static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);
+static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);
+static void etrax_usb_complete_intr_urb(struct urb *urb, int status);
+static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);
+
+static int etrax_usb_hc_init(void);
+static void etrax_usb_hc_cleanup(void);
+
+static struct usb_operations etrax_usb_device_operations =
+{
+	.allocate = etrax_usb_allocate_dev,
+	.deallocate = etrax_usb_deallocate_dev,
+	.get_frame_number = etrax_usb_get_frame_number,
+	.submit_urb = etrax_usb_submit_urb,
+	.unlink_urb = etrax_usb_unlink_urb,
+        .buffer_alloc = etrax_usb_buffer_alloc,
+        .buffer_free = etrax_usb_buffer_free
+};
+
+/* Note that these functions are always available in their "__" variants, for use in
+   error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/
+   USB_DEBUG_URB macros. */
+static void __dump_urb(struct urb* purb)
+{
+	printk("\nurb                  :0x%08lx\n", (unsigned long)purb);
+	printk("dev                   :0x%08lx\n", (unsigned long)purb->dev);
+	printk("pipe                  :0x%08x\n", purb->pipe);
+	printk("status                :%d\n", purb->status);
+	printk("transfer_flags        :0x%08x\n", purb->transfer_flags);
+	printk("transfer_buffer       :0x%08lx\n", (unsigned long)purb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
+	printk("actual_length         :%d\n", purb->actual_length);
+	printk("setup_packet          :0x%08lx\n", (unsigned long)purb->setup_packet);
+	printk("start_frame           :%d\n", purb->start_frame);
+	printk("number_of_packets     :%d\n", purb->number_of_packets);
+	printk("interval              :%d\n", purb->interval);
+	printk("error_count           :%d\n", purb->error_count);
+	printk("context               :0x%08lx\n", (unsigned long)purb->context);
+	printk("complete              :0x%08lx\n\n", (unsigned long)purb->complete);
+}
+
+static void __dump_in_desc(volatile USB_IN_Desc_t *in)
+{
+	printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
+	printk("  sw_len  : 0x%04x (%d)\n", in->sw_len, in->sw_len);
+	printk("  command : 0x%04x\n", in->command);
+	printk("  next    : 0x%08lx\n", in->next);
+	printk("  buf     : 0x%08lx\n", in->buf);
+	printk("  hw_len  : 0x%04x (%d)\n", in->hw_len, in->hw_len);
+	printk("  status  : 0x%04x\n\n", in->status);
+}
+
+static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
+{
+	char tt = (sb->command & 0x30) >> 4;
+	char *tt_string;
+
+	switch (tt) {
+	case 0:
+		tt_string = "zout";
+		break;
+	case 1:
+		tt_string = "in";
+		break;
+	case 2:
+		tt_string = "out";
+		break;
+	case 3:
+		tt_string = "setup";
+		break;
+	default:
+		tt_string = "unknown (weird)";
+	}
+
+	printk("\n   USB_SB_Desc at 0x%08lx\n", (unsigned long)sb);
+	printk("     command : 0x%04x\n", sb->command);
+	printk("        rem     : %d\n", (sb->command & 0x3f00) >> 8);
+	printk("        full    : %d\n", (sb->command & 0x40) >> 6);
+	printk("        tt      : %d (%s)\n", tt, tt_string);
+	printk("        intr    : %d\n", (sb->command & 0x8) >> 3);
+	printk("        eot     : %d\n", (sb->command & 0x2) >> 1);
+	printk("        eol     : %d\n", sb->command & 0x1);
+	printk("     sw_len  : 0x%04x (%d)\n", sb->sw_len, sb->sw_len);
+	printk("     next    : 0x%08lx\n", sb->next);
+	printk("     buf     : 0x%08lx\n\n", sb->buf);
+}
+
+
+static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
+{
+	printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep);
+	printk("  command : 0x%04x\n", ep->command);
+	printk("     ep_id   : %d\n", (ep->command & 0x1f00) >> 8);
+	printk("     enable  : %d\n", (ep->command & 0x10) >> 4);
+	printk("     intr    : %d\n", (ep->command & 0x8) >> 3);
+	printk("     eof     : %d\n", (ep->command & 0x2) >> 1);
+	printk("     eol     : %d\n", ep->command & 0x1);
+	printk("  hw_len  : 0x%04x (%d)\n", ep->hw_len, ep->hw_len);
+	printk("  next    : 0x%08lx\n", ep->next);
+	printk("  sub     : 0x%08lx\n\n", ep->sub);
+}
+
+static inline void __dump_ep_list(int pipe_type)
+{
+	volatile USB_EP_Desc_t *ep;
+	volatile USB_EP_Desc_t *first_ep;
+	volatile USB_SB_Desc_t *sb;
+
+	switch (pipe_type)
+	{
+	case PIPE_BULK:
+		first_ep = &TxBulkEPList[0];
+		break;
+	case PIPE_CONTROL:
+		first_ep = &TxCtrlEPList[0];
+		break;
+	case PIPE_INTERRUPT:
+		first_ep = &TxIntrEPList[0];
+		break;
+	case PIPE_ISOCHRONOUS:
+		first_ep = &TxIsocEPList[0];
+		break;
+	default:
+		warn("Cannot dump unknown traffic type");
+		return;
+	}
+	ep = first_ep;
+
+	printk("\n\nDumping EP list...\n\n");
+
+	do {
+		__dump_ep_desc(ep);
+		/* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
+		sb = ep->sub ? phys_to_virt(ep->sub) : 0;
+		while (sb) {
+			__dump_sb_desc(sb);
+			sb = sb->next ? phys_to_virt(sb->next) : 0;
+		}
+		ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next));
+
+	} while (ep != first_ep);
+}
+
+static inline void __dump_ept_data(int epid)
+{
+	unsigned long flags;
+	__u32 r_usb_ept_data;
+
+	if (epid < 0 || epid > 31) {
+		printk("Cannot dump ept data for invalid epid %d\n", epid);
+		return;
+	}
+
+	save_flags(flags);
+	cli();
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	r_usb_ept_data = *R_USB_EPT_DATA;
+	restore_flags(flags);
+
+	printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
+	if (r_usb_ept_data == 0) {
+		/* No need for more detailed printing. */
+		return;
+	}
+	printk("  valid           : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
+	printk("  hold            : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
+	printk("  error_count_in  : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
+	printk("  t_in            : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
+	printk("  low_speed       : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
+	printk("  port            : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
+	printk("  error_code      : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
+	printk("  t_out           : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
+	printk("  error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
+	printk("  max_len         : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
+	printk("  ep              : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
+	printk("  dev             : %d\n", (r_usb_ept_data & 0x0000003f));
+}
+
+static inline void __dump_ept_data_list(void)
+{
+	int i;
+
+	printk("Dumping the whole R_USB_EPT_DATA list\n");
+
+	for (i = 0; i < 32; i++) {
+		__dump_ept_data(i);
+	}
+}
+#ifdef USB_DEBUG_DESC
+#define dump_in_desc(...) __dump_in_desc(...)
+#define dump_sb_desc(...) __dump_sb_desc(...)
+#define dump_ep_desc(...) __dump_ep_desc(...)
+#else
+#define dump_in_desc(...) do {} while (0)
+#define dump_sb_desc(...) do {} while (0)
+#define dump_ep_desc(...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_URB
+#define dump_urb(x)     __dump_urb(x)
+#else
+#define dump_urb(x)     do {} while (0)
+#endif
+
+static void init_rx_buffers(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+		RxDescList[i].command = 0;
+		RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
+		RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+		RxDescList[i].hw_len = 0;
+		RxDescList[i].status = 0;
+
+		/* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc
+		   for the relevant fields.) */
+		prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
+
+	}
+
+	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+	RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
+	RxDescList[i].next = virt_to_phys(&RxDescList[0]);
+	RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+	RxDescList[i].hw_len = 0;
+	RxDescList[i].status = 0;
+
+	myNextRxDesc = &RxDescList[0];
+	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+
+	*R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
+	*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void init_tx_bulk_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+		CHECK_ALIGN(&TxBulkEPList[i]);
+		TxBulkEPList[i].hw_len = 0;
+		TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxBulkEPList[i].sub = 0;
+		TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]);
+
+		/* Initiate two EPs, disabled and with the eol flag set. No need for any
+		   preserved epid. */
+
+		/* The first one has the intr flag set so we get an interrupt when the DMA
+		   channel is about to become disabled. */
+		CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
+		TxBulkDummyEPList[i][0].hw_len = 0;
+		TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
+						   IO_STATE(USB_EP_command, eol, yes) |
+						   IO_STATE(USB_EP_command, intr, yes));
+		TxBulkDummyEPList[i][0].sub = 0;
+		TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
+
+		/* The second one. */
+		CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
+		TxBulkDummyEPList[i][1].hw_len = 0;
+		TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
+						   IO_STATE(USB_EP_command, eol, yes));
+		TxBulkDummyEPList[i][1].sub = 0;
+		/* The last dummy's next pointer is the same as the current EP's next pointer. */
+		TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
+	}
+
+	/* Configure the last one. */
+	CHECK_ALIGN(&TxBulkEPList[i]);
+	TxBulkEPList[i].hw_len = 0;
+	TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
+				   IO_FIELD(USB_EP_command, epid, i));
+	TxBulkEPList[i].sub = 0;
+	TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]);
+
+	/* No need configuring dummy EPs for the last one as it will never be used for
+	   bulk traffic (i == INVALD_EPID at this point). */
+
+	/* Set up to start on the last EP so we will enable it when inserting traffic
+	   for the first time (imitating the situation where the DMA has stopped
+	   because there was no more traffic). */
+	*R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
+	/* No point in starting the bulk channel yet.
+	 *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
+	DBFEXIT;
+}
+
+static void init_tx_ctrl_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+		CHECK_ALIGN(&TxCtrlEPList[i]);
+		TxCtrlEPList[i].hw_len = 0;
+		TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxCtrlEPList[i].sub = 0;
+		TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]);
+	}
+
+	CHECK_ALIGN(&TxCtrlEPList[i]);
+	TxCtrlEPList[i].hw_len = 0;
+	TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
+				   IO_FIELD(USB_EP_command, epid, i));
+
+	TxCtrlEPList[i].sub = 0;
+	TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
+
+	*R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
+	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+
+static void init_tx_intr_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	/* Read comment at zout_buffer declaration for an explanation to this. */
+	TxIntrSB_zout.sw_len = 1;
+	TxIntrSB_zout.next = 0;
+	TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
+	TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
+				 IO_STATE(USB_SB_command, tt, zout) |
+				 IO_STATE(USB_SB_command, full, yes) |
+				 IO_STATE(USB_SB_command, eot, yes) |
+				 IO_STATE(USB_SB_command, eol, yes));
+
+	for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
+		CHECK_ALIGN(&TxIntrEPList[i]);
+		TxIntrEPList[i].hw_len = 0;
+		TxIntrEPList[i].command =
+			(IO_STATE(USB_EP_command, eof, yes) |
+			 IO_STATE(USB_EP_command, enable, yes) |
+			 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+		TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+		TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
+	}
+
+	CHECK_ALIGN(&TxIntrEPList[i]);
+	TxIntrEPList[i].hw_len = 0;
+	TxIntrEPList[i].command =
+		(IO_STATE(USB_EP_command, eof, yes) |
+		 IO_STATE(USB_EP_command, eol, yes) |
+		 IO_STATE(USB_EP_command, enable, yes) |
+		 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+	TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+	TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
+
+	*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+	DBFEXIT;
+}
+
+static void init_tx_isoc_ep(void)
+{
+	int i;
+
+	DBFENTER;
+
+	/* Read comment at zout_buffer declaration for an explanation to this. */
+	TxIsocSB_zout.sw_len = 1;
+	TxIsocSB_zout.next = 0;
+	TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
+	TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
+				 IO_STATE(USB_SB_command, tt, zout) |
+				 IO_STATE(USB_SB_command, full, yes) |
+				 IO_STATE(USB_SB_command, eot, yes) |
+				 IO_STATE(USB_SB_command, eol, yes));
+
+	/* The last isochronous EP descriptor is a dummy. */
+
+	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+		CHECK_ALIGN(&TxIsocEPList[i]);
+		TxIsocEPList[i].hw_len = 0;
+		TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+		TxIsocEPList[i].sub = 0;
+		TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
+	}
+
+	CHECK_ALIGN(&TxIsocEPList[i]);
+	TxIsocEPList[i].hw_len = 0;
+
+	/* Must enable the last EP descr to get eof interrupt. */
+	TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
+				   IO_STATE(USB_EP_command, eof, yes) |
+				   IO_STATE(USB_EP_command, eol, yes) |
+				   IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+	TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
+	TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
+
+	*R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
+	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_unlink_intr_urb(struct urb *urb)
+{
+	volatile USB_EP_Desc_t *first_ep;  /* First EP in the list. */
+	volatile USB_EP_Desc_t *curr_ep;   /* Current EP, the iterator. */
+	volatile USB_EP_Desc_t *next_ep;   /* The EP after current. */
+	volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */
+
+	int epid;
+
+	/* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */
+
+	DBFENTER;
+
+	epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;
+
+	first_ep = &TxIntrEPList[0];
+	curr_ep = first_ep;
+
+
+	/* Note that this loop removes all EP descriptors with this epid. This assumes
+	   that all EP descriptors belong to the one and only urb for this epid. */
+
+	do {
+		next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);
+
+		if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
+
+			dbg_intr("Found EP to unlink for epid %d", epid);
+
+			/* This is the one we should unlink. */
+			unlink_ep = next_ep;
+
+			/* Actually unlink the EP from the DMA list. */
+			curr_ep->next = unlink_ep->next;
+
+			/* Wait until the DMA is no longer at this descriptor. */
+			while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));
+
+			/* Now we are free to remove it and its SB descriptor.
+			   Note that it is assumed here that there is only one sb in the
+			   sb list for this ep. */
+			kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));
+			kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);
+		}
+
+		curr_ep = phys_to_virt(curr_ep->next);
+
+	} while (curr_ep != first_ep);
+        urb->hcpriv = NULL;
+}
+
+void etrax_usb_do_intr_recover(int epid)
+{
+	USB_EP_Desc_t *first_ep, *tmp_ep;
+
+	DBFENTER;
+
+	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
+	tmp_ep = first_ep;
+
+	/* What this does is simply to walk the list of interrupt
+	   ep descriptors and enable those that are disabled. */
+
+	do {
+		if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
+		    !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
+			tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
+		}
+
+		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
+
+	} while (tmp_ep != first_ep);
+
+
+	DBFEXIT;
+}
+
+static int etrax_rh_unlink_urb (struct urb *urb)
+{
+	etrax_hc_t *hc;
+
+	DBFENTER;
+
+	hc = urb->dev->bus->hcpriv;
+
+	if (hc->rh.urb == urb) {
+		hc->rh.send = 0;
+		del_timer(&hc->rh.rh_int_timer);
+	}
+
+	DBFEXIT;
+	return 0;
+}
+
+static void etrax_rh_send_irq(struct urb *urb)
+{
+	__u16 data = 0;
+	etrax_hc_t *hc = urb->dev->bus->hcpriv;
+	DBFENTER;
+
+/*
+  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);
+  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
+*/
+
+	data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
+	data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
+
+	*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
+	/* FIXME: Why is actual_length set to 1 when data is 2 bytes?
+	   Since only 1 byte is used, why not declare data as __u8? */
+	urb->actual_length = 1;
+	urb->status = 0;
+
+	if (hc->rh.send && urb->complete) {
+		dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);
+		dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
+
+		urb->complete(urb, NULL);
+	}
+
+	DBFEXIT;
+}
+
+static void etrax_rh_init_int_timer(struct urb *urb)
+{
+	etrax_hc_t *hc;
+
+	DBFENTER;
+
+	hc = urb->dev->bus->hcpriv;
+	hc->rh.interval = urb->interval;
+	init_timer(&hc->rh.rh_int_timer);
+	hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
+	hc->rh.rh_int_timer.data = (unsigned long)urb;
+	/* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped
+	   to 0, and the rest to the nearest lower 10 ms. */
+	hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
+	add_timer(&hc->rh.rh_int_timer);
+
+	DBFEXIT;
+}
+
+static void etrax_rh_int_timer_do(unsigned long ptr)
+{
+	struct urb *urb;
+	etrax_hc_t *hc;
+
+	DBFENTER;
+
+	urb = (struct urb*)ptr;
+	hc = urb->dev->bus->hcpriv;
+
+	if (hc->rh.send) {
+		etrax_rh_send_irq(urb);
+	}
+
+	DBFEXIT;
+}
+
+static int etrax_usb_setup_epid(struct urb *urb)
+{
+	int epid;
+	char devnum, endpoint, out_traffic, slow;
+	int maxlen;
+	unsigned long flags;
+
+	DBFENTER;
+
+	epid = etrax_usb_lookup_epid(urb);
+	if ((epid != -1)){
+		/* An epid that fits this urb has been found. */
+		DBFEXIT;
+		return epid;
+	}
+
+	/* We must find and initiate a new epid for this urb. */
+	epid = etrax_usb_allocate_epid();
+
+	if (epid == -1) {
+		/* Failed to allocate a new epid. */
+		DBFEXIT;
+		return epid;
+	}
+
+	/* We now have a new epid to use. Initiate it. */
+	set_bit(epid, (void *)&epid_usage_bitmask);
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	slow = usb_pipeslow(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
+		out_traffic = 1;
+	} else {
+		out_traffic = usb_pipeout(urb->pipe);
+	}
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		*R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
+			/* FIXME: Change any to the actual port? */
+			IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
+			IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
+			IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
+			IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
+	} else {
+		*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
+			IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
+			/* FIXME: Change any to the actual port? */
+			IO_STATE(R_USB_EPT_DATA, port, any) |
+			IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
+			IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
+			IO_FIELD(R_USB_EPT_DATA, dev, devnum);
+	}
+
+	restore_flags(flags);
+
+	if (out_traffic) {
+		set_bit(epid, (void *)&epid_out_traffic);
+	} else {
+		clear_bit(epid, (void *)&epid_out_traffic);
+	}
+
+	dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",
+		 epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");
+
+	DBFEXIT;
+	return epid;
+}
+
+static void etrax_usb_free_epid(int epid)
+{
+	unsigned long flags;
+
+	DBFENTER;
+
+	if (!test_bit(epid, (void *)&epid_usage_bitmask)) {
+		warn("Trying to free unused epid %d", epid);
+		DBFEXIT;
+		return;
+	}
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));
+	/* This will, among other things, set the valid field to 0. */
+	*R_USB_EPT_DATA = 0;
+	restore_flags(flags);
+
+	clear_bit(epid, (void *)&epid_usage_bitmask);
+
+
+	dbg_epid("Freed epid %d", epid);
+
+	DBFEXIT;
+}
+
+static int etrax_usb_lookup_epid(struct urb *urb)
+{
+	int i;
+	__u32 data;
+	char devnum, endpoint, slow, out_traffic;
+	int maxlen;
+	unsigned long flags;
+
+	DBFENTER;
+
+	devnum = usb_pipedevice(urb->pipe);
+	endpoint = usb_pipeendpoint(urb->pipe);
+	slow = usb_pipeslow(urb->pipe);
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
+		out_traffic = 1;
+	} else {
+		out_traffic = usb_pipeout(urb->pipe);
+	}
+
+	/* Step through att epids. */
+	for (i = 0; i < NBR_OF_EPIDS; i++) {
+		if (test_bit(i, (void *)&epid_usage_bitmask) &&
+		    test_bit(i, (void *)&epid_out_traffic) == out_traffic) {
+
+			save_flags(flags);
+			cli();
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
+			nop();
+
+			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+				data = *R_USB_EPT_DATA_ISO;
+				restore_flags(flags);
+
+				if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {
+					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
+						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
+					DBFEXIT;
+					return i;
+				}
+			} else {
+				data = *R_USB_EPT_DATA;
+				restore_flags(flags);
+
+				if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {
+					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
+						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
+					DBFEXIT;
+					return i;
+				}
+			}
+		}
+	}
+
+	DBFEXIT;
+	return -1;
+}
+
+static int etrax_usb_allocate_epid(void)
+{
+	int i;
+
+	DBFENTER;
+
+	for (i = 0; i < NBR_OF_EPIDS; i++) {
+		if (!test_bit(i, (void *)&epid_usage_bitmask)) {
+			dbg_epid("Found free epid %d", i);
+			DBFEXIT;
+			return i;
+		}
+	}
+
+	dbg_epid("Found no free epids");
+	DBFEXIT;
+	return -1;
+}
+
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags)
+{
+	etrax_hc_t *hc;
+	int ret = -EINVAL;
+
+	DBFENTER;
+
+	if (!urb->dev || !urb->dev->bus) {
+		return -ENODEV;
+	}
+	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
+		info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe);
+		return -EMSGSIZE;
+	}
+
+	if (urb->timeout) {
+		/* FIXME. */
+		warn("urb->timeout specified, ignoring.");
+	}
+
+	hc = (etrax_hc_t*)urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+		/* This request is for the Virtual Root Hub. */
+		ret = etrax_rh_submit_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+		ret = etrax_usb_submit_bulk_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+		ret = etrax_usb_submit_ctrl_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+		int bustime;
+
+		if (urb->bandwidth == 0) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				ret = bustime;
+			} else {
+				ret = etrax_usb_submit_intr_urb(urb);
+				if (ret == 0)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else {
+			/* Bandwidth already set. */
+			ret = etrax_usb_submit_intr_urb(urb);
+		}
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		int bustime;
+
+		if (urb->bandwidth == 0) {
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				ret = bustime;
+			} else {
+				ret = etrax_usb_submit_isoc_urb(urb);
+				if (ret == 0)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else {
+			/* Bandwidth already set. */
+			ret = etrax_usb_submit_isoc_urb(urb);
+		}
+	}
+
+	DBFEXIT;
+
+        if (ret != 0)
+          printk("Submit URB error %d\n", ret);
+
+	return ret;
+}
+
+static int etrax_usb_unlink_urb(struct urb *urb, int status)
+{
+	etrax_hc_t *hc;
+	etrax_urb_priv_t *urb_priv;
+	int epid;
+	unsigned int flags;
+
+	DBFENTER;
+
+	if (!urb) {
+		return -EINVAL;
+	}
+
+	/* Disable interrupts here since a descriptor interrupt for the isoc epid
+	   will modify the sb list.  This could possibly be done more granular, but
+	   unlink_urb should not be used frequently anyway.
+	*/
+
+	save_flags(flags);
+	cli();
+
+	if (!urb->dev || !urb->dev->bus) {
+		restore_flags(flags);
+		return -ENODEV;
+	}
+	if (!urb->hcpriv) {
+		/* This happens if a device driver calls unlink on an urb that
+		   was never submitted (lazy driver) or if the urb was completed
+		   while unlink was being called. */
+		restore_flags(flags);
+		return 0;
+	}
+	if (urb->transfer_flags & URB_ASYNC_UNLINK) {
+		/* FIXME. */
+		/* If URB_ASYNC_UNLINK is set:
+		   unlink
+		   move to a separate urb list
+		   call complete at next sof with ECONNRESET
+
+		   If not:
+		   wait 1 ms
+		   unlink
+		   call complete with ENOENT
+		*/
+		warn("URB_ASYNC_UNLINK set, ignoring.");
+	}
+
+	/* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking,
+	   but that doesn't work for interrupt and isochronous traffic since they are completed
+	   repeatedly, and urb->status is set then. That may in itself be a bug though. */
+
+	hc = urb->dev->bus->hcpriv;
+	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	epid = urb_priv->epid;
+
+	/* Set the urb status (synchronous unlink). */
+	urb->status = -ENOENT;
+	urb_priv->urb_state = UNLINK;
+
+	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+		int ret;
+		ret = etrax_rh_unlink_urb(urb);
+		DBFEXIT;
+		restore_flags(flags);
+		return ret;
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+		dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb);
+
+		if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+			/* The EP was enabled, disable it and wait. */
+			TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+			/* Ah, the luxury of busy-wait. */
+			while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));
+		}
+		/* Kicking dummy list out of the party. */
+		TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+		dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb);
+
+		if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+			/* The EP was enabled, disable it and wait. */
+			TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+			/* Ah, the luxury of busy-wait. */
+			while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));
+		}
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+
+		dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb);
+
+		/* Separate function because it's a tad more complicated. */
+		etrax_usb_unlink_intr_urb(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+		dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb);
+
+		if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+			/* The EP was enabled, disable it and wait. */
+			TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+			/* Ah, the luxury of busy-wait. */
+			while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
+		}
+	}
+
+	/* Note that we need to remove the urb from the urb list *before* removing its SB
+	   descriptors. (This means that the isoc eof handler might get a null urb when we
+	   are unlinking the last urb.) */
+
+	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+		urb_list_del(urb, epid);
+		TxBulkEPList[epid].sub = 0;
+		etrax_remove_from_sb_list(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+		urb_list_del(urb, epid);
+		TxCtrlEPList[epid].sub = 0;
+		etrax_remove_from_sb_list(urb);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+
+		urb_list_del(urb, epid);
+		/* Sanity check (should never happen). */
+		assert(urb_list_empty(epid));
+
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 0);
+
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+		if (usb_pipeout(urb->pipe)) {
+
+			USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb;
+
+			if (__urb_list_entry(urb, epid)) {
+
+				urb_list_del(urb, epid);
+				iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
+				prev_sb = 0;
+				while (iter_sb && (iter_sb != urb_priv->first_sb)) {
+					prev_sb = iter_sb;
+					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+				}
+
+				if (iter_sb == 0) {
+					/* Unlink of the URB currently being transmitted. */
+					prev_sb = 0;
+					iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
+				}
+
+				while (iter_sb && (iter_sb != urb_priv->last_sb)) {
+					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+				}
+				if (iter_sb) {
+					next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+				} else {
+					/* This should only happen if the DMA has completed
+					   processing the SB list for this EP while interrupts
+					   are disabled. */
+					dbg_isoc("Isoc urb not found, already sent?");
+					next_sb = 0;
+				}
+				if (prev_sb) {
+					prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
+				} else {
+					TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
+				}
+
+				etrax_remove_from_sb_list(urb);
+				if (urb_list_empty(epid)) {
+					TxIsocEPList[epid].sub = 0;
+					dbg_isoc("Last isoc out urb epid %d", epid);
+				} else if (next_sb || prev_sb) {
+					dbg_isoc("Re-enable isoc out epid %d", epid);
+
+					TxIsocEPList[epid].hw_len = 0;
+					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+				} else {
+					TxIsocEPList[epid].sub = 0;
+					dbg_isoc("URB list non-empty and no SB list, EP disabled");
+				}
+			} else {
+				dbg_isoc("Urb 0x%p not found, completed already?", urb);
+			}
+		} else {
+
+			urb_list_del(urb, epid);
+
+			/* For in traffic there is only one SB descriptor for each EP even
+			   though there may be several urbs (all urbs point at the same SB). */
+			if (urb_list_empty(epid)) {
+				/* No more urbs, remove the SB. */
+				TxIsocEPList[epid].sub = 0;
+				etrax_remove_from_sb_list(urb);
+			} else {
+				TxIsocEPList[epid].hw_len = 0;
+				TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+			}
+		}
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 1);
+	}
+	/* Free the epid if urb list is empty. */
+	if (urb_list_empty(epid)) {
+		etrax_usb_free_epid(epid);
+	}
+	restore_flags(flags);
+
+	/* Must be done before calling completion handler. */
+	kfree(urb_priv);
+	urb->hcpriv = 0;
+
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	DBFEXIT;
+	return 0;
+}
+
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
+{
+	DBFENTER;
+	DBFEXIT;
+	return (*R_USB_FM_NUMBER & 0x7ff);
+}
+
+static int etrax_usb_allocate_dev(struct usb_device *usb_dev)
+{
+	DBFENTER;
+	DBFEXIT;
+	return 0;
+}
+
+static int etrax_usb_deallocate_dev(struct usb_device *usb_dev)
+{
+	DBFENTER;
+	DBFEXIT;
+	return 0;
+}
+
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+	DBFENTER;
+
+	/* This interrupt handler could be used when unlinking EP descriptors. */
+
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
+		USB_EP_Desc_t *ep;
+
+		//dbg_bulk("dma8_sub0_descr (BULK) intr.");
+
+		/* It should be safe clearing the interrupt here, since we don't expect to get a new
+		   one until we restart the bulk channel. */
+		*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
+
+		/* Wait while the DMA is running (though we don't expect it to be). */
+		while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));
+
+		/* Advance the DMA to the next EP descriptor. */
+		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
+
+		//dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);
+
+		/* ep->next is already a physical address; no need for a virt_to_phys. */
+		*R_DMA_CH8_SUB0_EP = ep->next;
+
+		/* Start the DMA bulk channel again. */
+		*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
+		struct urb *urb;
+		int epid;
+		etrax_urb_priv_t *urb_priv;
+		unsigned long int flags;
+
+		dbg_ctrl("dma8_sub1_descr (CTRL) intr.");
+		*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
+
+		/* The complete callback gets called so we cli. */
+		save_flags(flags);
+		cli();
+
+		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+			if ((TxCtrlEPList[epid].sub == 0) ||
+			    (epid == DUMMY_EPID) ||
+			    (epid == INVALID_EPID)) {
+				/* Nothing here to see. */
+				continue;
+			}
+
+			/* Get the first urb (if any). */
+			urb = urb_list_first(epid);
+
+			if (urb) {
+
+				/* Sanity check. */
+				assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);
+
+				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+				assert(urb_priv);
+
+				if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {
+					assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+
+					etrax_usb_complete_urb(urb, 0);
+				}
+			}
+		}
+		restore_flags(flags);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
+		dbg_intr("dma8_sub2_descr (INTR) intr.");
+		*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
+	}
+	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
+		struct urb *urb;
+		int epid;
+		int epid_done;
+		etrax_urb_priv_t *urb_priv;
+		USB_SB_Desc_t *sb_desc;
+
+		usb_isoc_complete_data_t *comp_data = NULL;
+
+		/* One or more isoc out transfers are done. */
+		dbg_isoc("dma8_sub3_descr (ISOC) intr.");
+
+		/* For each isoc out EP search for the first sb_desc with the intr flag
+		   set.  This descriptor must be the last packet from an URB.  Then
+		   traverse the URB list for the EP until the URB with urb_priv->last_sb
+		   matching the intr-marked sb_desc is found.  All URBs before this have
+		   been sent.
+		*/
+
+		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+			/* Skip past epids with no SB lists, epids used for in traffic,
+			   and special (dummy, invalid) epids. */
+			if ((TxIsocEPList[epid].sub == 0) ||
+			    (test_bit(epid, (void *)&epid_out_traffic) == 0) ||
+			    (epid == DUMMY_EPID) ||
+			    (epid == INVALID_EPID)) {
+				/* Nothing here to see. */
+				continue;
+			}
+			sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
+
+			/* Find the last descriptor of the currently active URB for this ep.
+			   This is the first descriptor in the sub list marked for a descriptor
+			   interrupt. */
+			while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
+				sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
+			}
+			assert(sb_desc);
+
+			dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",
+				 epid,
+				 phys_to_virt(TxIsocEPList[epid].sub),
+				 sb_desc);
+
+			epid_done = 0;
+
+			/* Get the first urb (if any). */
+			urb = urb_list_first(epid);
+			assert(urb);
+
+			while (urb && !epid_done) {
+
+				/* Sanity check. */
+				assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
+
+				if (!usb_pipeout(urb->pipe)) {
+					/* descr interrupts are generated only for out pipes. */
+					epid_done = 1;
+					continue;
+				}
+
+				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+				assert(urb_priv);
+
+				if (sb_desc != urb_priv->last_sb) {
+
+					/* This urb has been sent. */
+					dbg_isoc("out URB 0x%p sent", urb);
+
+					urb_priv->urb_state = TRANSFER_DONE;
+
+				} else if ((sb_desc == urb_priv->last_sb) &&
+					   !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+
+					assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));
+					assert(sb_desc->next == 0);
+
+					dbg_isoc("out URB 0x%p last in list, epid disabled", urb);
+					TxIsocEPList[epid].sub = 0;
+					TxIsocEPList[epid].hw_len = 0;
+					urb_priv->urb_state = TRANSFER_DONE;
+
+					epid_done = 1;
+
+				} else {
+					epid_done = 1;
+				}
+				if (!epid_done) {
+					urb = urb_list_next(urb, epid);
+				}
+			}
+
+		}
+
+		*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
+
+		comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
+		assert(comp_data != NULL);
+
+                INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);
+                schedule_work(&comp_data->usb_bh);
+	}
+
+	DBFEXIT;
+        return IRQ_HANDLED;
+}
+
+static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
+{
+	usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;
+
+	struct urb *urb;
+	int epid;
+	int epid_done;
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");
+
+	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+
+		epid_done = 0;
+
+		/* The descriptor interrupt handler has marked all transmitted isoch. out
+		   URBs with TRANSFER_DONE.  Now we traverse all epids and for all that
+ 		   have isoch. out traffic traverse its URB list and complete the
+		   transmitted URB.
+		*/
+
+		while (!epid_done) {
+
+			/* Get the first urb (if any). */
+			urb = urb_list_first(epid);
+			if (urb == 0) {
+				epid_done = 1;
+				continue;
+			}
+
+			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
+					epid_done = 1;
+					continue;
+			}
+
+			if (!usb_pipeout(urb->pipe)) {
+				/* descr interrupts are generated only for out pipes. */
+				epid_done = 1;
+				continue;
+			}
+
+			dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);
+
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+			assert(urb_priv);
+
+			if (urb_priv->urb_state == TRANSFER_DONE) {
+				int i;
+				struct usb_iso_packet_descriptor *packet;
+
+				/* This urb has been sent. */
+				dbg_isoc("Completing isoc out URB 0x%p", urb);
+
+				for (i = 0; i < urb->number_of_packets; i++) {
+					packet = &urb->iso_frame_desc[i];
+					packet->status = 0;
+					packet->actual_length = packet->length;
+				}
+
+				etrax_usb_complete_isoc_urb(urb, 0);
+
+				if (urb_list_empty(epid)) {
+					etrax_usb_free_epid(epid);
+					epid_done = 1;
+				}
+			} else {
+				epid_done = 1;
+			}
+		}
+		restore_flags(flags);
+
+	}
+	kmem_cache_free(isoc_compl_cache, comp_data);
+
+	DBFEXIT;
+}
+
+
+
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+	struct urb *urb;
+	etrax_urb_priv_t *urb_priv;
+	int epid = 0;
+	unsigned long flags;
+
+	/* Isoc diagnostics. */
+	static int curr_fm = 0;
+	static int prev_fm = 0;
+
+	DBFENTER;
+
+	/* Clear this interrupt. */
+	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
+
+	/* Note that this while loop assumes that all packets span only
+	   one rx descriptor. */
+
+	/* The reason we cli here is that we call the driver's callback functions. */
+	save_flags(flags);
+	cli();
+
+	while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
+
+		epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
+		urb = urb_list_first(epid);
+
+		//printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);
+
+		if (!urb) {
+			err("No urb for epid %d in rx interrupt", epid);
+			__dump_ept_data(epid);
+			goto skip_out;
+		}
+
+		/* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since
+		   ctrl pipes are not. */
+
+		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
+			__u32 r_usb_ept_data;
+			int no_error = 0;
+
+			assert(test_bit(epid, (void *)&epid_usage_bitmask));
+
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+			nop();
+			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+				r_usb_ept_data = *R_USB_EPT_DATA_ISO;
+
+				if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
+				    (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
+					/* Not an error, just a failure to receive an expected iso
+					   in packet in this frame.  This is not documented
+					   in the designers reference.
+					*/
+					no_error++;
+				} else {
+					warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);
+				}
+			} else {
+				r_usb_ept_data = *R_USB_EPT_DATA;
+				warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);
+			}
+
+			if (!no_error){
+				warn("error in rx desc->status, epid %d, first urb = 0x%lx",
+				     epid, (unsigned long)urb);
+				__dump_in_desc(myNextRxDesc);
+
+				warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);
+
+				/* Check that ept was disabled when error occurred. */
+				switch (usb_pipetype(urb->pipe)) {
+				case PIPE_BULK:
+					assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				case PIPE_CONTROL:
+					assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				case PIPE_INTERRUPT:
+					assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				case PIPE_ISOCHRONOUS:
+					assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+					break;
+				default:
+					warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",
+					     usb_pipetype(urb->pipe),
+					     urb);
+				}
+				etrax_usb_complete_urb(urb, -EPROTO);
+				goto skip_out;
+			}
+		}
+
+		urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+		assert(urb_priv);
+
+		if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
+		    (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
+		    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+				/* We get nodata for empty data transactions, and the rx descriptor's
+				   hw_len field is not valid in that case. No data to copy in other
+				   words. */
+			} else {
+				/* Make sure the data fits in the buffer. */
+				assert(urb_priv->rx_offset + myNextRxDesc->hw_len
+				       <= urb->transfer_buffer_length);
+
+				memcpy(urb->transfer_buffer + urb_priv->rx_offset,
+				       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
+				urb_priv->rx_offset += myNextRxDesc->hw_len;
+			}
+
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
+				if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&
+				    ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==
+				     IO_STATE(USB_EP_command, enable, yes))) {
+					/* The EP is still enabled, so the OUT packet used to ack
+					   the in data is probably not processed yet.  If the EP
+					   sub pointer has not moved beyond urb_priv->last_sb mark
+					   it for a descriptor interrupt and complete the urb in
+					   the descriptor interrupt handler.
+					*/
+					USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;
+
+					while ((sub != NULL) && (sub != urb_priv->last_sb)) {
+						sub = sub->next ? phys_to_virt(sub->next) : 0;
+					}
+					if (sub != NULL) {
+						/* The urb has not been fully processed. */
+						urb_priv->urb_state = WAITING_FOR_DESCR_INTR;
+					} else {
+						warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);
+						etrax_usb_complete_urb(urb, 0);
+					}
+				} else {
+					etrax_usb_complete_urb(urb, 0);
+				}
+			}
+
+		} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+			struct usb_iso_packet_descriptor *packet;
+
+			if (urb_priv->urb_state == UNLINK) {
+				info("Ignoring rx data for urb being unlinked.");
+				goto skip_out;
+			} else if (urb_priv->urb_state == NOT_STARTED) {
+				info("What? Got rx data for urb that isn't started?");
+				goto skip_out;
+			}
+
+			packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
+			packet->status = 0;
+
+			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+				/* We get nodata for empty data transactions, and the rx descriptor's
+				   hw_len field is not valid in that case. We copy 0 bytes however to
+				   stay in synch. */
+				packet->actual_length = 0;
+			} else {
+				packet->actual_length = myNextRxDesc->hw_len;
+				/* Make sure the data fits in the buffer. */
+				assert(packet->actual_length <= packet->length);
+				memcpy(urb->transfer_buffer + packet->offset,
+				       phys_to_virt(myNextRxDesc->buf), packet->actual_length);
+			}
+
+			/* Increment the packet counter. */
+			urb_priv->isoc_packet_counter++;
+
+			/* Note that we don't care about the eot field in the rx descriptor's status.
+			   It will always be set for isoc traffic. */
+			if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
+
+				/* Out-of-synch diagnostics. */
+				curr_fm = (*R_USB_FM_NUMBER & 0x7ff);
+				if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {
+					/* This test is wrong, if there is more than one isoc
+					   in endpoint active it will always calculate wrong
+					   since prev_fm is shared by all endpoints.
+
+					   FIXME Make this check per URB using urb->start_frame.
+					*/
+					dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",
+						 prev_fm, curr_fm);
+
+				}
+				prev_fm = curr_fm;
+
+				/* Complete the urb with status OK. */
+				etrax_usb_complete_isoc_urb(urb, 0);
+			}
+		}
+
+	skip_out:
+
+		/* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr
+		   has the same layout as USB_IN_Desc for the relevant fields.) */
+		prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);
+
+		myPrevRxDesc = myNextRxDesc;
+		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
+		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
+		myLastRxDesc = myPrevRxDesc;
+
+		myNextRxDesc->status = 0;
+		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+	}
+
+	restore_flags(flags);
+
+	DBFEXIT;
+
+        return IRQ_HANDLED;
+}
+
+
+/* This function will unlink the SB descriptors associated with this urb. */
+static int etrax_remove_from_sb_list(struct urb *urb)
+{
+	USB_SB_Desc_t *next_sb, *first_sb, *last_sb;
+	etrax_urb_priv_t *urb_priv;
+	int i = 0;
+
+	DBFENTER;
+
+	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	assert(urb_priv);
+
+	/* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor
+	   doesn't really need to be disabled, it's just that we expect it to be. */
+	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+		assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+	}
+
+	first_sb = urb_priv->first_sb;
+	last_sb = urb_priv->last_sb;
+
+	assert(first_sb);
+	assert(last_sb);
+
+	while (first_sb != last_sb) {
+		next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);
+		kmem_cache_free(usb_desc_cache, first_sb);
+		first_sb = next_sb;
+		i++;
+	}
+	kmem_cache_free(usb_desc_cache, last_sb);
+	i++;
+	dbg_sb("%d SB descriptors freed", i);
+	/* Compare i with urb->number_of_packets for Isoc traffic.
+	   Should be same when calling unlink_urb */
+
+	DBFEXIT;
+
+	return i;
+}
+
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
+{
+	int epid;
+	int empty;
+	unsigned long flags;
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	/* Epid allocation, empty check and list add must be protected.
+	   Read about this in etrax_usb_submit_ctrl_urb. */
+
+	spin_lock_irqsave(&urb_list_lock, flags);
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		DBFEXIT;
+		spin_unlock_irqrestore(&urb_list_lock, flags);
+		return -ENOMEM;
+	}
+	empty = urb_list_empty(epid);
+	urb_list_add(urb, epid);
+	spin_unlock_irqrestore(&urb_list_lock, flags);
+
+	dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",
+		 usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);
+
+	/* Mark the urb as being in progress. */
+	urb->status = -EINPROGRESS;
+
+	/* Setup the hcpriv data. */
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	assert(urb_priv != NULL);
+	/* This sets rx_offset to 0. */
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+	urb_priv->urb_state = NOT_STARTED;
+	urb->hcpriv = urb_priv;
+
+	if (empty) {
+		etrax_usb_add_to_bulk_sb_list(urb, epid);
+	}
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
+{
+	USB_SB_Desc_t *sb_desc;
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	unsigned long flags;
+	char maxlen;
+
+	DBFENTER;
+
+	dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);
+
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+	sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+	assert(sb_desc != NULL);
+	memset(sb_desc, 0, sizeof(USB_SB_Desc_t));
+
+
+	if (usb_pipeout(urb->pipe)) {
+
+		dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);
+
+		/* This is probably a sanity check of the bulk transaction length
+		   not being larger than 64 kB. */
+		if (urb->transfer_buffer_length > 0xffff) {
+			panic("urb->transfer_buffer_length > 0xffff");
+		}
+
+		sb_desc->sw_len = urb->transfer_buffer_length;
+
+		/* The rem field is don't care if it's not a full-length transfer, so setting
+		   it shouldn't hurt. Also, rem isn't used for OUT traffic. */
+		sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
+				    IO_STATE(USB_SB_command, tt, out) |
+				    IO_STATE(USB_SB_command, eot, yes) |
+				    IO_STATE(USB_SB_command, eol, yes));
+
+		/* The full field is set to yes, even if we don't actually check that this is
+		   a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).
+		   Setting full prevents the USB controller from sending an empty packet in
+		   that case.  However, if URB_ZERO_PACKET was set we want that. */
+		if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
+			sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
+		}
+
+		sb_desc->buf = virt_to_phys(urb->transfer_buffer);
+		sb_desc->next = 0;
+
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);
+
+		sb_desc->sw_len = urb->transfer_buffer_length ?
+			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+
+		/* The rem field is don't care if it's not a full-length transfer, so setting
+		   it shouldn't hurt. */
+		sb_desc->command =
+			(IO_FIELD(USB_SB_command, rem,
+				  urb->transfer_buffer_length % maxlen) |
+			 IO_STATE(USB_SB_command, tt, in) |
+			 IO_STATE(USB_SB_command, eot, yes) |
+			 IO_STATE(USB_SB_command, eol, yes));
+
+		sb_desc->buf = 0;
+		sb_desc->next = 0;
+	}
+
+	urb_priv->first_sb = sb_desc;
+	urb_priv->last_sb = sb_desc;
+	urb_priv->epid = epid;
+
+	urb->hcpriv = urb_priv;
+
+	/* Reset toggle bits and reset error count. */
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+
+	/* FIXME: Is this a special case since the hold field is checked,
+	   or should we check hold in a lot of other cases as well? */
+	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+		panic("Hold was set in %s", __FUNCTION__);
+	}
+
+	/* Reset error counters (regardless of which direction this traffic is). */
+	*R_USB_EPT_DATA &=
+		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+		  IO_MASK(R_USB_EPT_DATA, error_count_out));
+
+	/* Software must preset the toggle bits. */
+	if (usb_pipeout(urb->pipe)) {
+		char toggle =
+			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
+		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
+	} else {
+		char toggle =
+			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
+		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
+	}
+
+	/* Assert that the EP descriptor is disabled. */
+	assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+
+	/* The reason we set the EP's sub pointer directly instead of
+	   walking the SB list and linking it last in the list is that we only
+	   have one active urb at a time (the rest are queued). */
+
+	/* Note that we cannot have interrupts running when we have set the SB descriptor
+	   but the EP is not yet enabled.  If a bulk eot happens for another EP, we will
+	   find this EP disabled and with a SB != 0, which will make us think that it's done. */
+	TxBulkEPList[epid].sub = virt_to_phys(sb_desc);
+	TxBulkEPList[epid].hw_len = 0;
+	/* Note that we don't have to fill in the ep_id field since this
+	   was done when we allocated the EP descriptors in init_tx_bulk_ep. */
+
+	/* Check if the dummy list is already with us (if several urbs were queued). */
+	if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {
+
+		dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d",
+			 (unsigned long)urb, epid);
+
+		/* The last EP in the dummy list already has its next pointer set to
+		   TxBulkEPList[epid].next. */
+
+		/* We don't need to check if the DMA is at this EP or not before changing the
+		   next pointer, since we will do it in one 32-bit write (EP descriptors are
+		   32-bit aligned). */
+		TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
+	}
+	/* Enable the EP descr. */
+	dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);
+	TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+	/* Everything is set up, safe to enable interrupts again. */
+	restore_flags(flags);
+
+	/* If the DMA bulk channel isn't running, we need to restart it if it
+	   has stopped at the last EP descriptor (DMA stopped because there was
+	   no more traffic) or if it has stopped at a dummy EP with the intr flag
+	   set (DMA stopped because we were too slow in inserting new traffic). */
+	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+
+		USB_EP_Desc_t *ep;
+		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
+		dbg_bulk("DMA channel not running in add");
+		dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);
+
+		if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||
+		    (ep->command & 0x8) >> 3) {
+			*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+			/* Update/restart the bulk start timer since we just started the channel. */
+			mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
+			/* Update/restart the bulk eot timer since we just inserted traffic. */
+			mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+		}
+	}
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_bulk_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+	unsigned long flags;
+
+	DBFENTER;
+
+	if (status)
+		warn("Completing bulk urb with status %d.", status);
+
+	dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid);
+
+	/* Update the urb list. */
+	urb_list_del(urb, epid);
+
+	/* For an IN pipe, we always set the actual length, regardless of whether there was
+	   an error or not (which means the device driver can use the data if it wants to). */
+	if (usb_pipein(urb->pipe)) {
+		urb->actual_length = urb_priv->rx_offset;
+	} else {
+		/* Set actual_length for OUT urbs also; the USB mass storage driver seems
+		   to want that. We wouldn't know of any partial writes if there was an error. */
+		if (status == 0) {
+			urb->actual_length = urb->transfer_buffer_length;
+		} else {
+			urb->actual_length = 0;
+		}
+	}
+
+	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
+	   Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+
+	/* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */
+	if (usb_pipeout(urb->pipe)) {
+		char toggle =
+			IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			      usb_pipeout(urb->pipe), toggle);
+	} else {
+		char toggle =
+			IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			      usb_pipeout(urb->pipe), toggle);
+	}
+	restore_flags(flags);
+
+	/* Remember to free the SBs. */
+	etrax_remove_from_sb_list(urb);
+	kfree(urb_priv);
+	urb->hcpriv = 0;
+
+	/* If there are any more urb's in the list we'd better start sending */
+	if (!urb_list_empty(epid)) {
+
+		struct urb *new_urb;
+
+		/* Get the first urb. */
+		new_urb = urb_list_first(epid);
+		assert(new_urb);
+
+		dbg_bulk("More bulk for epid %d", epid);
+
+		etrax_usb_add_to_bulk_sb_list(new_urb, epid);
+	}
+
+	urb->status = status;
+
+	/* We let any non-zero status from the layer above have precedence. */
+	if (status == 0) {
+		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+		   is to be treated as an error. */
+		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+			if (usb_pipein(urb->pipe) &&
+			    (urb->actual_length !=
+			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
+				urb->status = -EREMOTEIO;
+			}
+		}
+	}
+
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	if (urb_list_empty(epid)) {
+		/* This means that this EP is now free, deconfigure it. */
+		etrax_usb_free_epid(epid);
+
+		/* No more traffic; time to clean up.
+		   Must set sub pointer to 0, since we look at the sub pointer when handling
+		   the bulk eot interrupt. */
+
+		dbg_bulk("No bulk for epid %d", epid);
+
+		TxBulkEPList[epid].sub = 0;
+
+		/* Unlink the dummy list. */
+
+		dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d",
+			 (unsigned long)urb, epid);
+
+		/* No need to wait for the DMA before changing the next pointer.
+		   The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
+		   the last one (INVALID_EPID) for actual traffic. */
+		TxBulkEPList[epid].next =
+			virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
+	}
+
+	DBFEXIT;
+}
+
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
+{
+	int epid;
+	int empty;
+	unsigned long flags;
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	/* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */
+
+	/* Epid allocation, empty check and list add must be protected.
+
+	   Epid allocation because if we find an existing epid for this endpoint an urb might be
+	   completed (emptying the list) before we add the new urb to the list, causing the epid
+	   to be de-allocated. We would then start the transfer with an invalid epid -> epid attn.
+
+	   Empty check and add because otherwise we might conclude that the list is not empty,
+	   after which it becomes empty before we add the new urb to the list, causing us not to
+	   insert the new traffic into the SB list. */
+
+	spin_lock_irqsave(&urb_list_lock, flags);
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		spin_unlock_irqrestore(&urb_list_lock, flags);
+		DBFEXIT;
+		return -ENOMEM;
+	}
+	empty = urb_list_empty(epid);
+	urb_list_add(urb, epid);
+	spin_unlock_irqrestore(&urb_list_lock, flags);
+
+	dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d",
+		 (unsigned long)urb, empty ? "empty" : "", epid);
+
+	/* Mark the urb as being in progress. */
+	urb->status = -EINPROGRESS;
+
+	/* Setup the hcpriv data. */
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	assert(urb_priv != NULL);
+	/* This sets rx_offset to 0. */
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+	urb_priv->urb_state = NOT_STARTED;
+	urb->hcpriv = urb_priv;
+
+	if (empty) {
+		etrax_usb_add_to_ctrl_sb_list(urb, epid);
+	}
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid)
+{
+	USB_SB_Desc_t *sb_desc_setup;
+	USB_SB_Desc_t *sb_desc_data;
+	USB_SB_Desc_t *sb_desc_status;
+
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+
+	unsigned long flags;
+	char maxlen;
+
+	DBFENTER;
+
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+	sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+	assert(sb_desc_setup != NULL);
+	sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+	assert(sb_desc_status != NULL);
+
+	/* Initialize the mandatory setup SB descriptor (used only in control transfers) */
+	sb_desc_setup->sw_len = 8;
+	sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) |
+				  IO_STATE(USB_SB_command, tt, setup) |
+				  IO_STATE(USB_SB_command, full, yes) |
+				  IO_STATE(USB_SB_command, eot, yes));
+
+	sb_desc_setup->buf = virt_to_phys(urb->setup_packet);
+
+	if (usb_pipeout(urb->pipe)) {
+		dbg_ctrl("Transfer for epid %d is OUT", epid);
+
+		/* If this Control OUT transfer has an optional data stage we add an OUT token
+		   before the mandatory IN (status) token, hence the reordered SB list */
+
+		sb_desc_setup->next = virt_to_phys(sb_desc_status);
+		if (urb->transfer_buffer) {
+
+			dbg_ctrl("This OUT transfer has an extra data stage");
+
+			sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+			assert(sb_desc_data != NULL);
+
+			sb_desc_setup->next = virt_to_phys(sb_desc_data);
+
+			sb_desc_data->sw_len = urb->transfer_buffer_length;
+			sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) |
+						 IO_STATE(USB_SB_command, full, yes) |
+						 IO_STATE(USB_SB_command, eot, yes));
+			sb_desc_data->buf = virt_to_phys(urb->transfer_buffer);
+			sb_desc_data->next = virt_to_phys(sb_desc_status);
+		}
+
+		sb_desc_status->sw_len = 1;
+		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
+					   IO_STATE(USB_SB_command, tt, in) |
+					   IO_STATE(USB_SB_command, eot, yes) |
+					   IO_STATE(USB_SB_command, intr, yes) |
+					   IO_STATE(USB_SB_command, eol, yes));
+
+		sb_desc_status->buf = 0;
+		sb_desc_status->next = 0;
+
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_ctrl("Transfer for epid %d is IN", epid);
+		dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
+		dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
+
+		sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+		assert(sb_desc_data != NULL);
+
+		sb_desc_setup->next = virt_to_phys(sb_desc_data);
+
+		sb_desc_data->sw_len = urb->transfer_buffer_length ?
+			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+		dbg_ctrl("sw_len got %d", sb_desc_data->sw_len);
+
+		sb_desc_data->command =
+			(IO_FIELD(USB_SB_command, rem,
+				  urb->transfer_buffer_length % maxlen) |
+			 IO_STATE(USB_SB_command, tt, in) |
+			 IO_STATE(USB_SB_command, eot, yes));
+
+		sb_desc_data->buf = 0;
+		sb_desc_data->next = virt_to_phys(sb_desc_status);
+
+		/* Read comment at zout_buffer declaration for an explanation to this. */
+		sb_desc_status->sw_len = 1;
+		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
+					   IO_STATE(USB_SB_command, tt, zout) |
+					   IO_STATE(USB_SB_command, full, yes) |
+					   IO_STATE(USB_SB_command, eot, yes) |
+					   IO_STATE(USB_SB_command, intr, yes) |
+					   IO_STATE(USB_SB_command, eol, yes));
+
+		sb_desc_status->buf = virt_to_phys(&zout_buffer[0]);
+		sb_desc_status->next = 0;
+	}
+
+	urb_priv->first_sb = sb_desc_setup;
+	urb_priv->last_sb = sb_desc_status;
+	urb_priv->epid = epid;
+
+	urb_priv->urb_state = STARTED;
+
+	/* Reset toggle bits and reset error count, remember to di and ei */
+	/* Warning: it is possible that this locking doesn't work with bottom-halves */
+
+	save_flags(flags);
+	cli();
+
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+		panic("Hold was set in %s", __FUNCTION__);
+	}
+
+
+	/* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits
+	   are set to a specific value. Why the difference? Read "Transfer and Toggle Bits
+	   in Designer's Reference, p. 8 - 11. */
+	*R_USB_EPT_DATA &=
+		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+		  IO_MASK(R_USB_EPT_DATA, error_count_out) |
+		  IO_MASK(R_USB_EPT_DATA, t_in) |
+		  IO_MASK(R_USB_EPT_DATA, t_out));
+
+	/* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now
+	   (i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */
+	restore_flags(flags);
+
+	/* Assert that the EP descriptor is disabled. */
+	assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+
+	/* Set up and enable the EP descriptor. */
+	TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup);
+	TxCtrlEPList[epid].hw_len = 0;
+	TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+	/* We start the DMA sub channel without checking if it's running or not, because:
+	   1) If it's already running, issuing the start command is a nop.
+	   2) We avoid a test-and-set race condition. */
+	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+
+	DBFENTER;
+
+	if (status)
+		warn("Completing ctrl urb with status %d.", status);
+
+	dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb);
+
+	/* Remove this urb from the list. */
+	urb_list_del(urb, epid);
+
+	/* For an IN pipe, we always set the actual length, regardless of whether there was
+	   an error or not (which means the device driver can use the data if it wants to). */
+	if (usb_pipein(urb->pipe)) {
+		urb->actual_length = urb_priv->rx_offset;
+	}
+
+	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
+	   Like, maybe we shouldn't insert more traffic. */
+
+	/* Remember to free the SBs. */
+	etrax_remove_from_sb_list(urb);
+	kfree(urb_priv);
+	urb->hcpriv = 0;
+
+	/* If there are any more urbs in the list we'd better start sending. */
+	if (!urb_list_empty(epid)) {
+		struct urb *new_urb;
+
+		/* Get the first urb. */
+		new_urb = urb_list_first(epid);
+		assert(new_urb);
+
+		dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb);
+
+		etrax_usb_add_to_ctrl_sb_list(new_urb, epid);
+	}
+
+	urb->status = status;
+
+	/* We let any non-zero status from the layer above have precedence. */
+	if (status == 0) {
+		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+		   is to be treated as an error. */
+		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+			if (usb_pipein(urb->pipe) &&
+			    (urb->actual_length !=
+			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
+				urb->status = -EREMOTEIO;
+			}
+		}
+	}
+
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	if (urb_list_empty(epid)) {
+		/* No more traffic. Time to clean up. */
+		etrax_usb_free_epid(epid);
+		/* Must set sub pointer to 0. */
+		dbg_ctrl("No ctrl for epid %d", epid);
+		TxCtrlEPList[epid].sub = 0;
+	}
+
+	DBFEXIT;
+}
+
+static int etrax_usb_submit_intr_urb(struct urb *urb)
+{
+
+	int epid;
+
+	DBFENTER;
+
+	if (usb_pipeout(urb->pipe)) {
+		/* Unsupported transfer type.
+		   We don't support interrupt out traffic. (If we do, we can't support
+		   intervals for neither in or out traffic, but are forced to schedule all
+		   interrupt traffic in one frame.) */
+		return -EINVAL;
+	}
+
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		DBFEXIT;
+		return -ENOMEM;
+	}
+
+	if (!urb_list_empty(epid)) {
+		/* There is already a queued urb for this endpoint. */
+		etrax_usb_free_epid(epid);
+		return -ENXIO;
+	}
+
+	urb->status = -EINPROGRESS;
+
+	dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid);
+
+	urb_list_add(urb, epid);
+	etrax_usb_add_to_intr_sb_list(urb, epid);
+
+	return 0;
+
+	DBFEXIT;
+}
+
+static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
+{
+
+	volatile USB_EP_Desc_t *tmp_ep;
+	volatile USB_EP_Desc_t *first_ep;
+
+	char maxlen;
+	int interval;
+	int i;
+
+	etrax_urb_priv_t *urb_priv;
+
+	DBFENTER;
+
+	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	interval = urb->interval;
+
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	assert(urb_priv != NULL);
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+	urb->hcpriv = urb_priv;
+
+	first_ep = &TxIntrEPList[0];
+
+	/* Round of the interval to 2^n, it is obvious that this code favours
+	   smaller numbers, but that is actually a good thing */
+	/* FIXME: The "rounding error" for larger intervals will be quite
+	   large. For in traffic this shouldn't be a problem since it will only
+	   mean that we "poll" more often. */
+	for (i = 0; interval; i++) {
+		interval = interval >> 1;
+	}
+	interval = 1 << (i - 1);
+
+	dbg_intr("Interval rounded to %d", interval);
+
+	tmp_ep = first_ep;
+	i = 0;
+	do {
+		if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
+			if ((i % interval) == 0) {
+				/* Insert the traffic ep after tmp_ep */
+				USB_EP_Desc_t *ep_desc;
+				USB_SB_Desc_t *sb_desc;
+
+				dbg_intr("Inserting EP for epid %d", epid);
+
+				ep_desc = (USB_EP_Desc_t *)
+					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+				sb_desc = (USB_SB_Desc_t *)
+					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+				assert(ep_desc != NULL);
+				CHECK_ALIGN(ep_desc);
+				assert(sb_desc != NULL);
+
+				ep_desc->sub = virt_to_phys(sb_desc);
+				ep_desc->hw_len = 0;
+				ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
+						    IO_STATE(USB_EP_command, enable, yes));
+
+
+				/* Round upwards the number of packets of size maxlen
+				   that this SB descriptor should receive. */
+				sb_desc->sw_len = urb->transfer_buffer_length ?
+					(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+				sb_desc->next = 0;
+				sb_desc->buf = 0;
+				sb_desc->command =
+					(IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) |
+					 IO_STATE(USB_SB_command, tt, in) |
+					 IO_STATE(USB_SB_command, eot, yes) |
+					 IO_STATE(USB_SB_command, eol, yes));
+
+				ep_desc->next = tmp_ep->next;
+				tmp_ep->next = virt_to_phys(ep_desc);
+			}
+			i++;
+		}
+		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
+	} while (tmp_ep != first_ep);
+
+
+	/* Note that first_sb/last_sb doesn't apply to interrupt traffic. */
+	urb_priv->epid = epid;
+
+	/* We start the DMA sub channel without checking if it's running or not, because:
+	   1) If it's already running, issuing the start command is a nop.
+	   2) We avoid a test-and-set race condition. */
+	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+
+
+static void etrax_usb_complete_intr_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+
+	DBFENTER;
+
+	if (status)
+		warn("Completing intr urb with status %d.", status);
+
+	dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb);
+
+	urb->status = status;
+	urb->actual_length = urb_priv->rx_offset;
+
+	dbg_intr("interrupt urb->actual_length = %d", urb->actual_length);
+
+	/* We let any non-zero status from the layer above have precedence. */
+	if (status == 0) {
+		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+		   is to be treated as an error. */
+		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+			if (urb->actual_length !=
+			    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
+				urb->status = -EREMOTEIO;
+			}
+		}
+	}
+
+	/* The driver will resubmit the URB so we need to remove it first */
+        etrax_usb_unlink_urb(urb, 0);
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	DBFEXIT;
+}
+
+
+static int etrax_usb_submit_isoc_urb(struct urb *urb)
+{
+	int epid;
+	unsigned long flags;
+
+	DBFENTER;
+
+	dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb);
+
+	/* Epid allocation, empty check and list add must be protected.
+	   Read about this in etrax_usb_submit_ctrl_urb. */
+
+	spin_lock_irqsave(&urb_list_lock, flags);
+	/* Is there an active epid for this urb ? */
+	epid = etrax_usb_setup_epid(urb);
+	if (epid == -1) {
+		DBFEXIT;
+		spin_unlock_irqrestore(&urb_list_lock, flags);
+		return -ENOMEM;
+	}
+
+	/* Ok, now we got valid endpoint, lets insert some traffic */
+
+	urb->status = -EINPROGRESS;
+
+	/* Find the last urb in the URB_List and add this urb after that one.
+	   Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list.  This
+	   is important to make this in "real time" since isochronous traffic is
+	   time sensitive. */
+
+	dbg_isoc("Adding isoc urb to (possibly empty) list");
+	urb_list_add(urb, epid);
+	etrax_usb_add_to_isoc_sb_list(urb, epid);
+	spin_unlock_irqrestore(&urb_list_lock, flags);
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_check_error_isoc_ep(const int epid)
+{
+	unsigned long int flags;
+	int error_code;
+	__u32 r_usb_ept_data;
+
+	/* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof,
+	   bulk_eot and epid_attn interrupts.  So we just check the status of
+	   the epid without testing if for it in R_USB_EPID_ATTN. */
+
+
+	save_flags(flags);
+	cli();
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+	nop();
+	/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
+	   registers, they are located at the same address and are of the same size.
+	   In other words, this read should be ok for isoc also. */
+	r_usb_ept_data = *R_USB_EPT_DATA;
+	restore_flags(flags);
+
+	error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
+
+	if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+		warn("Hold was set for epid %d.", epid);
+		return;
+	}
+
+	if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) {
+
+		/* This indicates that the SB list of the ept was completed before
+		   new data was appended to it.  This is not an error, but indicates
+		   large system or USB load and could possibly cause trouble for
+		   very timing sensitive USB device drivers so we log it.
+		*/
+		info("Isoc. epid %d disabled with no error", epid);
+		return;
+
+	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) {
+		/* Not really a protocol error, just says that the endpoint gave
+		   a stall response. Note that error_code cannot be stall for isoc. */
+		panic("Isoc traffic cannot stall");
+
+	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) {
+		/* Two devices responded to a transaction request. Must be resolved
+		   by software. FIXME: Reset ports? */
+		panic("Bus error for epid %d."
+		      " Two devices responded to transaction request",
+		      epid);
+
+	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+		/* DMA overrun or underrun. */
+		warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+
+		/* It seems that error_code = buffer_error in
+		   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
+		   are the same error. */
+	}
+}
+
+
+static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
+{
+
+	int i = 0;
+
+	etrax_urb_priv_t *urb_priv;
+	USB_SB_Desc_t *prev_sb_desc,  *next_sb_desc, *temp_sb_desc;
+
+	DBFENTER;
+
+	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
+
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+	assert(urb_priv != NULL);
+	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+
+	urb->hcpriv = urb_priv;
+	urb_priv->epid = epid;
+
+	if (usb_pipeout(urb->pipe)) {
+
+		if (urb->number_of_packets == 0) panic("etrax_usb_add_to_isoc_sb_list 0 packets\n");
+
+		dbg_isoc("Transfer for epid %d is OUT", epid);
+		dbg_isoc("%d packets in URB", urb->number_of_packets);
+
+		/* Create one SB descriptor for each packet and link them together. */
+		for (i = 0; i < urb->number_of_packets; i++) {
+			if (!urb->iso_frame_desc[i].length)
+				continue;
+
+			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
+			assert(next_sb_desc != NULL);
+
+			if (urb->iso_frame_desc[i].length > 0) {
+
+				next_sb_desc->command = (IO_STATE(USB_SB_command, tt, out) |
+							 IO_STATE(USB_SB_command, eot, yes));
+
+				next_sb_desc->sw_len = urb->iso_frame_desc[i].length;
+				next_sb_desc->buf = virt_to_phys((char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset);
+
+				/* Check if full length transfer. */
+				if (urb->iso_frame_desc[i].length ==
+				    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
+					next_sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
+				}
+			} else {
+				dbg_isoc("zero len packet");
+				next_sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
+							 IO_STATE(USB_SB_command, tt, zout) |
+							 IO_STATE(USB_SB_command, eot, yes) |
+							 IO_STATE(USB_SB_command, full, yes));
+
+				next_sb_desc->sw_len = 1;
+				next_sb_desc->buf = virt_to_phys(&zout_buffer[0]);
+			}
+
+			/* First SB descriptor that belongs to this urb */
+			if (i == 0)
+				urb_priv->first_sb = next_sb_desc;
+			else
+				prev_sb_desc->next = virt_to_phys(next_sb_desc);
+
+			prev_sb_desc = next_sb_desc;
+		}
+
+		next_sb_desc->command |= (IO_STATE(USB_SB_command, intr, yes) |
+					  IO_STATE(USB_SB_command, eol, yes));
+		next_sb_desc->next = 0;
+		urb_priv->last_sb = next_sb_desc;
+
+	} else if (usb_pipein(urb->pipe)) {
+
+		dbg_isoc("Transfer for epid %d is IN", epid);
+		dbg_isoc("transfer_buffer_length = %d", urb->transfer_buffer_length);
+		dbg_isoc("rem is calculated to %d", urb->iso_frame_desc[urb->number_of_packets - 1].length);
+
+		/* Note that in descriptors for periodic traffic are not consumed. This means that
+		   the USB controller never propagates in the SB list. In other words, if there already
+		   is an SB descriptor in the list for this EP we don't have to do anything. */
+		if (TxIsocEPList[epid].sub == 0) {
+			dbg_isoc("Isoc traffic not already running, allocating SB");
+
+			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
+			assert(next_sb_desc != NULL);
+
+			next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) |
+						 IO_STATE(USB_SB_command, eot, yes) |
+						 IO_STATE(USB_SB_command, eol, yes));
+
+			next_sb_desc->next = 0;
+			next_sb_desc->sw_len = 1; /* Actual number of packets is not relevant
+						     for periodic in traffic as long as it is more
+						     than zero.  Set to 1 always. */
+			next_sb_desc->buf = 0;
+
+			/* The rem field is don't care for isoc traffic, so we don't set it. */
+
+			/* Only one SB descriptor that belongs to this urb. */
+			urb_priv->first_sb = next_sb_desc;
+			urb_priv->last_sb = next_sb_desc;
+
+		} else {
+
+			dbg_isoc("Isoc traffic already running, just setting first/last_sb");
+
+			/* Each EP for isoc in will have only one SB descriptor, setup when submitting the
+			   already active urb. Note that even though we may have several first_sb/last_sb
+			   pointing at the same SB descriptor, they are freed only once (when the list has
+			   become empty). */
+			urb_priv->first_sb = phys_to_virt(TxIsocEPList[epid].sub);
+			urb_priv->last_sb = phys_to_virt(TxIsocEPList[epid].sub);
+			return;
+		}
+
+	}
+
+	/* Find the spot to insert this urb and add it. */
+	if (TxIsocEPList[epid].sub == 0) {
+		/* First SB descriptor inserted in this list (in or out). */
+		dbg_isoc("Inserting SB desc first in list");
+		TxIsocEPList[epid].hw_len = 0;
+		TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
+
+	} else {
+		/* Isochronous traffic is already running, insert new traffic last (only out). */
+		dbg_isoc("Inserting SB desc last in list");
+		temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
+		while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
+		       IO_STATE(USB_SB_command, eol, yes)) {
+			assert(temp_sb_desc->next);
+			temp_sb_desc = phys_to_virt(temp_sb_desc->next);
+		}
+		dbg_isoc("Appending list on desc 0x%p", temp_sb_desc);
+
+		/* Next pointer must be set before eol is removed. */
+		temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
+		/* Clear the previous end of list flag since there is a new in the
+		   added SB descriptor list. */
+		temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
+
+		if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+			/* 8.8.5 in Designer's Reference says we should check for and correct
+			   any errors in the EP here.  That should not be necessary if epid_attn
+			   is handled correctly, so we assume all is ok. */
+			dbg_isoc("EP disabled");
+			etrax_usb_check_error_isoc_ep(epid);
+
+			/* The SB list was exhausted. */
+			if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
+				/* The new sublist did not get processed before the EP was
+				   disabled.  Setup the EP again. */
+				dbg_isoc("Set EP sub to new list");
+				TxIsocEPList[epid].hw_len = 0;
+				TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
+			}
+		}
+	}
+
+	if (urb->transfer_flags & URB_ISO_ASAP) {
+		/* The isoc transfer should be started as soon as possible. The start_frame
+		   field is a return value if URB_ISO_ASAP was set. Comparing R_USB_FM_NUMBER
+		   with a USB Chief trace shows that the first isoc IN token is sent 2 frames
+		   later. I'm not sure how this affects usage of the start_frame field by the
+		   device driver, or how it affects things when USB_ISO_ASAP is not set, so
+		   therefore there's no compensation for the 2 frame "lag" here. */
+		urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
+		TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+		urb_priv->urb_state = STARTED;
+		dbg_isoc("URB_ISO_ASAP set, urb->start_frame set to %d", urb->start_frame);
+	} else {
+		/* Not started yet. */
+		urb_priv->urb_state = NOT_STARTED;
+		dbg_isoc("urb_priv->urb_state set to NOT_STARTED");
+	}
+
+       /* We start the DMA sub channel without checking if it's running or not, because:
+	  1) If it's already running, issuing the start command is a nop.
+	  2) We avoid a test-and-set race condition. */
+	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_isoc_urb(struct urb *urb, int status)
+{
+	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+	int epid = urb_priv->epid;
+	int auto_resubmit = 0;
+
+	DBFENTER;
+	dbg_isoc("complete urb 0x%p, status %d", urb, status);
+
+	if (status)
+		warn("Completing isoc urb with status %d.", status);
+
+	if (usb_pipein(urb->pipe)) {
+		int i;
+
+		/* Make that all isoc packets have status and length set before
+		   completing the urb. */
+		for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++) {
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = -EPROTO;
+		}
+
+		urb_list_del(urb, epid);
+
+		if (!list_empty(&urb_list[epid])) {
+			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
+		} else {
+			unsigned long int flags;
+			if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+				/* The EP was enabled, disable it and wait. */
+				TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+				/* Ah, the luxury of busy-wait. */
+				while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
+			}
+
+			etrax_remove_from_sb_list(urb);
+			TxIsocEPList[epid].sub = 0;
+			TxIsocEPList[epid].hw_len = 0;
+
+			save_flags(flags);
+			cli();
+			etrax_usb_free_epid(epid);
+			restore_flags(flags);
+		}
+
+		urb->hcpriv = 0;
+		kfree(urb_priv);
+
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 0);
+	} else if (usb_pipeout(urb->pipe)) {
+		int freed_descr;
+
+		dbg_isoc("Isoc out urb complete 0x%p", urb);
+
+		/* Update the urb list. */
+		urb_list_del(urb, epid);
+
+		freed_descr = etrax_remove_from_sb_list(urb);
+		dbg_isoc("freed %d descriptors of %d packets", freed_descr, urb->number_of_packets);
+		assert(freed_descr == urb->number_of_packets);
+		urb->hcpriv = 0;
+		kfree(urb_priv);
+
+		/* Release allocated bandwidth. */
+		usb_release_bandwidth(urb->dev, urb, 0);
+	}
+
+	urb->status = status;
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+
+	if (auto_resubmit) {
+		/* Check that urb was not unlinked by the complete callback. */
+		if (__urb_list_entry(urb, epid)) {
+			/* Move this one down the list. */
+			urb_list_move_last(urb, epid);
+
+			/* Mark the now first urb as started (may already be). */
+			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
+
+			/* Must set this to 0 since this urb is still active after
+			   completion. */
+			urb_priv->isoc_packet_counter = 0;
+		} else {
+			warn("(ISOC) automatic resubmit urb 0x%p removed by complete.", urb);
+		}
+	}
+
+	DBFEXIT;
+}
+
+static void etrax_usb_complete_urb(struct urb *urb, int status)
+{
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_BULK:
+		etrax_usb_complete_bulk_urb(urb, status);
+		break;
+	case PIPE_CONTROL:
+		etrax_usb_complete_ctrl_urb(urb, status);
+		break;
+	case PIPE_INTERRUPT:
+		etrax_usb_complete_intr_urb(urb, status);
+		break;
+	case PIPE_ISOCHRONOUS:
+		etrax_usb_complete_isoc_urb(urb, status);
+		break;
+	default:
+		err("Unknown pipetype");
+	}
+}
+
+
+
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs)
+{
+	usb_interrupt_registers_t *reg;
+	unsigned long flags;
+	__u32 irq_mask;
+	__u8 status;
+	__u32 epid_attn;
+	__u16 port_status_1;
+	__u16 port_status_2;
+	__u32 fm_number;
+
+	DBFENTER;
+
+	/* Read critical registers into local variables, do kmalloc afterwards. */
+	save_flags(flags);
+	cli();
+
+	irq_mask = *R_USB_IRQ_MASK_READ;
+	/* Reading R_USB_STATUS clears the ctl_status interrupt. Note that R_USB_STATUS
+	   must be read before R_USB_EPID_ATTN since reading the latter clears the
+	   ourun and perror fields of R_USB_STATUS. */
+	status = *R_USB_STATUS;
+
+	/* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn interrupts. */
+	epid_attn = *R_USB_EPID_ATTN;
+
+	/* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
+	   port_status interrupt. */
+	port_status_1 = *R_USB_RH_PORT_STATUS_1;
+	port_status_2 = *R_USB_RH_PORT_STATUS_2;
+
+	/* Reading R_USB_FM_NUMBER clears the sof interrupt. */
+	/* Note: the lower 11 bits contain the actual frame number, sent with each sof. */
+	fm_number = *R_USB_FM_NUMBER;
+
+	restore_flags(flags);
+
+	reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, SLAB_ATOMIC);
+
+	assert(reg != NULL);
+
+	reg->hc = (etrax_hc_t *)vhc;
+
+	/* Now put register values into kmalloc'd area. */
+	reg->r_usb_irq_mask_read = irq_mask;
+	reg->r_usb_status = status;
+	reg->r_usb_epid_attn = epid_attn;
+	reg->r_usb_rh_port_status_1 = port_status_1;
+	reg->r_usb_rh_port_status_2 = port_status_2;
+	reg->r_usb_fm_number = fm_number;
+
+        INIT_WORK(&reg->usb_bh, etrax_usb_hc_interrupt_bottom_half, reg);
+        schedule_work(&reg->usb_bh);
+
+	DBFEXIT;
+
+        return IRQ_HANDLED;
+}
+
+static void etrax_usb_hc_interrupt_bottom_half(void *data)
+{
+	usb_interrupt_registers_t *reg = (usb_interrupt_registers_t *)data;
+	__u32 irq_mask = reg->r_usb_irq_mask_read;
+
+	DBFENTER;
+
+	/* Interrupts are handled in order of priority. */
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
+		etrax_usb_hc_epid_attn_interrupt(reg);
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
+		etrax_usb_hc_port_status_interrupt(reg);
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
+		etrax_usb_hc_ctl_status_interrupt(reg);
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
+		etrax_usb_hc_isoc_eof_interrupt();
+	}
+	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
+		/* Update/restart the bulk start timer since obviously the channel is running. */
+		mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
+		/* Update/restart the bulk eot timer since we just received an bulk eot interrupt. */
+		mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+
+		etrax_usb_hc_bulk_eot_interrupt(0);
+	}
+
+	kmem_cache_free(top_half_reg_cache, reg);
+
+	DBFEXIT;
+}
+
+
+void etrax_usb_hc_isoc_eof_interrupt(void)
+{
+	struct urb *urb;
+	etrax_urb_priv_t *urb_priv;
+	int epid;
+	unsigned long flags;
+
+	DBFENTER;
+
+	/* Do not check the invalid epid (it has a valid sub pointer). */
+	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+
+		/* Do not check the invalid epid (it has a valid sub pointer). */
+		if ((epid == DUMMY_EPID) || (epid == INVALID_EPID))
+			continue;
+
+		/* Disable interrupts to block the isoc out descriptor interrupt handler
+		   from being called while the isoc EPID list is being checked.
+		*/
+		save_flags(flags);
+		cli();
+
+		if (TxIsocEPList[epid].sub == 0) {
+			/* Nothing here to see. */
+			restore_flags(flags);
+			continue;
+		}
+
+		/* Get the first urb (if any). */
+		urb = urb_list_first(epid);
+		if (urb == 0) {
+			warn("Ignoring NULL urb");
+			restore_flags(flags);
+			continue;
+		}
+		if (usb_pipein(urb->pipe)) {
+
+			/* Sanity check. */
+			assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
+
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+			assert(urb_priv);
+
+			if (urb_priv->urb_state == NOT_STARTED) {
+
+				/* If ASAP is not set and urb->start_frame is the current frame,
+				   start the transfer. */
+				if (!(urb->transfer_flags & URB_ISO_ASAP) &&
+				    (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
+
+					dbg_isoc("Enabling isoc IN EP descr for epid %d", epid);
+					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+					/* This urb is now active. */
+					urb_priv->urb_state = STARTED;
+					continue;
+				}
+			}
+		}
+		restore_flags(flags);
+	}
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_hc_bulk_eot_interrupt(int timer_induced)
+{
+ 	int epid;
+
+	/* The technique is to run one urb at a time, wait for the eot interrupt at which
+	   point the EP descriptor has been disabled. */
+
+	DBFENTER;
+	dbg_bulk("bulk eot%s", timer_induced ? ", called by timer" : "");
+
+	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+
+		if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
+		    (TxBulkEPList[epid].sub != 0)) {
+
+			struct urb *urb;
+			etrax_urb_priv_t *urb_priv;
+			unsigned long flags;
+			__u32 r_usb_ept_data;
+
+			/* Found a disabled EP descriptor which has a non-null sub pointer.
+			   Verify that this ctrl EP descriptor got disabled no errors.
+			   FIXME: Necessary to check error_code? */
+			dbg_bulk("for epid %d?", epid);
+
+			/* Get the first urb. */
+			urb = urb_list_first(epid);
+
+			/* FIXME: Could this happen for valid reasons? Why did it disappear? Because of
+			   wrong unlinking? */
+			if (!urb) {
+				warn("NULL urb for epid %d", epid);
+				continue;
+			}
+
+			assert(urb);
+			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+			assert(urb_priv);
+
+			/* Sanity checks. */
+			assert(usb_pipetype(urb->pipe) == PIPE_BULK);
+			if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
+				err("bulk endpoint got disabled before reaching last sb");
+			}
+
+			/* For bulk IN traffic, there seems to be a race condition between
+			   between the bulk eot and eop interrupts, or rather an uncertainty regarding
+			   the order in which they happen. Normally we expect the eop interrupt from
+			   DMA channel 9 to happen before the eot interrupt.
+
+			   Therefore, we complete the bulk IN urb in the rx interrupt handler instead. */
+
+			if (usb_pipein(urb->pipe)) {
+				dbg_bulk("in urb, continuing");
+				continue;
+			}
+
+			save_flags(flags);
+			cli();
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+			nop();
+			r_usb_ept_data = *R_USB_EPT_DATA;
+			restore_flags(flags);
+
+			if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
+			    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+				/* This means that the endpoint has no error, is disabled
+				   and had inserted traffic, i.e. transfer successfully completed. */
+				etrax_usb_complete_bulk_urb(urb, 0);
+			} else {
+				/* Shouldn't happen. We expect errors to be caught by epid attention. */
+				err("Found disabled bulk EP desc, error_code != no_error");
+			}
+		}
+	}
+
+	/* Normally, we should find (at least) one disabled EP descriptor with a valid sub pointer.
+	   However, because of the uncertainty in the deliverance of the eop/eot interrupts, we may
+	   not.  Also, we might find two disabled EPs when handling an eot interrupt, and then find
+	   none the next time. */
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg)
+{
+	/* This function handles the epid attention interrupt.  There are a variety of reasons
+	   for this interrupt to happen (Designer's Reference, p. 8 - 22 for the details):
+
+	   invalid ep_id  - Invalid epid in an EP (EP disabled).
+	   stall	  - Not strictly an error condition (EP disabled).
+	   3rd error      - Three successive transaction errors  (EP disabled).
+	   buffer ourun   - Buffer overrun or underrun (EP disabled).
+	   past eof1      - Intr or isoc transaction proceeds past EOF1.
+	   near eof       - Intr or isoc transaction would not fit inside the frame.
+	   zout transfer  - If zout transfer for a bulk endpoint (EP disabled).
+	   setup transfer - If setup transfer for a non-ctrl endpoint (EP disabled). */
+
+	int epid;
+
+
+	DBFENTER;
+
+	assert(reg != NULL);
+
+	/* Note that we loop through all epids. We still want to catch errors for
+	   the invalid one, even though we might handle them differently. */
+	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+
+		if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
+
+			struct urb *urb;
+			__u32 r_usb_ept_data;
+			unsigned long flags;
+			int error_code;
+
+			save_flags(flags);
+			cli();
+			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+			nop();
+			/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
+			   registers, they are located at the same address and are of the same size.
+			   In other words, this read should be ok for isoc also. */
+			r_usb_ept_data = *R_USB_EPT_DATA;
+			restore_flags(flags);
+
+			/* First some sanity checks. */
+			if (epid == INVALID_EPID) {
+				/* FIXME: What if it became disabled? Could seriously hurt interrupt
+				   traffic. (Use do_intr_recover.) */
+				warn("Got epid_attn for INVALID_EPID (%d).", epid);
+				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
+				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
+				continue;
+			} else 	if (epid == DUMMY_EPID) {
+				/* We definitely don't care about these ones. Besides, they are
+				   always disabled, so any possible disabling caused by the
+				   epid attention interrupt is irrelevant. */
+				warn("Got epid_attn for DUMMY_EPID (%d).", epid);
+				continue;
+			}
+
+			/* Get the first urb in the urb list for this epid. We blatantly assume
+			   that only the first urb could have caused the epid attention.
+			   (For bulk and ctrl, only one urb is active at any one time. For intr
+			   and isoc we remove them once they are completed.) */
+			urb = urb_list_first(epid);
+
+			if (urb == NULL) {
+				err("Got epid_attn for epid %i with no urb.", epid);
+				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
+				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
+				continue;
+			}
+
+			switch (usb_pipetype(urb->pipe)) {
+			case PIPE_BULK:
+				warn("Got epid attn for bulk endpoint, epid %d", epid);
+				break;
+			case PIPE_CONTROL:
+				warn("Got epid attn for control endpoint, epid %d", epid);
+				break;
+			case PIPE_INTERRUPT:
+				warn("Got epid attn for interrupt endpoint, epid %d", epid);
+				break;
+			case PIPE_ISOCHRONOUS:
+				warn("Got epid attn for isochronous endpoint, epid %d", epid);
+				break;
+			}
+
+			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
+				if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+					warn("Hold was set for epid %d.", epid);
+					continue;
+				}
+			}
+
+			/* Even though error_code occupies bits 22 - 23 in both R_USB_EPT_DATA and
+			   R_USB_EPT_DATA_ISOC, we separate them here so we don't forget in other places. */
+			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+				error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
+			} else {
+				error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data);
+			}
+
+			/* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
+			if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+
+				/* Isoc traffic doesn't have error_count_in/error_count_out. */
+				if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
+				    (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3 ||
+				     IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3)) {
+					/* 3rd error. */
+					warn("3rd error for epid %i", epid);
+					etrax_usb_complete_urb(urb, -EPROTO);
+
+				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+
+					warn("Perror for epid %d", epid);
+
+					if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
+						/* invalid ep_id */
+						panic("Perror because of invalid epid."
+						      " Deconfigured too early?");
+					} else {
+						/* past eof1, near eof, zout transfer, setup transfer */
+
+						/* Dump the urb and the relevant EP descriptor list. */
+
+						__dump_urb(urb);
+						__dump_ept_data(epid);
+						__dump_ep_list(usb_pipetype(urb->pipe));
+
+						panic("Something wrong with DMA descriptor contents."
+						      " Too much traffic inserted?");
+					}
+				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+					/* buffer ourun */
+					panic("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+				}
+
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) {
+				/* Not really a protocol error, just says that the endpoint gave
+				   a stall response. Note that error_code cannot be stall for isoc. */
+				if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+					panic("Isoc traffic cannot stall");
+				}
+
+				warn("Stall for epid %d", epid);
+				etrax_usb_complete_urb(urb, -EPIPE);
+
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) {
+				/* Two devices responded to a transaction request. Must be resolved
+				   by software. FIXME: Reset ports? */
+				panic("Bus error for epid %d."
+				      " Two devices responded to transaction request",
+				      epid);
+
+			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+				/* DMA overrun or underrun. */
+				warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+
+				/* It seems that error_code = buffer_error in
+				   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
+				   are the same error. */
+				etrax_usb_complete_urb(urb, -EPROTO);
+			}
+		}
+	}
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_bulk_start_timer_func(unsigned long dummy)
+{
+
+	/* We might enable an EP descriptor behind the current DMA position when it's about
+	   to decide that there are no more bulk traffic and it should stop the bulk channel.
+	   Therefore we periodically check if the bulk channel is stopped and there is an
+	   enabled bulk EP descriptor, in which case we start the bulk channel. */
+	dbg_bulk("bulk_start_timer timed out.");
+
+	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+		int epid;
+
+		dbg_bulk("Bulk DMA channel not running.");
+
+		for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+			if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+				dbg_bulk("Found enabled EP for epid %d, starting bulk channel.\n",
+					 epid);
+				*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+
+				/* Restart the bulk eot timer since we just started the bulk channel. */
+				mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+
+				/* No need to search any further. */
+				break;
+			}
+		}
+	} else {
+		dbg_bulk("Bulk DMA channel running.");
+	}
+}
+
+void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg)
+{
+	etrax_hc_t *hc = reg->hc;
+	__u16 r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1;
+	__u16 r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2;
+
+	DBFENTER;
+
+	/* The Etrax RH does not include a wPortChange register, so this has to be handled in software
+	   (by saving the old port status value for comparison when the port status interrupt happens).
+	   See section 11.16.2.6.2 in the USB 1.1 spec for details. */
+
+	dbg_rh("hc->rh.prev_wPortStatus_1 = 0x%x", hc->rh.prev_wPortStatus_1);
+	dbg_rh("hc->rh.prev_wPortStatus_2 = 0x%x", hc->rh.prev_wPortStatus_2);
+	dbg_rh("r_usb_rh_port_status_1 = 0x%x", r_usb_rh_port_status_1);
+	dbg_rh("r_usb_rh_port_status_2 = 0x%x", r_usb_rh_port_status_2);
+
+	/* C_PORT_CONNECTION is set on any transition. */
+	hc->rh.wPortChange_1 |=
+		((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) !=
+		 (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ?
+		(1 << RH_PORT_CONNECTION) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) !=
+		 (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ?
+		(1 << RH_PORT_CONNECTION) : 0;
+
+	/* C_PORT_ENABLE is _only_ set on a one to zero transition, i.e. when
+	   the port is disabled, not when it's enabled. */
+	hc->rh.wPortChange_1 |=
+		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE))
+		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
+		(1 << RH_PORT_ENABLE) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE))
+		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
+		(1 << RH_PORT_ENABLE) : 0;
+
+	/* C_PORT_SUSPEND is set to one when the device has transitioned out
+	   of the suspended state, i.e. when suspend goes from one to zero. */
+	hc->rh.wPortChange_1 |=
+		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_SUSPEND))
+		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_SUSPEND))) ?
+		(1 << RH_PORT_SUSPEND) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_SUSPEND))
+		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_SUSPEND))) ?
+		(1 << RH_PORT_SUSPEND) : 0;
+
+
+	/* C_PORT_RESET is set when reset processing on this port is complete. */
+	hc->rh.wPortChange_1 |=
+		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET))
+		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_RESET))) ?
+		(1 << RH_PORT_RESET) : 0;
+
+	hc->rh.wPortChange_2 |=
+		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET))
+		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_RESET))) ?
+		(1 << RH_PORT_RESET) : 0;
+
+	/* Save the new values for next port status change. */
+	hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1;
+	hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2;
+
+	dbg_rh("hc->rh.wPortChange_1 set to 0x%x", hc->rh.wPortChange_1);
+	dbg_rh("hc->rh.wPortChange_2 set to 0x%x", hc->rh.wPortChange_2);
+
+	DBFEXIT;
+
+}
+
+void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg)
+{
+	DBFENTER;
+
+	/* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
+	   list for the corresponding epid? */
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+		panic("USB controller got ourun.");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+
+		/* Before, etrax_usb_do_intr_recover was called on this epid if it was
+		   an interrupt pipe. I don't see how re-enabling all EP descriptors
+		   will help if there was a programming error. */
+		panic("USB controller got perror.");
+	}
+
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
+		/* We should never operate in device mode. */
+		panic("USB controller in device mode.");
+	}
+
+	/* These if-statements could probably be nested. */
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, host_mode)) {
+		info("USB controller in host mode.");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, started)) {
+		info("USB controller started.");
+	}
+	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, running)) {
+		info("USB controller running.");
+	}
+
+	DBFEXIT;
+
+}
+
+
+static int etrax_rh_submit_urb(struct urb *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	etrax_hc_t *hc = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int stat = 0;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBFENTER;
+
+	/* FIXME: What is this interrupt urb that is sent to the root hub? */
+	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+		dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval);
+		hc->rh.urb = urb;
+		hc->rh.send = 1;
+		/* FIXME: We could probably remove this line since it's done
+		   in etrax_rh_init_int_timer. (Don't remove it from
+		   etrax_rh_init_int_timer though.) */
+		hc->rh.interval = urb->interval;
+		etrax_rh_init_int_timer(urb);
+		DBFEXIT;
+
+		return 0;
+	}
+
+	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
+
+	dbg_rh("bmRType_bReq : 0x%04x (%d)", bmRType_bReq, bmRType_bReq);
+	dbg_rh("wValue       : 0x%04x (%d)", wValue, wValue);
+	dbg_rh("wIndex       : 0x%04x (%d)", wIndex, wIndex);
+	dbg_rh("wLength      : 0x%04x (%d)", wLength, wLength);
+
+	switch (bmRType_bReq) {
+
+		/* Request Destination:
+		   without flags: Device,
+		   RH_INTERFACE: interface,
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here,
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data = cpu_to_le16 (1);
+		OK (2);
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data = cpu_to_le32 (0);
+		OK (4);		/* hub power ** */
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		if (wIndex == 1) {
+			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
+			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
+		} else if (wIndex == 2) {
+			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
+			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
+		} else {
+			dbg_rh("RH_GET_STATUS whith invalid wIndex!");
+			OK(0);
+		}
+
+		OK(4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case (RH_C_HUB_OVER_CURRENT):
+			OK (0);	/* hub power over current ** */
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			if (wIndex == 1) {
+
+				dbg_rh("trying to do disable port 1");
+
+				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
+
+				while (hc->rh.prev_wPortStatus_1 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes));
+				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+				dbg_rh("Port 1 is disabled");
+
+			} else if (wIndex == 2) {
+
+				dbg_rh("trying to do disable port 2");
+
+				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
+
+				while (hc->rh.prev_wPortStatus_2 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes));
+				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+				dbg_rh("Port 2 is disabled");
+
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_PORT_SUSPEND):
+			/* Opposite to suspend should be resume, so we'll do a resume. */
+			/* FIXME: USB 1.1, 11.16.2.2 says:
+			   "Clearing the PORT_SUSPEND feature causes a host-initiated resume
+			   on the specified port. If the port is not in the Suspended state,
+			   the hub should treat this request as a functional no-operation."
+			   Shouldn't we check if the port is in a suspended state before
+			   resuming? */
+
+			/* Make sure the controller isn't busy. */
+			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+			if (wIndex == 1) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else if (wIndex == 2) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_C_PORT_CONNECTION):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
+			} else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_C_PORT_ENABLE):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE);
+			} else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+			OK (0);
+		case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK (0);
+		case (RH_C_PORT_OVER_CURRENT):
+			OK (0);	/* port power over current ** */
+		case (RH_C_PORT_RESET):
+			if (wIndex == 1) {
+				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET);
+			} else if (wIndex == 2) {
+				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET);
+			} else {
+				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET "
+				       "with invalid index == %d!", wIndex);
+			}
+
+			OK (0);
+
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+
+			/* Make sure the controller isn't busy. */
+			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+			if (wIndex == 1) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else if (wIndex == 2) {
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_PORT_SUSPEND "
+				       "with invalid wIndex == %d!", wIndex);
+			}
+
+			OK (0);
+		case (RH_PORT_RESET):
+			if (wIndex == 1) {
+
+			port_1_reset:
+				dbg_rh("Doing reset of port 1");
+
+				/* Make sure the controller isn't busy. */
+				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port1) |
+					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+
+				/* We must wait at least 10 ms for the device to recover.
+				   15 ms should be enough. */
+				udelay(15000);
+
+				/* Wait for reset bit to go low (should be done by now). */
+				while (hc->rh.prev_wPortStatus_1 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes));
+
+				/* If the port status is
+				   1) connected and enabled then there is a device and everything is fine
+				   2) neither connected nor enabled then there is no device, also fine
+				   3) connected and not enabled then we try again
+				   (Yes, there are other port status combinations besides these.) */
+
+				if ((hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
+				    (hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
+					dbg_rh("Connected device on port 1, but port not enabled?"
+					       " Trying reset again.");
+					goto port_2_reset;
+				}
+
+				/* Diagnostic printouts. */
+				if ((hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, no)) &&
+				    (hc->rh.prev_wPortStatus_1 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
+					dbg_rh("No connected device on port 1");
+				} else if ((hc->rh.prev_wPortStatus_1 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
+					   (hc->rh.prev_wPortStatus_1 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) {
+					dbg_rh("Connected device on port 1, port 1 enabled");
+				}
+
+			} else if (wIndex == 2) {
+
+			port_2_reset:
+				dbg_rh("Doing reset of port 2");
+
+				/* Make sure the controller isn't busy. */
+				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+				/* Issue the reset command. */
+				*R_USB_COMMAND =
+					IO_STATE(R_USB_COMMAND, port_sel, port2) |
+					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+
+				/* We must wait at least 10 ms for the device to recover.
+				   15 ms should be enough. */
+				udelay(15000);
+
+				/* Wait for reset bit to go low (should be done by now). */
+				while (hc->rh.prev_wPortStatus_2 &
+				       IO_STATE(R_USB_RH_PORT_STATUS_2, reset, yes));
+
+				/* If the port status is
+				   1) connected and enabled then there is a device and everything is fine
+				   2) neither connected nor enabled then there is no device, also fine
+				   3) connected and not enabled then we try again
+				   (Yes, there are other port status combinations besides these.) */
+
+				if ((hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
+				    (hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
+					dbg_rh("Connected device on port 2, but port not enabled?"
+					       " Trying reset again.");
+					goto port_2_reset;
+				}
+
+				/* Diagnostic printouts. */
+				if ((hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, no)) &&
+				    (hc->rh.prev_wPortStatus_2 &
+				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
+					dbg_rh("No connected device on port 2");
+				} else if ((hc->rh.prev_wPortStatus_2 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
+					   (hc->rh.prev_wPortStatus_2 &
+					    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) {
+					dbg_rh("Connected device on port 2, port 2 enabled");
+				}
+
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_PORT_RESET with invalid wIndex = %d", wIndex);
+			}
+
+			/* Make sure the controller isn't busy. */
+			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+			/* If all enabled ports were disabled the host controller goes down into
+			   started mode, so we need to bring it back into the running state.
+			   (This is safe even if it's already in the running state.) */
+			*R_USB_COMMAND =
+				IO_STATE(R_USB_COMMAND, port_sel, nop) |
+				IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+				IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+
+			dbg_rh("...Done");
+			OK(0);
+
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_PORT_ENABLE):
+			/* There is no port enable command in the host controller, so if the
+			   port is already enabled, we do nothing. If not, we reset the port
+			   (with an ugly goto). */
+
+			if (wIndex == 1) {
+				if (hc->rh.prev_wPortStatus_1 &
+				    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no)) {
+					goto port_1_reset;
+				}
+			} else if (wIndex == 2) {
+				if (hc->rh.prev_wPortStatus_2 &
+				    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no)) {
+					goto port_2_reset;
+				}
+			} else {
+				dbg_rh("RH_SET_FEATURE->RH_GET_STATUS with invalid wIndex = %d", wIndex);
+			}
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		hc->rh.devnum = wValue;
+		dbg_rh("RH address set to: %d", hc->rh.devnum);
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength));
+			memcpy (data, root_hub_dev_des, len);
+			OK (len);
+		case (0x02):	/* configuration descriptor */
+			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK (len);
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+						   0xff, "ETRAX 100LX",
+						   data, wLength);
+			if (len > 0) {
+				OK(min(leni, len));
+			} else {
+				stat = -EPIPE;
+			}
+
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = hc->rh.numports;
+		len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
+		memcpy (data, root_hub_hub_des, len);
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+	urb->status = stat;
+	urb->dev = NULL;
+	if (urb->complete) {
+		urb->complete(urb, NULL);
+	}
+	DBFEXIT;
+
+	return 0;
+}
+
+static void
+etrax_usb_bulk_eot_timer_func(unsigned long dummy)
+{
+	/* Because of a race condition in the top half, we might miss a bulk eot.
+	   This timer "simulates" a bulk eot if we don't get one for a while, hopefully
+	   correcting the situation. */
+	dbg_bulk("bulk_eot_timer timed out.");
+	etrax_usb_hc_bulk_eot_interrupt(1);
+}
+
+static void*
+etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma)
+{
+  return kmalloc(size, mem_flags);
+}
+
+static void
+etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma)
+{
+  kfree(addr);
+}
+
+
+static struct device fake_device;
+
+static int __init etrax_usb_hc_init(void)
+{
+	static etrax_hc_t *hc;
+	struct usb_bus *bus;
+	struct usb_device *usb_rh;
+	int i;
+
+	DBFENTER;
+
+	info("ETRAX 100LX USB-HCD %s (c) 2001-2003 Axis Communications AB\n", usb_hcd_version);
+
+ 	hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL);
+	assert(hc != NULL);
+
+	/* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
+	/* Note that we specify sizeof(USB_EP_Desc_t) as the size, but also allocate
+	   SB descriptors from this cache. This is ok since sizeof(USB_EP_Desc_t) ==
+	   sizeof(USB_SB_Desc_t). */
+
+	usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0,
+					   SLAB_HWCACHE_ALIGN, 0, 0);
+	assert(usb_desc_cache != NULL);
+
+	top_half_reg_cache = kmem_cache_create("top_half_reg_cache",
+					       sizeof(usb_interrupt_registers_t),
+					       0, SLAB_HWCACHE_ALIGN, 0, 0);
+	assert(top_half_reg_cache != NULL);
+
+	isoc_compl_cache = kmem_cache_create("isoc_compl_cache",
+						sizeof(usb_isoc_complete_data_t),
+						0, SLAB_HWCACHE_ALIGN, 0, 0);
+	assert(isoc_compl_cache != NULL);
+
+	etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
+	hc->bus = bus;
+	bus->bus_name="ETRAX 100LX";
+	bus->hcpriv = hc;
+
+	/* Initalize RH to the default address.
+	   And make sure that we have no status change indication */
+	hc->rh.numports = 2;  /* The RH has two ports */
+	hc->rh.devnum = 1;
+	hc->rh.wPortChange_1 = 0;
+	hc->rh.wPortChange_2 = 0;
+
+	/* Also initate the previous values to zero */
+	hc->rh.prev_wPortStatus_1 = 0;
+	hc->rh.prev_wPortStatus_2 = 0;
+
+	/* Initialize the intr-traffic flags */
+	/* FIXME: This isn't used. (Besides, the error field isn't initialized.) */
+	hc->intr.sleeping = 0;
+	hc->intr.wq = NULL;
+
+	epid_usage_bitmask = 0;
+	epid_out_traffic = 0;
+
+	/* Mark the invalid epid as being used. */
+	set_bit(INVALID_EPID, (void *)&epid_usage_bitmask);
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, INVALID_EPID);
+	nop();
+	/* The valid bit should still be set ('invalid' is in our world; not the hardware's). */
+	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, yes) |
+			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
+
+	/* Mark the dummy epid as being used. */
+	set_bit(DUMMY_EPID, (void *)&epid_usage_bitmask);
+	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, DUMMY_EPID);
+	nop();
+	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, no) |
+			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
+
+	/* Initialize the urb list by initiating a head for each list. */
+	for (i = 0; i < NBR_OF_EPIDS; i++) {
+		INIT_LIST_HEAD(&urb_list[i]);
+	}
+	spin_lock_init(&urb_list_lock);
+
+	INIT_LIST_HEAD(&urb_unlink_list);
+
+
+	/* Initiate the bulk start timer. */
+	init_timer(&bulk_start_timer);
+	bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
+	bulk_start_timer.function = etrax_usb_bulk_start_timer_func;
+	add_timer(&bulk_start_timer);
+
+
+	/* Initiate the bulk eot timer. */
+	init_timer(&bulk_eot_timer);
+	bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
+	bulk_eot_timer.function = etrax_usb_bulk_eot_timer_func;
+	add_timer(&bulk_eot_timer);
+
+	/* Set up the data structures for USB traffic. Note that this must be done before
+	   any interrupt that relies on sane DMA list occurrs. */
+	init_rx_buffers();
+	init_tx_bulk_ep();
+	init_tx_ctrl_ep();
+	init_tx_intr_ep();
+	init_tx_isoc_ep();
+
+        device_initialize(&fake_device);
+        kobject_set_name(&fake_device.kobj, "etrax_usb");
+        kobject_add(&fake_device.kobj);
+        hc->bus->controller = &fake_device;
+	usb_register_bus(hc->bus);
+
+	*R_IRQ_MASK2_SET =
+		/* Note that these interrupts are not used. */
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
+		/* Sub channel 1 (ctrl) descr. interrupts are used. */
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
+		/* Sub channel 3 (isoc) descr. interrupts are used. */
+		IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
+
+	/* Note that the dma9_descr interrupt is not used. */
+	*R_IRQ_MASK2_SET =
+		IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
+
+	/* FIXME: Enable iso_eof only when isoc traffic is running. */
+	*R_USB_IRQ_MASK_SET =
+		IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
+		IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
+
+
+	if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_interrupt_top_half, 0,
+			"ETRAX 100LX built-in USB (HC)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0,
+			"ETRAX 100LX built-in USB (Rx)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0,
+			"ETRAX 100LX built-in USB (Tx)", hc)) {
+		err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
+		etrax_usb_hc_cleanup();
+		DBFEXIT;
+		return -1;
+	}
+
+	/* R_USB_COMMAND:
+	   USB commands in host mode. The fields in this register should all be
+	   written to in one write. Do not read-modify-write one field at a time. A
+	   write to this register will trigger events in the USB controller and an
+	   incomplete command may lead to unpredictable results, and in worst case
+	   even to a deadlock in the controller.
+	   (Note however that the busy field is read-only, so no need to write to it.) */
+
+	/* Check the busy bit before writing to R_USB_COMMAND. */
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Reset the USB interface. */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, nop) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
+
+	/* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to 0x2A30 (10800),
+	   to guarantee that control traffic gets 10% of the bandwidth, and periodic transfer may
+	   allocate the rest (90%). This doesn't work though. Read on for a lenghty explanation.
+
+	   While there is a difference between rev. 2 and rev. 3 of the ETRAX 100LX regarding the NAK
+	   behaviour, it doesn't solve this problem. What happens is that a control transfer will not
+	   be interrupted in its data stage when PSTART happens (the point at which periodic traffic
+	   is started). Thus, if PSTART is set to 10800 and its IN or OUT token is NAKed until just before
+	   PSTART happens, it will continue the IN/OUT transfer as long as it's ACKed. After it's done,
+	   there may be too little time left for an isochronous transfer, causing an epid attention
+	   interrupt due to perror. The work-around for this is to let the control transfers run at the
+	   end of the frame instead of at the beginning, and will be interrupted just fine if it doesn't
+	   fit into the frame. However, since there will *always* be a control transfer at the beginning
+	   of the frame, regardless of what we set PSTART to, that transfer might be a 64-byte transfer
+	   which consumes up to 15% of the frame, leaving only 85% for periodic traffic. The solution to
+	   this would be to 'dummy allocate' 5% of the frame with the usb_claim_bandwidth function to make
+	   sure that the periodic transfers that are inserted will always fit in the frame.
+
+	   The idea was suggested that a control transfer could be split up into several 8 byte transfers,
+	   so that it would be interrupted by PSTART, but since this can't be done for an IN transfer this
+	   hasn't been implemented.
+
+	   The value 11960 is chosen to be just after the SOF token, with a couple of bit times extra
+	   for possible bit stuffing. */
+
+	*R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+	*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+#endif
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+	*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+#endif
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Configure the USB interface as a host controller. */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, nop) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
+
+	/* Note: Do not reset any ports here. Await the port status interrupts, to have a controlled
+	   sequence of resetting the ports. If we reset both ports now, and there are devices
+	   on both ports, we will get a bus error because both devices will answer the set address
+	   request. */
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	/* Start processing of USB traffic. */
+	*R_USB_COMMAND =
+		IO_STATE(R_USB_COMMAND, port_sel, nop) |
+		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+
+	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+	usb_rh = usb_alloc_dev(NULL, hc->bus, 0);
+	hc->bus->root_hub = usb_rh;
+        usb_rh->state = USB_STATE_ADDRESS;
+        usb_rh->speed = USB_SPEED_FULL;
+        usb_rh->devnum = 1;
+        hc->bus->devnum_next = 2;
+        usb_rh->epmaxpacketin[0] = usb_rh->epmaxpacketout[0] = 64;
+        usb_get_device_descriptor(usb_rh, USB_DT_DEVICE_SIZE);
+	usb_new_device(usb_rh);
+
+	DBFEXIT;
+
+	return 0;
+}
+
+static void etrax_usb_hc_cleanup(void)
+{
+	DBFENTER;
+
+	free_irq(ETRAX_USB_HC_IRQ, NULL);
+	free_irq(ETRAX_USB_RX_IRQ, NULL);
+	free_irq(ETRAX_USB_TX_IRQ, NULL);
+
+	usb_deregister_bus(etrax_usb_bus);
+
+	/* FIXME: call kmem_cache_destroy here? */
+
+	DBFEXIT;
+}
+
+module_init(etrax_usb_hc_init);
+module_exit(etrax_usb_hc_cleanup);
diff -puN /dev/null drivers/usb/host/hc_crisv10.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/usb/host/hc_crisv10.h	Mon Nov  8 14:19:37 2004
@@ -0,0 +1,289 @@
+#ifndef __LINUX_ETRAX_USB_H
+#define __LINUX_ETRAX_USB_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+typedef struct USB_IN_Desc {
+	volatile __u16 sw_len;
+	volatile __u16 command;
+	volatile unsigned long next;
+	volatile unsigned long buf;
+	volatile __u16 hw_len;
+	volatile __u16 status;
+} USB_IN_Desc_t;
+
+typedef struct USB_SB_Desc {
+	volatile __u16 sw_len;
+	volatile __u16 command;
+	volatile unsigned long next;
+	volatile unsigned long buf;
+	__u32 dummy;
+} USB_SB_Desc_t;
+
+typedef struct USB_EP_Desc {
+	volatile __u16 hw_len;
+	volatile __u16 command;
+	volatile unsigned long sub;
+	volatile unsigned long next;
+	__u32 dummy;
+} USB_EP_Desc_t;
+
+struct virt_root_hub {
+	int devnum;
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	struct timer_list rh_int_timer;
+	volatile __u16 wPortChange_1;
+	volatile __u16 wPortChange_2;
+	volatile __u16 prev_wPortStatus_1;
+	volatile __u16 prev_wPortStatus_2;
+};
+
+struct etrax_usb_intr_traffic {
+	int sleeping;
+	int error;
+	struct wait_queue *wq;
+};
+
+typedef struct etrax_usb_hc {
+	struct usb_bus *bus;
+	struct virt_root_hub rh;
+	struct etrax_usb_intr_traffic intr;
+} etrax_hc_t;
+
+typedef enum {
+	STARTED,
+	NOT_STARTED,
+	UNLINK,
+	TRANSFER_DONE,
+	WAITING_FOR_DESCR_INTR
+} etrax_usb_urb_state_t;
+
+
+
+typedef struct etrax_usb_urb_priv {
+	/* The first_sb field is used for freeing all SB descriptors belonging
+	   to an urb. The corresponding ep descriptor's sub pointer cannot be
+	   used for this since the DMA advances the sub pointer as it processes
+	   the sb list. */
+	USB_SB_Desc_t *first_sb;
+	/* The last_sb field referes to the last SB descriptor that belongs to
+	   this urb. This is important to know so we can free the SB descriptors
+	   that ranges between first_sb and last_sb. */
+	USB_SB_Desc_t *last_sb;
+
+	/* The rx_offset field is used in ctrl and bulk traffic to keep track
+	   of the offset in the urb's transfer_buffer where incoming data should be
+	   copied to. */
+	__u32 rx_offset;
+
+	/* Counter used in isochronous transfers to keep track of the
+	   number of packets received/transmitted.  */
+	__u32 isoc_packet_counter;
+
+	/* This field is used to pass information about the urb's current state between
+	   the various interrupt handlers (thus marked volatile). */
+	volatile etrax_usb_urb_state_t urb_state;
+
+	/* Connection between the submitted urb and ETRAX epid number */
+	__u8 epid;
+
+	/* The rx_data_list field is used for periodic traffic, to hold
+	   received data for later processing in the the complete_urb functions,
+	   where the data us copied to the urb's transfer_buffer. Basically, we
+	   use this intermediate storage because we don't know when it's safe to
+	   reuse the transfer_buffer (FIXME?). */
+	struct list_head rx_data_list;
+} etrax_urb_priv_t;
+
+/* This struct is for passing data from the top half to the bottom half. */
+typedef struct usb_interrupt_registers
+{
+	etrax_hc_t *hc;
+	__u32 r_usb_epid_attn;
+	__u8 r_usb_status;
+	__u16 r_usb_rh_port_status_1;
+	__u16 r_usb_rh_port_status_2;
+	__u32 r_usb_irq_mask_read;
+	__u32 r_usb_fm_number;
+	struct work_struct usb_bh;
+} usb_interrupt_registers_t;
+
+/* This struct is for passing data from the isoc top half to the isoc bottom half. */
+typedef struct usb_isoc_complete_data
+{
+	struct urb *urb;
+	struct work_struct usb_bh;
+} usb_isoc_complete_data_t;
+
+/* This struct holds data we get from the rx descriptors for DMA channel 9
+   for periodic traffic (intr and isoc). */
+typedef struct rx_data
+{
+	void *data;
+	int length;
+	struct list_head list;
+} rx_data_t;
+
+typedef struct urb_entry
+{
+	struct urb *urb;
+	struct list_head list;
+} urb_entry_t;
+
+/* ---------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* 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
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+/* Field definitions for */
+
+#define USB_IN_command__eol__BITNR      0 /* command macros */
+#define USB_IN_command__eol__WIDTH      1
+#define USB_IN_command__eol__no         0
+#define USB_IN_command__eol__yes        1
+
+#define USB_IN_command__intr__BITNR     3
+#define USB_IN_command__intr__WIDTH     1
+#define USB_IN_command__intr__no        0
+#define USB_IN_command__intr__yes       1
+
+#define USB_IN_status__eop__BITNR       1 /* status macros. */
+#define USB_IN_status__eop__WIDTH       1
+#define USB_IN_status__eop__no          0
+#define USB_IN_status__eop__yes         1
+
+#define USB_IN_status__eot__BITNR       5
+#define USB_IN_status__eot__WIDTH       1
+#define USB_IN_status__eot__no          0
+#define USB_IN_status__eot__yes         1
+
+#define USB_IN_status__error__BITNR     6
+#define USB_IN_status__error__WIDTH     1
+#define USB_IN_status__error__no        0
+#define USB_IN_status__error__yes       1
+
+#define USB_IN_status__nodata__BITNR    7
+#define USB_IN_status__nodata__WIDTH    1
+#define USB_IN_status__nodata__no       0
+#define USB_IN_status__nodata__yes      1
+
+#define USB_IN_status__epid__BITNR      8
+#define USB_IN_status__epid__WIDTH      5
+
+#define USB_EP_command__eol__BITNR      0
+#define USB_EP_command__eol__WIDTH      1
+#define USB_EP_command__eol__no         0
+#define USB_EP_command__eol__yes        1
+
+#define USB_EP_command__eof__BITNR      1
+#define USB_EP_command__eof__WIDTH      1
+#define USB_EP_command__eof__no         0
+#define USB_EP_command__eof__yes        1
+
+#define USB_EP_command__intr__BITNR     3
+#define USB_EP_command__intr__WIDTH     1
+#define USB_EP_command__intr__no        0
+#define USB_EP_command__intr__yes       1
+
+#define USB_EP_command__enable__BITNR   4
+#define USB_EP_command__enable__WIDTH   1
+#define USB_EP_command__enable__no      0
+#define USB_EP_command__enable__yes     1
+
+#define USB_EP_command__hw_valid__BITNR 5
+#define USB_EP_command__hw_valid__WIDTH 1
+#define USB_EP_command__hw_valid__no    0
+#define USB_EP_command__hw_valid__yes   1
+
+#define USB_EP_command__epid__BITNR     8
+#define USB_EP_command__epid__WIDTH     5
+
+#define USB_SB_command__eol__BITNR      0 /* command macros. */
+#define USB_SB_command__eol__WIDTH      1
+#define USB_SB_command__eol__no         0
+#define USB_SB_command__eol__yes        1
+
+#define USB_SB_command__eot__BITNR      1
+#define USB_SB_command__eot__WIDTH      1
+#define USB_SB_command__eot__no         0
+#define USB_SB_command__eot__yes        1
+
+#define USB_SB_command__intr__BITNR     3
+#define USB_SB_command__intr__WIDTH     1
+#define USB_SB_command__intr__no        0
+#define USB_SB_command__intr__yes       1
+
+#define USB_SB_command__tt__BITNR       4
+#define USB_SB_command__tt__WIDTH       2
+#define USB_SB_command__tt__zout        0
+#define USB_SB_command__tt__in          1
+#define USB_SB_command__tt__out         2
+#define USB_SB_command__tt__setup       3
+
+
+#define USB_SB_command__rem__BITNR      8
+#define USB_SB_command__rem__WIDTH      6
+
+#define USB_SB_command__full__BITNR     6
+#define USB_SB_command__full__WIDTH     1
+#define USB_SB_command__full__no        0
+#define USB_SB_command__full__yes       1
+
+#endif
_