summaryrefslogtreecommitdiffstats
path: root/target/linux/etrax-2.6/patches/cris/003-drivers-cris.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/etrax-2.6/patches/cris/003-drivers-cris.patch')
-rw-r--r--target/linux/etrax-2.6/patches/cris/003-drivers-cris.patch22601
1 files changed, 22601 insertions, 0 deletions
diff --git a/target/linux/etrax-2.6/patches/cris/003-drivers-cris.patch b/target/linux/etrax-2.6/patches/cris/003-drivers-cris.patch
new file mode 100644
index 0000000000..1f42fc86e6
--- /dev/null
+++ b/target/linux/etrax-2.6/patches/cris/003-drivers-cris.patch
@@ -0,0 +1,22601 @@
+diff -urN linux-2.6.19.2.orig/drivers/ide/cris/ide-cris.c linux-2.6.19.2.dev/drivers/ide/cris/ide-cris.c
+--- linux-2.6.19.2.orig/drivers/ide/cris/ide-cris.c 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/ide/cris/ide-cris.c 2006-12-06 14:17:02.000000000 +0100
+@@ -1,8 +1,8 @@
+-/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm Exp $
++/* $Id: ide-cris.c,v 1.10 2006/12/06 13:17:02 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-2005 Axis Communications AB
++ * Copyright (c) 2000-2006 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (initial version)
+ * Mikael Starvik (crisv32 port)
+@@ -43,8 +43,8 @@
+
+ #define IDE_REGISTER_TIMEOUT 300
+
+-#define LOWDB(x)
+-#define D(x)
++#define LOWDB(x)
++#define D(x)
+
+ enum /* Transfer types */
+ {
+@@ -88,12 +88,50 @@
+ #define ATA_PIO0_STROBE 39
+ #define ATA_PIO0_HOLD 9
+
+-int
++/*
++ * On ETRAX FS, an interrupt remains latched and active until ack:ed.
++ * Further, ATA acks are without effect as long as INTRQ is asserted, as the
++ * corresponding ATA interrupt is continuously set to active. There will be a
++ * clearing ack at the usual cris_ide_ack_intr call, but that serves just to
++ * gracefully handle an actual spurious interrupt or similar situation (which
++ * will cause an early return without further actions, see the ide_intr
++ * function).
++ *
++ * However, the normal case at time of this writing is that nothing has
++ * changed from when INTRQ was asserted until the cris_ide_ack_intr call; no
++ * ATA registers written and no status register read, so INTRQ will *remain*
++ * asserted, thus *another* interrupt will be latched, and will be seen as a
++ * spurious interrupt after the "real" interrupt is serviced. With lots of
++ * ATA traffic (as in a trivial file-copy between two drives), this will trig
++ * the condition desc->irqs_unhandled > 99900 in
++ * kernel/irq/spurious.c:note_interrupt and the system will halt.
++ *
++ * To actually get rid of the interrupt corresponding to the current INTRQ
++ * assertion, we make a second ack after the next ATA register read or write;
++ * i.e. when INTRQ must be deasserted. At that time, we don't have the hwif
++ * pointer available, so we need to stash a local copy (safe, because it'll be
++ * set and cleared within the same spin_lock_irqsave region). The pointer
++ * serves doubly as a boolean flag that an ack is needed. The caller must
++ * NULL the pointer after the "second ack".
++ */
++
++static ide_hwif_t *hwif_to_ack;
++
++static int
+ cris_ide_ack_intr(ide_hwif_t* hwif)
+ {
+- reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2,
++ /*
++ * The interrupt is shared so we need to find the interface bit number
++ * to ack. We define the ATA I/O register addresses to have the
++ * format of ata rw_ctrl2 register contents, conveniently holding this
++ * number.
++ */
++ reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2,
+ int, hwif->io_ports[0]);
+ REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel);
++
++ /* Prepare to ack again, see above. */
++ hwif_to_ack = hwif;
+ return 1;
+ }
+
+@@ -122,8 +160,24 @@
+
+ static void
+ cris_ide_write_command(unsigned long command)
+-{
++{
+ REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */
++
++ /*
++ * Perform a pending ack if needed; see hwif_ack definition. Perhaps
++ * we should check closer that this call is really a part of the
++ * preparation to read the ATA status register or write to the ATA
++ * command register (causing deassert of INTRQ; see the ATA standard),
++ * but at time of this writing (and expected to sanely remain so), the
++ * first ATA register activity after an cris_ide_ack_intr call is
++ * certain to do exactly that.
++ */
++ if (hwif_to_ack) {
++ /* The drive may take this long to deassert INTRQ. */
++ ndelay(400);
++ cris_ide_ack_intr(hwif_to_ack);
++ hwif_to_ack = NULL;
++ }
+ }
+
+ static void
+@@ -160,8 +214,8 @@
+ {
+ reg_ata_rw_ctrl2 ctrl2 = {0};
+ ctrl2.addr = addr;
+- ctrl2.cs1 = cs1;
+- ctrl2.cs0 = cs0;
++ ctrl2.cs1 = !cs1;
++ ctrl2.cs0 = !cs0;
+ return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2);
+ }
+
+@@ -184,14 +238,14 @@
+
+ intr_mask.bus0 = regk_ata_yes;
+ intr_mask.bus1 = regk_ata_yes;
+- intr_mask.bus2 = regk_ata_yes;
++ intr_mask.bus2 = regk_ata_yes;
+ intr_mask.bus3 = regk_ata_yes;
+
+ REG_WR(ata, regi_ata, rw_intr_mask, intr_mask);
+
+ crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);
+ crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);
+-
++
+ crisv32_pinmux_alloc_fixed(pinmux_ata);
+ crisv32_pinmux_alloc_fixed(pinmux_ata0);
+ crisv32_pinmux_alloc_fixed(pinmux_ata1);
+@@ -204,14 +258,15 @@
+ DMA_ENABLE(regi_dma3);
+
+ DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2);
+- DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2);
++ DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2);
+ }
+
+ static dma_descr_context mycontext __attribute__ ((__aligned__(32)));
+
+ #define cris_dma_descr_type dma_descr_data
+-#define cris_pio_read regk_ata_rd
+-#define cris_ultra_mask 0x7
++#define cris_pio_read (regk_ata_rd << 24)
++#define cris_ultra_mask 0x0 /* 0x7 for UDMA */
++#define IRQ ATA_INTR_VECT
+ #define MAX_DESCR_SIZE 0xffffffffUL
+
+ static unsigned long
+@@ -226,6 +281,8 @@
+ d->buf = (char*)virt_to_phys(buf);
+ d->after = d->buf + len;
+ d->eol = last;
++ /* assume descriptors are consecutively placed in memory */
++ d->next = last ? 0 : (cris_dma_descr_type*)virt_to_phys(d+1);
+ }
+
+ static void
+@@ -237,8 +294,10 @@
+ mycontext.saved_data = (dma_descr_data*)virt_to_phys(d);
+ mycontext.saved_data_buf = d->buf;
+ /* start the dma channel */
++ if (dir)
++ flush_dma_context(&mycontext); // Cache bug workaround
+ DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext));
+-
++
+ /* initiate a multi word dma read using PIO handshaking */
+ trf_cnt.cnt = len >> 1;
+ /* Due to a "feature" the transfer count has to be one extra word for UDMA. */
+@@ -248,7 +307,7 @@
+
+ ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr;
+ ctrl2.trf_mode = regk_ata_dma;
+- ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio :
++ ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio :
+ type == TYPE_DMA ? regk_ata_dma : regk_ata_udma;
+ ctrl2.multi = regk_ata_yes;
+ ctrl2.dma_size = regk_ata_word;
+@@ -339,7 +398,7 @@
+ #define ATA_PIO0_STROBE 19
+ #define ATA_PIO0_HOLD 4
+
+-int
++int
+ cris_ide_ack_intr(ide_hwif_t* hwif)
+ {
+ return 1;
+@@ -348,13 +407,13 @@
+ static inline int
+ cris_ide_busy(void)
+ {
+- return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ;
++ return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ;
+ }
+
+ static inline int
+ cris_ide_ready(void)
+ {
+- return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ;
++ return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ;
+ }
+
+ static inline int
+@@ -364,12 +423,12 @@
+ *data = (unsigned short)status;
+ return status & IO_MASK(R_ATA_STATUS_DATA, dav);
+ }
+-
++
+ static void
+ cris_ide_write_command(unsigned long command)
+ {
+- *R_ATA_CTRL_DATA = command;
+-}
++ *R_ATA_CTRL_DATA = command;
++}
+
+ static void
+ cris_ide_set_speed(int type, int setup, int strobe, int hold)
+@@ -406,8 +465,8 @@
+ cris_ide_reg_addr(unsigned long addr, int cs0, int cs1)
+ {
+ return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) |
+- IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) |
+- IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1);
++ IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0 ? 0 : 1) |
++ IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1 ? 0 : 1);
+ }
+
+ static __init void
+@@ -484,6 +543,7 @@
+ #define cris_dma_descr_type etrax_dma_descr
+ #define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read)
+ #define cris_ultra_mask 0x0
++#define IRQ 4
+ #define MAX_DESCR_SIZE 0x10000UL
+
+ static unsigned long
+@@ -497,8 +557,8 @@
+ {
+ d->buf = virt_to_phys(buf);
+ d->sw_len = len == MAX_DESCR_SIZE ? 0 : len;
+- if (last)
+- d->ctrl |= d_eol;
++ d->ctrl = last ? d_eol : 0;
++ d->next = last ? 0 : virt_to_phys(d+1); /* assumes descr's in array */
+ }
+
+ static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len)
+@@ -521,14 +581,14 @@
+ *R_DMA_CH2_FIRST = virt_to_phys(d);
+ *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+ }
+-
++
+ /* initiate a multi word dma read using DMA handshaking */
+
+ *R_ATA_TRANSFER_CNT =
+ IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1);
+
+ cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write);
+- cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) :
++ cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) :
+ IO_STATE(R_ATA_CTRL_DATA, handsh, dma);
+ *R_ATA_CTRL_DATA =
+ cmd |
+@@ -570,7 +630,7 @@
+ }
+
+ #endif
+-
++
+ void
+ cris_ide_outw(unsigned short data, unsigned long reg) {
+ int timeleft;
+@@ -597,7 +657,7 @@
+ if(!timeleft)
+ printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
+
+- cris_ide_write_command(reg|data); /* write data to the drive's register */
++ cris_ide_write_command(reg|data); /* write data to the drive's register */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for transmitter ready */
+@@ -684,13 +744,15 @@
+ static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
+ static int cris_dma_off (ide_drive_t *drive);
+ static int cris_dma_on (ide_drive_t *drive);
++static int cris_dma_host_off (ide_drive_t *drive);
++static int cris_dma_host_on (ide_drive_t *drive);
+
+ static void tune_cris_ide(ide_drive_t *drive, u8 pio)
+ {
+ int setup, strobe, hold;
+
+ switch(pio)
+- {
++ {
+ case 0:
+ setup = ATA_PIO0_SETUP;
+ strobe = ATA_PIO0_STROBE;
+@@ -715,7 +777,7 @@
+ setup = ATA_PIO4_SETUP;
+ strobe = ATA_PIO4_STROBE;
+ hold = ATA_PIO4_HOLD;
+- break;
++ break;
+ default:
+ return;
+ }
+@@ -733,7 +795,7 @@
+ }
+
+ switch(speed)
+- {
++ {
+ case XFER_UDMA_0:
+ cyc = ATA_UDMA0_CYC;
+ dvs = ATA_UDMA0_DVS;
+@@ -765,7 +827,7 @@
+ if (speed >= XFER_UDMA_0)
+ cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0);
+ else
+- cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
++ cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
+
+ return 0;
+ }
+@@ -790,11 +852,13 @@
+
+ for(h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+- ide_setup_ports(&hw, cris_ide_base_address(h),
++ memset(&hw, 0, sizeof(hw));
++ ide_setup_ports(&hw, cris_ide_base_address(h),
+ ide_offsets,
+ 0, 0, cris_ide_ack_intr,
+- ide_default_irq(0));
++ IRQ);
+ ide_register_hw(&hw, &hwif);
++ hwif->irq = IRQ;
+ hwif->mmio = 2;
+ hwif->chipset = ide_etrax100;
+ hwif->tuneproc = &tune_cris_ide;
+@@ -814,13 +878,15 @@
+ hwif->OUTBSYNC = &cris_ide_outbsync;
+ hwif->INB = &cris_ide_inb;
+ hwif->INW = &cris_ide_inw;
+- hwif->ide_dma_host_off = &cris_dma_off;
+- hwif->ide_dma_host_on = &cris_dma_on;
++ hwif->ide_dma_host_off = &cris_dma_host_off;
++ hwif->ide_dma_host_on = &cris_dma_host_on;
+ hwif->ide_dma_off_quietly = &cris_dma_off;
++ hwif->ide_dma_on = &cris_dma_on;
+ hwif->udma_four = 0;
+ hwif->ultra_mask = cris_ultra_mask;
+ hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
+ hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */
++ hwif->rqsize = 256;
+ }
+
+ /* Reset pulse */
+@@ -835,13 +901,25 @@
+ cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
+ }
+
++static int cris_dma_host_off (ide_drive_t *drive)
++{
++ return 0;
++}
++
++static int cris_dma_host_on (ide_drive_t *drive)
++{
++ return 0;
++}
++
+ static int cris_dma_off (ide_drive_t *drive)
+ {
++ drive->using_dma = 0;
+ return 0;
+ }
+
+ static int cris_dma_on (ide_drive_t *drive)
+ {
++ drive->using_dma = 1;
+ return 0;
+ }
+
+@@ -958,30 +1036,28 @@
+ 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 - rw_trf_cnt cannot be more
+- than 65536 words per transfer, so in that case we need to either
++ /* rw_trf_cnt cannot be more than 131072 words per transfer,
++ (- 1 word for UDMA CRC) so in that case we need to either:
+ 1) use a DMA interrupt to re-trigger rw_trf_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.
++ (The ide framework will issue a new request for the remainder)
+ */
+
+- if(ata_tot_size + size > 131072) {
++ if(ata_tot_size + size > 262140) {
+ printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
+ return 1;
+ }
+
+- /* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. Since we
+- don't handle size > 131072 only one split is necessary */
++ /* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. */
+
+- if(size > MAX_DESCR_SIZE) {
++ while (size > MAX_DESCR_SIZE) {
++ /* did we run out of descriptors? */
++ if(count >= MAX_DMA_DESCRS) {
++ printk("%s: too few DMA descriptors\n", drive->name);
++ return 1;
++ }
+ cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, MAX_DESCR_SIZE, 0);
+ count++;
+ ata_tot_size += MAX_DESCR_SIZE;
+@@ -989,6 +1065,11 @@
+ addr += MAX_DESCR_SIZE;
+ }
+
++ /* did we run out of descriptors? */
++ if(count >= MAX_DMA_DESCRS) {
++ printk("%s: too few DMA descriptors\n", drive->name);
++ return 1;
++ }
+ cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, size,i ? 0 : 1);
+ count++;
+ ata_tot_size += size;
+@@ -1050,8 +1131,12 @@
+
+ if (id && (id->capability & 1)) {
+ if (ide_use_dma(drive)) {
+- if (cris_config_drive_for_dma(drive))
+- return hwif->ide_dma_on(drive);
++ if (cris_config_drive_for_dma(drive)) {
++ if (hwif->ide_dma_on)
++ return hwif->ide_dma_on(drive);
++ else
++ return 1;
++ }
+ }
+ }
+
+--- linux-2.6.19.2.orig/drivers/serial/crisv10.c 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/serial/crisv10.c 2007-01-09 10:30:54.000000000 +0100
+@@ -2,7 +2,7 @@
+ *
+ * Serial port driver for the ETRAX 100LX chip
+ *
+- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Axis Communications AB
++ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Axis Communications AB
+ *
+ * Many, many authors. Based once upon a time on serial.c for 16x50.
+ *
+@@ -445,6 +445,7 @@
+
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/dma.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
+ #include <linux/delay.h>
+@@ -454,8 +455,9 @@
+ /* 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 "crisv10.h"
+ #include <asm/fasttimer.h>
++#include <asm/arch/io_interface_mux.h>
+
+ #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+ #ifndef CONFIG_ETRAX_FAST_TIMER
+@@ -586,11 +588,10 @@
+ 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,
++static int rs_write(struct tty_struct * tty,
+ 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);
++static int e100_write_rs485(struct tty_struct * tty, const unsigned char *buf, int count);
+ #endif
+ static int get_lsr_info(struct e100_serial * info, unsigned int *value);
+
+@@ -677,20 +678,39 @@
+ .rx_ctrl = DEF_RX,
+ .tx_ctrl = DEF_TX,
+ .iseteop = 2,
++ .dma_owner = dma_ser0,
++ .io_if = if_serial_0,
+ #ifdef CONFIG_ETRAX_SERIAL_PORT0
+ .enabled = 1,
+ #ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+ .dma_out_enabled = 1,
++ .dma_out_nbr = SER0_TX_DMA_NBR,
++ .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
++ .dma_out_irq_flags = IRQF_DISABLED,
++ .dma_out_irq_description = "serial 0 dma tr",
+ #else
+ .dma_out_enabled = 0,
++ .dma_out_nbr = UINT_MAX,
++ .dma_out_irq_nbr = 0,
++ .dma_out_irq_flags = 0,
++ .dma_out_irq_description = NULL,
+ #endif
+ #ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+ .dma_in_enabled = 1,
++ .dma_in_nbr = SER0_RX_DMA_NBR,
++ .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
++ .dma_in_irq_flags = IRQF_DISABLED,
++ .dma_in_irq_description = "serial 0 dma rec",
+ #else
+- .dma_in_enabled = 0
++ .dma_in_enabled = 0,
++ .dma_in_nbr = UINT_MAX,
++ .dma_in_irq_nbr = 0,
++ .dma_in_irq_flags = 0,
++ .dma_in_irq_description = NULL,
+ #endif
+ #else
+ .enabled = 0,
++ .io_if_description = NULL,
+ .dma_out_enabled = 0,
+ .dma_in_enabled = 0
+ #endif
+@@ -712,20 +732,42 @@
+ .rx_ctrl = DEF_RX,
+ .tx_ctrl = DEF_TX,
+ .iseteop = 3,
++ .dma_owner = dma_ser1,
++ .io_if = if_serial_1,
+ #ifdef CONFIG_ETRAX_SERIAL_PORT1
+ .enabled = 1,
++ .io_if_description = "ser1",
+ #ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+ .dma_out_enabled = 1,
++ .dma_out_nbr = SER1_TX_DMA_NBR,
++ .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
++ .dma_out_irq_flags = IRQF_DISABLED,
++ .dma_out_irq_description = "serial 1 dma tr",
+ #else
+ .dma_out_enabled = 0,
++ .dma_out_nbr = UINT_MAX,
++ .dma_out_irq_nbr = 0,
++ .dma_out_irq_flags = 0,
++ .dma_out_irq_description = NULL,
+ #endif
+ #ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+ .dma_in_enabled = 1,
++ .dma_in_nbr = SER1_RX_DMA_NBR,
++ .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
++ .dma_in_irq_flags = IRQF_DISABLED,
++ .dma_in_irq_description = "serial 1 dma rec",
+ #else
+- .dma_in_enabled = 0
++ .dma_in_enabled = 0,
++ .dma_in_enabled = 0,
++ .dma_in_nbr = UINT_MAX,
++ .dma_in_irq_nbr = 0,
++ .dma_in_irq_flags = 0,
++ .dma_in_irq_description = NULL,
+ #endif
+ #else
+ .enabled = 0,
++ .io_if_description = NULL,
++ .dma_in_irq_nbr = 0,
+ .dma_out_enabled = 0,
+ .dma_in_enabled = 0
+ #endif
+@@ -746,20 +788,40 @@
+ .rx_ctrl = DEF_RX,
+ .tx_ctrl = DEF_TX,
+ .iseteop = 0,
++ .dma_owner = dma_ser2,
++ .io_if = if_serial_2,
+ #ifdef CONFIG_ETRAX_SERIAL_PORT2
+ .enabled = 1,
++ .io_if_description = "ser2",
+ #ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+ .dma_out_enabled = 1,
++ .dma_out_nbr = SER2_TX_DMA_NBR,
++ .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
++ .dma_out_irq_flags = IRQF_DISABLED,
++ .dma_out_irq_description = "serial 2 dma tr",
+ #else
+ .dma_out_enabled = 0,
++ .dma_in_nbr = UINT_MAX,
++ .dma_in_irq_nbr = 0,
++ .dma_in_irq_flags = 0,
++ .dma_in_irq_description = NULL,
+ #endif
+ #ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+ .dma_in_enabled = 1,
++ .dma_in_nbr = SER2_RX_DMA_NBR,
++ .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
++ .dma_in_irq_flags = IRQF_DISABLED,
++ .dma_in_irq_description = "serial 2 dma rec",
+ #else
+- .dma_in_enabled = 0
++ .dma_in_enabled = 0,
++ .dma_in_nbr = UINT_MAX,
++ .dma_in_irq_nbr = 0,
++ .dma_in_irq_flags = 0,
++ .dma_in_irq_description = NULL,
+ #endif
+ #else
+ .enabled = 0,
++ .io_if_description = NULL,
+ .dma_out_enabled = 0,
+ .dma_in_enabled = 0
+ #endif
+@@ -780,20 +842,40 @@
+ .rx_ctrl = DEF_RX,
+ .tx_ctrl = DEF_TX,
+ .iseteop = 1,
++ .dma_owner = dma_ser3,
++ .io_if = if_serial_3,
+ #ifdef CONFIG_ETRAX_SERIAL_PORT3
+ .enabled = 1,
++ .io_if_description = "ser3",
+ #ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+ .dma_out_enabled = 1,
++ .dma_out_nbr = SER3_TX_DMA_NBR,
++ .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
++ .dma_out_irq_flags = IRQF_DISABLED,
++ .dma_out_irq_description = "serial 3 dma tr",
+ #else
+ .dma_out_enabled = 0,
++ .dma_out_nbr = UINT_MAX,
++ .dma_out_irq_nbr = 0,
++ .dma_out_irq_flags = 0,
++ .dma_out_irq_description = NULL,
+ #endif
+ #ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+ .dma_in_enabled = 1,
++ .dma_in_nbr = SER3_RX_DMA_NBR,
++ .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
++ .dma_in_irq_flags = IRQF_DISABLED,
++ .dma_in_irq_description = "serial 3 dma rec",
+ #else
+- .dma_in_enabled = 0
++ .dma_in_enabled = 0,
++ .dma_in_nbr = UINT_MAX,
++ .dma_in_irq_nbr = 0,
++ .dma_in_irq_flags = 0,
++ .dma_in_irq_description = NULL
+ #endif
+ #else
+ .enabled = 0,
++ .io_if_description = NULL,
+ .dma_out_enabled = 0,
+ .dma_in_enabled = 0
+ #endif
+@@ -1414,12 +1496,11 @@
+ {
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ *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);
++ local_irq_restore(flags);
+ }
+
+ #ifdef SERIAL_DEBUG_IO
+@@ -1438,12 +1519,11 @@
+ {
+ #ifndef CONFIG_SVINTO_SIM
+ unsigned long flags;
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ 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);
++ local_irq_restore(flags);
+ #ifdef SERIAL_DEBUG_IO
+ printk("ser%i rts %i\n", info->line, set);
+ #endif
+@@ -1461,12 +1541,11 @@
+ unsigned char mask = e100_modem_pins[info->line].ri_mask;
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ *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);
++ local_irq_restore(flags);
+ }
+ #endif
+ }
+@@ -1479,12 +1558,11 @@
+ unsigned char mask = e100_modem_pins[info->line].cd_mask;
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ *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);
++ local_irq_restore(flags);
+ }
+ #endif
+ }
+@@ -1558,8 +1636,7 @@
+ /* Disable output DMA channel for the serial port in question
+ * ( set to something other then serialX)
+ */
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ 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)) ==
+@@ -1587,7 +1664,7 @@
+ }
+ }
+ *R_GEN_CONFIG = genconfig_shadow;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+
+@@ -1595,8 +1672,7 @@
+ {
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ 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) {
+@@ -1613,7 +1689,7 @@
+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
+ }
+ *R_GEN_CONFIG = genconfig_shadow;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+ static void e100_disable_rxdma_channel(struct e100_serial *info)
+@@ -1623,8 +1699,7 @@
+ /* Disable input DMA channel for the serial port in question
+ * ( set to something other then serialX)
+ */
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ if (info->line == 0) {
+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
+ IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
+@@ -1651,7 +1726,7 @@
+ }
+ }
+ *R_GEN_CONFIG = genconfig_shadow;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+
+@@ -1659,8 +1734,7 @@
+ {
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ /* Enable input DMA channel for the serial port in question */
+ if (info->line == 0) {
+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7);
+@@ -1676,7 +1750,7 @@
+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
+ }
+ *R_GEN_CONFIG = genconfig_shadow;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+ #ifdef SERIAL_HANDLE_EARLY_ERRORS
+@@ -1783,7 +1857,7 @@
+ }
+
+ static int
+-e100_write_rs485(struct tty_struct *tty, int from_user,
++e100_write_rs485(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+ {
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+@@ -1796,7 +1870,7 @@
+ */
+ info->rs485.enabled = 1;
+ /* rs_write now deals with RS485 if enabled */
+- count = rs_write(tty, from_user, buf, count);
++ count = rs_write(tty, buf, count);
+ info->rs485.enabled = old_enabled;
+ return count;
+ }
+@@ -1834,7 +1908,7 @@
+ unsigned long flags;
+ unsigned long xoff;
+
+- save_flags(flags); cli();
++ local_irq_save(flags);
+ DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
+ CIRC_CNT(info->xmit.head,
+ info->xmit.tail,SERIAL_XMIT_SIZE)));
+@@ -1846,7 +1920,7 @@
+ }
+
+ *((unsigned long *)&info->port[REG_XOFF]) = xoff;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+ }
+
+@@ -1858,7 +1932,7 @@
+ unsigned long flags;
+ unsigned long xoff;
+
+- save_flags(flags); cli();
++ local_irq_save(flags);
+ DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
+ CIRC_CNT(info->xmit.head,
+ info->xmit.tail,SERIAL_XMIT_SIZE)));
+@@ -1873,7 +1947,7 @@
+ info->xmit.head != info->xmit.tail && info->xmit.buf)
+ e100_enable_serial_tx_ready_irq(info);
+
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+ }
+
+@@ -2053,8 +2127,7 @@
+ 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(); \
++ local_irq_save(timer_flags); \
+ if (fast_timers[info->line].function == NULL) { \
+ serial_fast_timer_started++; \
+ TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+@@ -2068,7 +2141,7 @@
+ else { \
+ TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+ } \
+- restore_flags(timer_flags); \
++ local_irq_restore(timer_flags); \
+ }
+ #define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
+
+@@ -2097,8 +2170,7 @@
+ {
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+
+ if (!info->first_recv_buffer)
+ info->first_recv_buffer = buffer;
+@@ -2111,7 +2183,7 @@
+ if (info->recv_cnt > info->max_recv_cnt)
+ info->max_recv_cnt = info->recv_cnt;
+
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+ static int
+@@ -2131,11 +2203,7 @@
+ 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++;
++ tty_insert_flip_char(tty, data, flag);
+ info->icount.rx++;
+ }
+
+@@ -2320,7 +2388,6 @@
+ */
+ return;
+ #endif
+- info->tty->flip.count = 0;
+ if (info->uses_dma_in) {
+ /* reset the input dma channel to be sure it works */
+
+@@ -2482,70 +2549,21 @@
+ {
+ 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();
++ local_irq_save(flags);
++ tty = info->tty;
+
+- if (!(tty = info->tty)) {
+- restore_flags(flags);
++ if (!tty) {
++ local_irq_restore(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) {
++ while ((buffer = info->first_recv_buffer)) {
+ 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;
++ tty_insert_flip_string(tty, buffer->buffer, count);
+ info->recv_cnt -= count;
+- DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length));
+
+ if (count == buffer->length) {
+ info->first_recv_buffer = buffer->next;
+@@ -2560,24 +2578,7 @@
+ 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) {
+- 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));
+- }
+-
+- );
++ local_irq_restore(flags);
+
+ /* this includes a check for low-latency */
+ tty_flip_buffer_push(tty);
+@@ -2722,21 +2723,7 @@
+ 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:
+@@ -2789,27 +2776,25 @@
+ DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+ info->errorcode = ERRCODE_INSERT_BREAK;
+ } else {
++ unsigned char data = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
++ char flag = TTY_NORMAL;
+ 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++;
++ struct tty_struct *tty = info->tty;
++ tty_insert_flip_char(tty, 0, flag);
+ 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;
++ flag = TTY_PARITY;
+ } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
+ info->icount.overrun++;
+- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
++ flag = TTY_OVERRUN;
+ } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
+ info->icount.frame++;
+- *tty->flip.flag_buf_ptr = TTY_FRAME;
++ flag = TTY_FRAME;
+ }
++ tty_insert_flip_char(tty, data, flag);
+ info->errorcode = 0;
+ }
+ info->break_detected_cnt = 0;
+@@ -2825,16 +2810,12 @@
+ 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;
++ tty_insert_flip_char(tty, IO_EXTRACT(R_SERIAL0_READ, data_in, data_read), TTY_NORMAL);
+ } 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)) {
+@@ -2972,7 +2953,7 @@
+ 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();
++ local_irq_save(flags);
+ rstat = info->port[REG_STATUS];
+ DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+
+@@ -2981,7 +2962,7 @@
+ info->x_char = 0;
+ /* We must enable since it is disabled in ser_interrupt */
+ e100_enable_serial_tx_ready_irq(info);
+- restore_flags(flags);
++ local_irq_restore(flags);
+ return;
+ }
+ if (info->uses_dma_out) {
+@@ -2989,7 +2970,7 @@
+ 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();
++ local_irq_save(flags);
+ rstat = info->port[REG_STATUS];
+ DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+ e100_disable_serial_tx_ready_irq(info);
+@@ -3002,7 +2983,7 @@
+ nop();
+
+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
+- restore_flags(flags);
++ local_irq_restore(flags);
+ return;
+ }
+ /* Normal char-by-char interrupt */
+@@ -3016,7 +2997,7 @@
+ }
+ 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();
++ local_irq_save(flags);
+ 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++;
+@@ -3040,7 +3021,7 @@
+ /* We must enable since it is disabled in ser_interrupt */
+ e100_enable_serial_tx_ready_irq(info);
+ }
+- restore_flags(flags);
++ local_irq_restore(flags);
+
+ if (CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+@@ -3065,7 +3046,7 @@
+ int handled = 0;
+ static volatile unsigned long reentered_ready_mask = 0;
+
+- save_flags(flags); cli();
++ local_irq_save(flags);
+ irq_mask1_rd = *R_IRQ_MASK1_RD;
+ /* First handle all rx interrupts with ints disabled */
+ info = rs_table;
+@@ -3110,7 +3091,7 @@
+ /* Unblock the serial interrupt */
+ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+- sti();
++ local_irq_enable();
+ ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
+ info = rs_table;
+ for (i = 0; i < NR_PORTS; i++) {
+@@ -3123,11 +3104,11 @@
+ ready_mask <<= 2;
+ }
+ /* handle_ser_tx_interrupt enables tr_ready interrupts */
+- cli();
++ local_irq_disable();
+ /* Handle reentered TX interrupt */
+ irq_mask1_rd = reentered_ready_mask;
+ }
+- cli();
++ local_irq_disable();
+ tx_started = 0;
+ } else {
+ unsigned long ready_mask;
+@@ -3143,7 +3124,7 @@
+ }
+ }
+
+- restore_flags(flags);
++ local_irq_restore(flags);
+ return IRQ_RETVAL(handled);
+ } /* ser_interrupt */
+ #endif
+@@ -3192,13 +3173,12 @@
+ if (!xmit_page)
+ return -ENOMEM;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+
+ /* if it was already initialized, skip this */
+
+ if (info->flags & ASYNC_INITIALIZED) {
+- restore_flags(flags);
++ local_irq_restore(flags);
+ free_page(xmit_page);
+ return 0;
+ }
+@@ -3324,7 +3304,7 @@
+
+ info->flags |= ASYNC_INITIALIZED;
+
+- restore_flags(flags);
++ local_irq_restore(flags);
+ return 0;
+ }
+
+@@ -3375,8 +3355,7 @@
+ info->irq);
+ #endif
+
+- save_flags(flags);
+- cli(); /* Disable interrupts */
++ local_irq_save(flags);
+
+ if (info->xmit.buf) {
+ free_page((unsigned long)info->xmit.buf);
+@@ -3400,7 +3379,7 @@
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+
+@@ -3492,8 +3471,7 @@
+
+ #ifndef CONFIG_SVINTO_SIM
+ /* start with default settings and then fill in changes */
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ /* 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) |
+@@ -3557,7 +3535,7 @@
+ }
+
+ *((unsigned long *)&info->port[REG_XOFF]) = xoff;
+- restore_flags(flags);
++ local_irq_restore(flags);
+ #endif /* !CONFIG_SVINTO_SIM */
+
+ update_char_time(info);
+@@ -3585,13 +3563,12 @@
+
+ /* this protection might not exactly be necessary here */
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ start_transmit(info);
+- restore_flags(flags);
++ local_irq_restore(flags);
+ }
+
+-static int rs_raw_write(struct tty_struct * tty, int from_user,
++static int rs_raw_write(struct tty_struct * tty,
+ const unsigned char *buf, int count)
+ {
+ int c, ret = 0;
+@@ -3614,72 +3591,37 @@
+ SIMCOUT(buf, count);
+ return count;
+ #endif
+- save_flags(flags);
++ local_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
++ /* the local_irq_disable/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) {
+- mutex_lock(&tmp_buf_mutex);
+- 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;
+- }
+- mutex_unlock(&tmp_buf_mutex);
+- } 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);
++ local_irq_disable();
++ 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;
+ }
++ local_irq_restore(flags);
+
+ /* enable transmitter if not running, unless the tty is stopped
+ * this does not need IRQ protection since if tr_running == 0
+@@ -3698,7 +3640,7 @@
+ } /* raw_raw_write() */
+
+ static int
+-rs_write(struct tty_struct * tty, int from_user,
++rs_write(struct tty_struct * tty,
+ const unsigned char *buf, int count)
+ {
+ #if defined(CONFIG_ETRAX_RS485)
+@@ -3725,7 +3667,7 @@
+ }
+ #endif /* CONFIG_ETRAX_RS485 */
+
+- count = rs_raw_write(tty, from_user, buf, count);
++ count = rs_raw_write(tty, buf, count);
+
+ #if defined(CONFIG_ETRAX_RS485)
+ if (info->rs485.enabled)
+@@ -3793,10 +3735,9 @@
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ info->xmit.head = info->xmit.tail = 0;
+- restore_flags(flags);
++ local_irq_restore(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+
+@@ -3818,7 +3759,7 @@
+ {
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+- save_flags(flags); cli();
++ local_irq_save(flags);
+ if (info->uses_dma_out) {
+ /* Put the DMA on hold and disable the channel */
+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
+@@ -3835,7 +3776,7 @@
+ 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);
++ local_irq_restore(flags);
+ }
+
+ /*
+@@ -4085,61 +4026,6 @@
+ 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)
+ {
+@@ -4149,8 +4035,7 @@
+ if (!info->port)
+ return;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ 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) */
+@@ -4158,7 +4043,42 @@
+ info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
+ }
+ info->port[REG_TR_CTRL] = info->tx_ctrl;
+- restore_flags(flags);
++ local_irq_restore(flags);
++}
++
++static int
++rs_tiocmset(struct tty_struct *tty, struct file * file, unsigned int set, unsigned int clear)
++{
++ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
++
++ if (clear & TIOCM_RTS) {
++ e100_rts(info, 0);
++ }
++ if (clear & TIOCM_DTR) {
++ e100_dtr(info, 0);
++ }
++ /* Handle FEMALE behaviour */
++ if (clear & TIOCM_RI) {
++ e100_ri_out(info, 0);
++ }
++ if (clear & TIOCM_CD) {
++ e100_cd_out(info, 0);
++ }
++
++ if (set & TIOCM_RTS) {
++ e100_rts(info, 1);
++ }
++ if (set & TIOCM_DTR) {
++ e100_dtr(info, 1);
++ }
++ /* Handle FEMALE behaviour */
++ if (set & TIOCM_RI) {
++ e100_ri_out(info, 1);
++ }
++ if (set & TIOCM_CD) {
++ e100_cd_out(info, 1);
++ }
++ return 0;
+ }
+
+ static int
+@@ -4177,10 +4097,6 @@
+ 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);
+@@ -4212,7 +4128,7 @@
+ if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr)))
+ return -EFAULT;
+
+- return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size);
++ return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size);
+ }
+ #endif
+
+@@ -4242,46 +4158,6 @@
+
+ }
+
+-/* 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()
+@@ -4303,11 +4179,10 @@
+
+ /* interrupts are disabled for this entire function */
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+
+ if (tty_hung_up_p(filp)) {
+- restore_flags(flags);
++ local_irq_restore(flags);
+ return;
+ }
+
+@@ -4334,7 +4209,7 @@
+ info->count = 0;
+ }
+ if (info->count) {
+- restore_flags(flags);
++ local_irq_restore(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+@@ -4388,7 +4263,7 @@
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+- restore_flags(flags);
++ local_irq_restore(flags);
+
+ /* port closed */
+
+@@ -4410,6 +4285,28 @@
+ #endif
+ }
+ #endif
++
++ /*
++ * Release any allocated DMA irq's.
++ */
++ if (info->dma_in_enabled) {
++ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
++ free_irq(info->dma_in_irq_nbr,
++ info);
++ info->uses_dma_in = 0;
++#ifdef SERIAL_DEBUG_OPEN
++ printk("DMA irq '%s' freed\n", info->dma_in_irq_description);
++#endif
++ }
++ if (info->dma_out_enabled) {
++ free_irq(info->dma_out_irq_nbr,
++ info);
++ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
++ info->uses_dma_out = 0;
++#ifdef SERIAL_DEBUG_OPEN
++ printk("DMA irq '%s' freed\n", info->dma_out_irq_description);
++#endif
++ }
+ }
+
+ /*
+@@ -4485,7 +4382,7 @@
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+- interruptible_sleep_on(&info->close_wait);
++ wait_event_interruptible(info->close_wait, 0);
+ #ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+@@ -4523,21 +4420,19 @@
+ printk("block_til_ready before block: ttyS%d, count = %d\n",
+ info->line, info->count);
+ #endif
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ if (!tty_hung_up_p(filp)) {
+ extra_count++;
+ info->count--;
+ }
+- restore_flags(flags);
++ local_irq_restore(flags);
+ info->blocked_open++;
+ while (1) {
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+ /* assert RTS and DTR */
+ e100_rts(info, 1);
+ e100_dtr(info, 1);
+- restore_flags(flags);
++ local_irq_restore(flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+@@ -4589,9 +4484,9 @@
+ struct e100_serial *info;
+ int retval, line;
+ unsigned long page;
++ int allocated_resources = 0;
+
+ /* find which port we want to open */
+-
+ line = tty->index;
+
+ if (line < 0 || line >= NR_PORTS)
+@@ -4632,7 +4527,7 @@
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+- interruptible_sleep_on(&info->close_wait);
++ wait_event_interruptible(info->close_wait, 0);
+ #ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+@@ -4642,12 +4537,79 @@
+ }
+
+ /*
++ * If DMA is enabled try to allocate the irq's.
++ */
++ if (info->count == 1) {
++ allocated_resources = 1;
++ if (info->dma_in_enabled) {
++ if (request_irq(info->dma_in_irq_nbr,
++ rec_interrupt,
++ info->dma_in_irq_flags,
++ info->dma_in_irq_description,
++ info)) {
++ printk(KERN_WARNING "DMA irq '%s' busy; falling back to non-DMA mode\n", info->dma_in_irq_description);
++ /* Make sure we never try to use DMA in for the port again. */
++ info->dma_in_enabled = 0;
++ } else if (cris_request_dma(info->dma_in_nbr,
++ info->dma_in_irq_description,
++ DMA_VERBOSE_ON_ERROR,
++ info->dma_owner)) {
++ free_irq(info->dma_in_irq_nbr, info);
++ printk(KERN_WARNING "DMA '%s' busy; falling back to non-DMA mode\n", info->dma_in_irq_description);
++ /* Make sure we never try to use DMA in for the port again. */
++ info->dma_in_enabled = 0;
++ }
++#ifdef SERIAL_DEBUG_OPEN
++ else printk("DMA irq '%s' allocated\n", info->dma_in_irq_description);
++#endif
++ }
++ if (info->dma_out_enabled) {
++ if (request_irq(info->dma_out_irq_nbr,
++ tr_interrupt,
++ info->dma_out_irq_flags,
++ info->dma_out_irq_description,
++ info)) {
++ printk(KERN_WARNING "DMA irq '%s' busy; falling back to non-DMA mode\n", info->dma_out_irq_description);
++ /* Make sure we never try to use DMA out for the port again. */
++ info->dma_out_enabled = 0;
++ } else if (cris_request_dma(info->dma_out_nbr,
++ info->dma_out_irq_description,
++ DMA_VERBOSE_ON_ERROR,
++ info->dma_owner)) {
++ free_irq(info->dma_out_irq_nbr, info);
++ printk(KERN_WARNING "DMA '%s' busy; falling back to non-DMA mode\n", info->dma_out_irq_description);
++ /* Make sure we never try to use DMA in for the port again. */
++ info->dma_out_enabled = 0;
++ }
++#ifdef SERIAL_DEBUG_OPEN
++ else printk("DMA irq '%s' allocated\n", info->dma_out_irq_description);
++#endif
++ }
++ }
++
++ /*
+ * Start up the serial port
+ */
+
+ retval = startup(info);
+- if (retval)
+- return retval;
++ if (retval) {
++ if (allocated_resources) {
++ if (info->dma_out_enabled) {
++ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
++ free_irq(info->dma_out_irq_nbr,
++ info);
++ }
++ if (info->dma_in_enabled) {
++ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
++ free_irq(info->dma_in_irq_nbr,
++ info);
++ }
++ }
++ /* FIXME Decrease count info->count here too? */
++ return retval;
++
++ }
++
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+@@ -4655,6 +4617,19 @@
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+ #endif
++ if (allocated_resources) {
++ if (info->dma_out_enabled) {
++ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
++ free_irq(info->dma_out_irq_nbr,
++ info);
++ }
++ if (info->dma_in_enabled) {
++ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
++ free_irq(info->dma_in_irq_nbr,
++ info);
++ }
++ }
++
+ return retval;
+ }
+
+@@ -4844,6 +4819,7 @@
+ .send_xchar = rs_send_xchar,
+ .wait_until_sent = rs_wait_until_sent,
+ .read_proc = rs_read_proc,
++ .tiocmset = rs_tiocmset
+ };
+
+ static int __init
+@@ -4863,7 +4839,22 @@
+ #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);
++ mod_timer(&flush_timer, jiffies + 5);
++#endif
++
++#if defined(CONFIG_ETRAX_RS485)
++#if defined(CONFIG_ETRAX_RS485_ON_PA)
++ if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, rs485_pa_bit)) {
++ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate RS485 pin\n");
++ return -EBUSY;
++ }
++#endif
++#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
++ if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, rs485_port_g_bit)) {
++ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate RS485 pin\n");
++ return -EBUSY;
++ }
++#endif
+ #endif
+
+ /* Initialize the tty_driver structure */
+@@ -4888,6 +4879,14 @@
+ /* do some initializing for the separate ports */
+
+ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
++ if (info->enabled) {
++ if (cris_request_io_interface(info->io_if, info->io_if_description)) {
++ printk(KERN_CRIT "ETRAX100LX async serial: Could not allocate IO pins for %s, port %d\n",
++ info->io_if_description,
++ i);
++ info->enabled = 0;
++ }
++ }
+ info->uses_dma_in = 0;
+ info->uses_dma_out = 0;
+ info->line = i;
+@@ -4939,64 +4938,16 @@
+ #endif
+
+ #ifndef CONFIG_SVINTO_SIM
++#ifndef CONFIG_ETRAX_KGDB
+ /* 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, IRQF_SHARED | IRQF_DISABLED, "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, IRQF_DISABLED, "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, IRQF_DISABLED, "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, IRQF_DISABLED, "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, IRQF_DISABLED, "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, IRQF_SHARED | IRQF_DISABLED, "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, IRQF_SHARED | IRQF_DISABLED, "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, IRQF_SHARED | IRQF_DISABLED, "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, IRQF_SHARED | IRQF_DISABLED, "serial 3 dma rec", NULL))
+- panic("irq21");
+-#endif
+-#endif
++ if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
++ panic("%s: Failed to request irq8", __FUNCTION__);
+
+-#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+- if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, IRQF_SHARED | IRQF_DISABLED,
+- "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;
+ }
+
+--- linux-2.6.19.2.orig/drivers/serial/crisv10.h 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/serial/crisv10.h 2006-10-13 14:44:38.000000000 +0200
+@@ -9,6 +9,8 @@
+
+ #include <linux/circ_buf.h>
+ #include <asm/termios.h>
++#include <asm/dma.h>
++#include <asm/arch/io_interface_mux.h>
+
+ /* Software state per channel */
+
+@@ -61,6 +63,19 @@
+ u8 dma_in_enabled:1; /* Set to 1 if DMA should be used */
+
+ /* end of fields defined in rs_table[] in .c-file */
++ int dma_owner;
++ unsigned int dma_in_nbr;
++ unsigned int dma_out_nbr;
++ unsigned int dma_in_irq_nbr;
++ unsigned int dma_out_irq_nbr;
++ unsigned long dma_in_irq_flags;
++ unsigned long dma_out_irq_flags;
++ char *dma_in_irq_description;
++ char *dma_out_irq_description;
++
++ enum cris_io_interface io_if;
++ char *io_if_description;
++
+ 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 */
+--- linux-2.6.19.2.orig/drivers/serial/crisv32.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/serial/crisv32.c 2007-01-05 09:59:53.000000000 +0100
+@@ -0,0 +1,2333 @@
++/* $Id: crisv32.c,v 1.78 2007/01/05 08:59:53 starvik Exp $
++ *
++ * Serial port driver for the ETRAX FS chip
++ *
++ * Copyright (C) 1998-2006 Axis Communications AB
++ *
++ * Many, many authors. Based once upon a time on serial.c for 16x50.
++ *
++ * Johan Adolfsson - port to ETRAX FS
++ * Mikael Starvik - port to serial_core framework
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/serial_core.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <asm/arch/dma.h>
++#include <asm/arch/system.h>
++#include <asm/arch/pinmux.h>
++#include <asm/arch/hwregs/dma.h>
++#include <asm/arch/hwregs/reg_rdwr.h>
++#include <asm/arch/hwregs/ser_defs.h>
++#include <asm/arch/hwregs/dma_defs.h>
++#include <asm/arch/hwregs/gio_defs.h>
++#include <asm/arch/hwregs/intr_vect_defs.h>
++#include <asm/arch/hwregs/reg_map.h>
++
++#define UART_NR 5 /* 4 ports + dummy port */
++#define SERIAL_RECV_DESCRIPTORS 8
++
++/* We only buffer 255 characters here, no need for more tx descriptors. */
++#define SERIAL_TX_DESCRIPTORS 4
++
++/* Kept for experimental purposes. */
++#define ETRAX_SER_FIFO_SIZE 1
++#define SERIAL_DESCR_BUF_SIZE 256
++#define regi_NULL 0
++#define DMA_WAIT_UNTIL_RESET(inst) \
++ do { \
++ reg_dma_rw_stat r; \
++ do { \
++ r = REG_RD(dma, (inst), rw_stat); \
++ } while (r.mode != regk_dma_rst); \
++ } while (0)
++
++/* Macro to set up control lines for a port. */
++#define SETUP_PINS(port) \
++ if (serial_cris_ports[port].used) { \
++ if (strcmp(CONFIG_ETRAX_SER##port##_DTR_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].dtr_pin, \
++ CONFIG_ETRAX_SER##port##_DTR_BIT); \
++ else \
++ serial_cris_ports[port].dtr_pin = dummy_pin; \
++ if (strcmp(CONFIG_ETRAX_SER##port##_DSR_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].dsr_pin, \
++ CONFIG_ETRAX_SER##port##_DSR_BIT); \
++ else \
++ serial_cris_ports[port].dsr_pin = dummy_pin; \
++ if (strcmp(CONFIG_ETRAX_SER##port##_RI_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].ri_pin, \
++ CONFIG_ETRAX_SER##port##_RI_BIT); \
++ else \
++ serial_cris_ports[port].ri_pin = dummy_pin; \
++ if (strcmp(CONFIG_ETRAX_SER##port##_CD_BIT, "")) \
++ crisv32_io_get_name(&serial_cris_ports[port].cd_pin, \
++ CONFIG_ETRAX_SER##port##_CD_BIT); \
++ else \
++ serial_cris_ports[port].cd_pin = dummy_pin; \
++ }
++
++/* Set a serial port register if anything has changed. */
++#define MODIFY_REG(instance, reg, var) \
++ if (REG_RD_INT(ser, instance, reg) \
++ != REG_TYPE_CONV(int, reg_ser_##reg, var)) \
++ REG_WR(ser, instance, reg, var);
++
++/*
++ * Regarding RS485 operation in crisv32 serial driver.
++ * ---------------------------------------------------
++ * RS485 can be run in two modes, full duplex using four wires (485FD) and
++ * half duplex using two wires (485HD). The default mode of each serial port
++ * is configured in the kernel configuration. The available modes are:
++ * RS-232, RS-485 half duplex, and RS-485 full duplex.
++ *
++ * In the 485HD mode the direction of the data bus must be able to switch.
++ * The direction of the transceiver is controlled by the RTS signal. Hence
++ * the auto_rts function in the ETRAX FS chip is enabled in this mode, which
++ * automatically toggle RTS when transmitting. The initial direction of the
++ * port is receiving.
++ *
++ * In the 485FD mode two transceivers will be used, one in each direction.
++ * Usually the hardware can handle both 485HD and 485FD, which implies that
++ * one of the transceivers can change direction. Consequently that transceiver
++ * must be tied to operate in the opposite direction of the other one, setting
++ * and keeping RTS to a fixed value do this.
++ *
++ * There are two special "ioctl" that can configure the ports. These two are
++ * left for backward compatible with older applications. The effects of using
++ * them are described below:
++ * The TIOCSERSETRS485:
++ * This ioctl sets a serial port in 232 mode to 485HD mode or vise versa. The
++ * state of the port is kept when closing the port. Note that this ioctl has no
++ * effect on a serial port in the 485FD mode.
++ * The TIOCSERWRRS485:
++ * This ioctl set a serial port in 232 mode to 485HD mode and writes the data
++ * "included" in the ioctl to the port. The port will then stay in 485HD mode.
++ * Using this ioctl on a serial port in the 485HD mode will transmit the data
++ * without changing the mode. Using this ioctl on a serial port in 485FD mode
++ * will not change the mode and simply send the data using the 485FD mode.
++ */
++
++#define TYPE_232 0
++#define TYPE_485HD 1
++#define TYPE_485FD 2
++
++struct etrax_recv_buffer {
++ struct etrax_recv_buffer *next;
++ unsigned short length;
++ unsigned char error;
++ unsigned char pad;
++
++ unsigned char buffer[0];
++};
++
++struct uart_cris_port {
++ struct uart_port port;
++
++ int initialized;
++ int used;
++ int irq;
++
++ /* Used to check if port enabled as well by testing for zero. */
++ reg_scope_instances regi_ser;
++ reg_scope_instances regi_dmain;
++ reg_scope_instances regi_dmaout;
++
++ struct crisv32_iopin dtr_pin;
++ struct crisv32_iopin dsr_pin;
++ struct crisv32_iopin ri_pin;
++ struct crisv32_iopin cd_pin;
++
++ struct dma_descr_context tr_context_descr
++ __attribute__ ((__aligned__(32)));
++ struct dma_descr_data tr_descr[SERIAL_TX_DESCRIPTORS]
++ __attribute__ ((__aligned__(32)));
++ struct dma_descr_context rec_context_descr
++ __attribute__ ((__aligned__(32)));
++ struct dma_descr_data rec_descr[SERIAL_RECV_DESCRIPTORS]
++ __attribute__ ((__aligned__(32)));
++
++ /* This is the first one in the list the HW is working on now. */
++ struct dma_descr_data* first_tx_descr;
++
++ /* This is the last one in the list the HW is working on now. */
++ struct dma_descr_data* last_tx_descr;
++
++ /* This is how many characters the HW is working on now. */
++ unsigned int tx_pending_chars;
++
++ int tx_started;
++ unsigned int cur_rec_descr;
++ struct etrax_recv_buffer *first_recv_buffer;
++ struct etrax_recv_buffer *last_recv_buffer;
++
++ unsigned int recv_cnt;
++ unsigned int max_recv_cnt;
++
++ /* The time for 1 char, in usecs. */
++ unsigned long char_time_usec;
++
++ /* Last tx usec in the jiffies. */
++ unsigned long last_tx_active_usec;
++
++ /* Last tx time in jiffies. */
++ unsigned long last_tx_active;
++
++ /* Last rx usec in the jiffies. */
++ unsigned long last_rx_active_usec;
++
++ /* Last rx time in jiffies. */
++ unsigned long last_rx_active;
++
++#ifdef CONFIG_ETRAX_RS485
++ /* RS-485 support, duh. */
++ struct rs485_control rs485;
++#endif
++ int port_type;
++};
++
++extern struct uart_driver serial_cris_driver;
++static struct uart_port *console_port;
++static int console_baud = 115200;
++static struct uart_cris_port serial_cris_ports[UART_NR] = {
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT0
++ .used = 1,
++ .irq = SER0_INTR_VECT,
++ .regi_ser = regi_ser0,
++ /*
++ * We initialize the dma stuff like this to get a compiler error
++ * if a CONFIG is missing
++ */
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
++ regi_dma7,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
++ regi_dma6,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT0_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++}, /* ttyS0 */
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT1
++ .used = 1,
++ .irq = SER1_INTR_VECT,
++ .regi_ser = regi_ser1,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
++ regi_dma5,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
++ regi_dma4,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT1_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++}, /* ttyS1 */
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT2
++ .used = 1,
++ .irq = SER2_INTR_VECT,
++ .regi_ser = regi_ser2,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
++ regi_dma3,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
++ regi_dma2,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT2_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++}, /* ttyS2 */
++{
++#ifdef CONFIG_ETRAX_SERIAL_PORT3
++ .used = 1,
++ .irq = SER3_INTR_VECT,
++ .regi_ser = regi_ser3,
++ .regi_dmain =
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
++ regi_dma9,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN
++ regi_NULL,
++# endif
++
++ .regi_dmaout =
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
++ regi_dma8,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT
++ regi_NULL,
++# endif
++
++# ifdef CONFIG_ETRAX_RS485
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_TYPE_485HD
++ .port_type = TYPE_485HD,
++# endif
++# ifdef CONFIG_ETRAX_SERIAL_PORT3_TYPE_485FD
++ .port_type = TYPE_485FD,
++# endif
++# endif
++#else
++ .regi_ser = regi_NULL,
++ .regi_dmain = regi_NULL,
++ .regi_dmaout = regi_NULL,
++#endif
++}, /* ttyS3 */
++{
++#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
++ .used = 1,
++#endif
++ .regi_ser = regi_NULL
++} /* Dummy console port */
++
++};
++
++/* Dummy pin used for unused CD, DSR, DTR and RI signals. */
++static unsigned long io_dummy;
++static struct crisv32_ioport dummy_port =
++{
++ &io_dummy,
++ &io_dummy,
++ &io_dummy,
++ 18
++};
++static struct crisv32_iopin dummy_pin =
++{
++ &dummy_port,
++ 0
++};
++
++static int selected_console =
++#if defined(CONFIG_ETRAX_DEBUG_PORT0)
++0;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
++1;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
++2;
++#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
++3;
++#else /* CONFIG_ETRAX_DEBUG_PORT_NULL */
++4;
++#endif
++
++extern void reset_watchdog(void);
++
++/*
++ * Interrupts are disabled on entering
++ */
++static void
++cris_console_write(struct console *co, const char *s, unsigned int count)
++{
++ struct uart_cris_port *up;
++ int i;
++ reg_ser_r_stat_din stat;
++ reg_ser_rw_tr_dma_en tr_dma_en, old;
++
++ up = &serial_cris_ports[selected_console];
++
++ /*
++ * This function isn't covered by the struct uart_ops, so we
++ * have to check manually that the port really is there,
++ * configured and live.
++ */
++ if (!up->regi_ser)
++ return;
++
++ /* Switch to manual mode. */
++ tr_dma_en = old = REG_RD (ser, up->regi_ser, rw_tr_dma_en);
++ if (tr_dma_en.en == regk_ser_yes) {
++ tr_dma_en.en = regk_ser_no;
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
++ }
++
++ /* Send data. */
++ for (i = 0; i < count; i++) {
++ /* LF -> CRLF */
++ if (s[i] == '\n') {
++ do {
++ stat = REG_RD (ser, up->regi_ser, r_stat_din);
++ } while (!stat.tr_rdy);
++ REG_WR_INT (ser, up->regi_ser, rw_dout, '\r');
++ }
++ /* Wait until transmitter is ready and send. */
++ do {
++ stat = REG_RD (ser, up->regi_ser, r_stat_din);
++ } while (!stat.tr_rdy);
++ REG_WR_INT (ser, up->regi_ser, rw_dout, s[i]);
++
++ /* Feed watchdog, because this may take looong time. */
++ reset_watchdog();
++ }
++
++ /* Restore mode. */
++ if (tr_dma_en.en != old.en)
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, old);
++}
++
++static void cris_serial_port_init(struct uart_port *port, int line);
++static int __init
++cris_console_setup(struct console *co, char *options)
++{
++ struct uart_port *port;
++ int baud = 115200;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ if (co->index >= UART_NR)
++ co->index = 0;
++ if (options)
++ selected_console = co->index;
++ port = &serial_cris_ports[selected_console].port;
++ console_port = port;
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++ console_baud = baud;
++ cris_serial_port_init(port, selected_console);
++ co->index = port->line;
++ uart_set_options(port, co, baud, parity, bits, flow);
++
++ return 0;
++}
++
++static struct tty_driver*
++cris_console_device(struct console* co, int *index)
++{
++ struct uart_driver *p = co->data;
++ *index = selected_console;
++ return p->tty_driver;
++}
++
++static struct console cris_console = {
++ .name = "ttyS",
++ .write = cris_console_write,
++ .device = cris_console_device,
++ .setup = cris_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &serial_cris_driver,
++};
++
++#define SERIAL_CRIS_CONSOLE &cris_console
++
++struct uart_driver serial_cris_driver = {
++ .owner = THIS_MODULE,
++ .driver_name = "serial",
++ .dev_name = "ttyS",
++ .major = TTY_MAJOR,
++ .minor = 64,
++ .nr = UART_NR,
++ .cons = SERIAL_CRIS_CONSOLE,
++};
++
++static int inline crisv32_serial_get_rts(struct uart_cris_port *up)
++{
++ reg_scope_instances regi_ser = up->regi_ser;
++ /*
++ * Return what the user has controlled rts to or
++ * what the pin is? (if auto_rts is used it differs during tx)
++ */
++ reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
++ return !(rstat.rts_n == regk_ser_active);
++}
++
++/*
++ * A set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
++ * 0=0V , 1=3.3V
++ */
++static inline void crisv32_serial_set_rts(struct uart_cris_port *up, int set)
++{
++ reg_scope_instances regi_ser = up->regi_ser;
++
++#ifdef CONFIG_ETRAX_RS485
++ /* Never toggle RTS if port is in 485 mode. If port is in 485FD mode we
++ * do not want to send with the reciever and for 485HD mode auto_rts
++ * take care of the RTS for us.
++ */
++ if (!up->rs485.enabled) {
++#else
++ {
++#endif
++ unsigned long flags;
++ reg_ser_rw_rec_ctrl rec_ctrl;
++
++ local_irq_save(flags);
++ rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
++ if (set)
++ rec_ctrl.rts_n = regk_ser_active;
++ else
++ rec_ctrl.rts_n = regk_ser_inactive;
++ REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
++ local_irq_restore(flags);
++ }
++}
++
++/* Input */
++static int inline crisv32_serial_get_cts(struct uart_cris_port *up)
++{
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
++ return (rstat.cts_n == regk_ser_active);
++}
++
++/*
++ * Send a single character for XON/XOFF purposes. We do it in this separate
++ * function instead of the alternative support port.x_char, in the ...start_tx
++ * function, so we don't mix up this case with possibly enabling transmission
++ * of queued-up data (in case that's disabled after *receiving* an XOFF or
++ * negative CTS). This function is used for both DMA and non-DMA case; see HW
++ * docs specifically blessing sending characters manually when DMA for
++ * transmission is enabled and running. We may be asked to transmit despite
++ * the transmitter being disabled by a ..._stop_tx call so we need to enable
++ * it temporarily but restore the state afterwards.
++ *
++ * Beware: I'm not sure how the RS-485 stuff is supposed to work. Using
++ * XON/XOFF seems problematic if there are several controllers, but if it's
++ * actually RS-422 (multi-drop; one sender and multiple receivers), it might
++ * Just Work, so don't bail out just because it looks a little suspicious.
++ */
++
++void serial_cris_send_xchar(struct uart_port *port, char ch)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ reg_ser_rw_dout dout = { .data = ch };
++ reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
++ reg_ser_r_stat_din rstat;
++ reg_ser_rw_tr_ctrl prev_tr_ctrl, tr_ctrl;
++ reg_scope_instances regi_ser = up->regi_ser;
++ unsigned long flags;
++
++ /*
++ * Wait for tr_rdy in case a character is already being output. Make
++ * sure we have integrity between the register reads and the writes
++ * below, but don't busy-wait with interrupts off and the port lock
++ * taken.
++ */
++ spin_lock_irqsave(&port->lock, flags);
++ do {
++ spin_unlock_irqrestore(&port->lock, flags);
++ spin_lock_irqsave(&port->lock, flags);
++ prev_tr_ctrl = tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
++ rstat = REG_RD(ser, regi_ser, r_stat_din);
++ } while (!rstat.tr_rdy);
++
++ /*
++ * Ack an interrupt if one was just issued for the previous character
++ * that was output. This is required for non-DMA as the interrupt is
++ * used as the only indicator that the transmitter is ready and it
++ * isn't while this x_char is being transmitted.
++ */
++ REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
++
++ /* Enable the transmitter in case it was disabled. */
++ tr_ctrl.stop = 0;
++ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
++
++ /*
++ * Finally, send the blessed character; nothing should stop it now,
++ * except for an xoff-detected state, which we'll handle below.
++ */
++ REG_WR(ser, regi_ser, rw_dout, dout);
++ up->port.icount.tx++;
++
++ /* There might be an xoff state to clear. */
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++
++ /*
++ * Clear any xoff state that *may* have been there to
++ * inhibit transmission of the character.
++ */
++ if (rstat.xoff_detect) {
++ reg_ser_rw_xoff_clr xoff_clr = { .clr = 1 };
++ REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
++ reg_ser_rw_tr_dma_en tr_dma_en
++ = REG_RD(ser, regi_ser, rw_tr_dma_en);
++
++ /*
++ * If we had an xoff state but cleared it, instead sneak in a
++ * disabled state for the transmitter, after the character we
++ * sent. Thus we keep the port disabled, just as if the xoff
++ * state was still in effect (or actually, as if stop_tx had
++ * been called, as we stop DMA too).
++ */
++ prev_tr_ctrl.stop = 1;
++
++ tr_dma_en.en = 0;
++ REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
++ }
++
++ /* Restore "previous" enabled/disabled state of the transmitter. */
++ REG_WR(ser, regi_ser, rw_tr_ctrl, prev_tr_ctrl);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void transmit_chars_dma(struct uart_cris_port *up);
++
++/*
++ * Do not spin_lock_irqsave or disable interrupts by other means here; it's
++ * already done by the caller.
++ */
++
++static void serial_cris_start_tx(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_rw_tr_ctrl tr_ctrl;
++
++ tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
++ tr_ctrl.stop = regk_ser_no;
++ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
++ if (!up->regi_dmaout) {
++ reg_ser_rw_intr_mask intr_mask =
++ REG_RD(ser, regi_ser, rw_intr_mask);
++ intr_mask.tr_rdy = regk_ser_yes;
++ REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
++ } else {
++ /*
++ * We're called possibly to re-enable transmission after it
++ * has been disabled. If so, DMA needs to be re-enabled.
++ */
++ reg_ser_rw_tr_dma_en tr_dma_en = { .en = 1 };
++ REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
++ transmit_chars_dma(up);
++ }
++}
++
++/*
++ * This function handles both the DMA and non-DMA case by ordering the
++ * transmitter to stop of after the current character. We don't need to wait
++ * for any such character to be completely transmitted; we do that where it
++ * matters, like in serial_cris_set_termios. Don't busy-wait here; see
++ * Documentation/serial/driver: this function is called within
++ * spin_lock_irq{,save} and thus separate ones would be disastrous (when SMP).
++ * There's no documented need to set the txd pin to any particular value;
++ * break setting is controlled solely by serial_cris_break_ctl.
++ */
++
++static void serial_cris_stop_tx(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_rw_tr_ctrl tr_ctrl;
++ reg_ser_rw_intr_mask intr_mask;
++ reg_ser_rw_tr_dma_en tr_dma_en = {0};
++ reg_ser_rw_xoff_clr xoff_clr = {0};
++
++ /*
++ * For the non-DMA case, we'd get a tr_rdy interrupt that we're not
++ * interested in as we're not transmitting any characters. For the
++ * DMA case, that interrupt is already turned off, but no reason to
++ * waste code on conditionals here.
++ */
++ intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
++ intr_mask.tr_rdy = regk_ser_no;
++ REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
++
++ tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
++ tr_ctrl.stop = 1;
++ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
++
++ /*
++ * Always clear possible hardware xoff-detected state here, no need to
++ * unnecessary consider mctrl settings and when they change. We clear
++ * it here rather than in start_tx: both functions are called as the
++ * effect of XOFF processing, but start_tx is also called when upper
++ * levels tell the driver that there are more characters to send, so
++ * avoid adding code there.
++ */
++ xoff_clr.clr = 1;
++ REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
++
++ /*
++ * Disable transmitter DMA, so that if we're in XON/XOFF, we can send
++ * those single characters without also giving go-ahead for queued up
++ * DMA data.
++ */
++ tr_dma_en.en = 0;
++ REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
++}
++
++static void serial_cris_stop_rx(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_rw_rec_ctrl rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
++
++ rec_ctrl.en = regk_ser_no;
++ REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
++}
++
++static void serial_cris_enable_ms(struct uart_port *port)
++{
++}
++
++static void check_modem_status(struct uart_cris_port *up)
++{
++}
++
++static unsigned int serial_cris_tx_empty(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ unsigned long flags;
++ unsigned int ret;
++ reg_ser_r_stat_din rstat = {0};
++
++ spin_lock_irqsave(&up->port.lock, flags);
++ if (up->regi_dmaout) {
++ /*
++ * For DMA, before looking at r_stat, we need to check that we
++ * either haven't actually started or that end-of-list is
++ * reached, else a tr_empty indication is just an internal
++ * state. The caller qualifies, if needed, that the
++ * port->info.xmit buffer is empty, so we don't need to
++ * check that.
++ */
++ reg_dma_rw_stat status = REG_RD(dma, up->regi_dmaout, rw_stat);
++
++ if (!up->tx_started) {
++ ret = 1;
++ goto done;
++ }
++
++ if (status.list_state != regk_dma_data_at_eol) {
++ ret = 0;
++ goto done;
++ }
++ }
++
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++ ret = rstat.tr_empty ? TIOCSER_TEMT : 0;
++
++ done:
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ return ret;
++}
++static unsigned int serial_cris_get_mctrl(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ unsigned int ret;
++
++ ret = 0;
++ if (crisv32_serial_get_rts(up))
++ ret |= TIOCM_RTS;
++ if (crisv32_io_rd(&up->dtr_pin))
++ ret |= TIOCM_DTR;
++ if (crisv32_io_rd(&up->cd_pin))
++ ret |= TIOCM_CD;
++ if (crisv32_io_rd(&up->ri_pin))
++ ret |= TIOCM_RI;
++ if (!crisv32_io_rd(&up->dsr_pin))
++ ret |= TIOCM_DSR;
++ if (crisv32_serial_get_cts(up))
++ ret |= TIOCM_CTS;
++ return ret;
++}
++
++static void serial_cris_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++
++ crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0);
++ crisv32_io_set(&up->dtr_pin, mctrl & TIOCM_DTR ? 1 : 0);
++ crisv32_io_set(&up->ri_pin, mctrl & TIOCM_RNG ? 1 : 0);
++ crisv32_io_set(&up->cd_pin, mctrl & TIOCM_CD ? 1 : 0);
++}
++
++static void serial_cris_break_ctl(struct uart_port *port, int break_state)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ unsigned long flags;
++ reg_ser_rw_tr_ctrl tr_ctrl;
++ reg_ser_rw_tr_dma_en tr_dma_en;
++ reg_ser_rw_intr_mask intr_mask;
++
++ spin_lock_irqsave(&up->port.lock, flags);
++ tr_ctrl = REG_RD(ser, up->regi_ser, rw_tr_ctrl);
++ tr_dma_en = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
++ intr_mask = REG_RD(ser, up->regi_ser, rw_intr_mask);
++
++ if (break_state != 0) { /* Send break */
++ /*
++ * We need to disable DMA (if used) or tr_rdy interrupts if no
++ * DMA. No need to make this conditional on use of DMA;
++ * disabling will be a no-op for the other mode.
++ */
++ intr_mask.tr_rdy = regk_ser_no;
++ tr_dma_en.en = 0;
++
++ /*
++ * Stop transmission and set the txd pin to 0 after the
++ * current character. The txd setting will take effect after
++ * any current transmission has completed.
++ */
++ tr_ctrl.stop = 1;
++ tr_ctrl.txd = 0;
++ } else {
++ /* Re-enable either transmit DMA or the serial interrupt. */
++ if (up->regi_dmaout)
++ tr_dma_en.en = 1;
++ else
++ intr_mask.tr_rdy = regk_ser_yes;
++
++
++ tr_ctrl.stop = 0;
++ tr_ctrl.txd = 1;
++ }
++ REG_WR(ser, up->regi_ser, rw_tr_ctrl, tr_ctrl);
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
++ REG_WR(ser, up->regi_ser, rw_intr_mask, intr_mask);
++
++ spin_unlock_irqrestore(&up->port.lock, flags);
++}
++
++/*
++ * The output DMA channel is free - use it to send as many chars as
++ * possible.
++ */
++
++static void
++transmit_chars_dma(struct uart_cris_port *up)
++{
++ struct dma_descr_data *descr, *pending_descr, *dmapos;
++ struct dma_descr_data *last_tx_descr;
++ struct circ_buf *xmit = &up->port.info->xmit;
++ unsigned int sentl = 0;
++ reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes };
++ reg_dma_rw_stat status;
++ reg_scope_instances regi_dmaout = up->regi_dmaout;
++ unsigned int chars_in_q;
++ unsigned int chars_to_send;
++
++ /* Acknowledge dma data descriptor irq, if there was one. */
++ REG_WR(dma, regi_dmaout, rw_ack_intr, ack_intr);
++
++ /*
++ * First get the amount of bytes sent during the last DMA transfer,
++ * and update xmit accordingly.
++ */
++ status = REG_RD(dma, regi_dmaout, rw_stat);
++ if (status.list_state == regk_dma_data_at_eol || !up->tx_started)
++ dmapos = phys_to_virt((int)up->last_tx_descr->next);
++ else
++ dmapos = phys_to_virt(REG_RD_INT(dma, regi_dmaout, rw_data));
++
++ pending_descr = up->first_tx_descr;
++ while (pending_descr != dmapos) {
++ sentl += pending_descr->after - pending_descr->buf;
++ pending_descr->after = pending_descr->buf = NULL;
++ pending_descr = phys_to_virt((int)pending_descr->next);
++ }
++
++ up->first_tx_descr = pending_descr;
++ last_tx_descr = up->last_tx_descr;
++
++ /* Update stats. */
++ up->port.icount.tx += sentl;
++
++ up->tx_pending_chars -= sentl;
++
++ /* Update xmit buffer. */
++ xmit->tail = (xmit->tail + sentl) & (UART_XMIT_SIZE - 1);
++
++ /*
++ * Find out the largest amount of consecutive bytes we want to send
++ * now.
++ */
++ chars_in_q = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
++
++ if (chars_in_q == 0)
++ /* Tell upper layers that we're now idle. */
++ goto done;
++
++ /* Some of those characters are actually pending output. */
++ chars_to_send = chars_in_q - up->tx_pending_chars;
++
++ /*
++ * Clamp the new number of pending chars to the advertised
++ * one.
++ */
++ if (chars_to_send + up->tx_pending_chars > up->port.fifosize)
++ chars_to_send = up->port.fifosize - up->tx_pending_chars;
++
++ /* If we don't want to send any, we're done. */
++ if (chars_to_send == 0)
++ goto done;
++
++ descr = phys_to_virt((int)last_tx_descr->next);
++
++ /*
++ * We can't send anything if we could make the condition in
++ * the while-loop above (reaping finished descriptors) be met
++ * immediately before the first iteration. However, don't
++ * mistake the full state for the empty state.
++ */
++ if ((descr == up->first_tx_descr && up->tx_pending_chars != 0)
++ || descr->next == up->first_tx_descr)
++ goto done;
++
++ /* Set up the descriptor for output. */
++ descr->buf = (void*)virt_to_phys(xmit->buf + xmit->tail
++ + up->tx_pending_chars);
++ descr->after = descr->buf + chars_to_send;
++ descr->eol = 1;
++ descr->out_eop = 0;
++ descr->intr = 1;
++ descr->wait = 0;
++ descr->in_eop = 0;
++ descr->md = 0;
++ /*
++ * Make sure GCC doesn't move this eol clear before the eol set
++ * above.
++ */
++ barrier();
++ last_tx_descr->eol = 0;
++
++ up->last_tx_descr = descr;
++ up->tx_pending_chars += chars_to_send;
++
++ if (!up->tx_started) {
++ up->tx_started = 1;
++ up->tr_context_descr.next = 0;
++ up->tr_context_descr.saved_data
++ = (dma_descr_data*)virt_to_phys(descr);
++ up->tr_context_descr.saved_data_buf = descr->buf;
++ DMA_START_CONTEXT(regi_dmaout,
++ virt_to_phys(&up->tr_context_descr));
++ } else
++ DMA_CONTINUE_DATA(regi_dmaout);
++
++ /* DMA is now running (hopefully). */
++
++ done:
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&up->port);
++}
++
++static void
++transmit_chars_no_dma(struct uart_cris_port *up)
++{
++ int count;
++ struct circ_buf *xmit = &up->port.info->xmit;
++
++ reg_scope_instances regi_ser = up->regi_ser;
++ reg_ser_r_stat_din rstat;
++ reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
++
++ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
++ /* No more to send, so disable the interrupt. */
++ reg_ser_rw_intr_mask intr_mask;
++ intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
++ intr_mask.tr_rdy = 0;
++ intr_mask.tr_empty = 0;
++ REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
++ return;
++ }
++
++ count = ETRAX_SER_FIFO_SIZE;
++ do {
++ reg_ser_rw_dout dout = { .data = xmit->buf[xmit->tail] };
++ REG_WR(ser, regi_ser, rw_dout, dout);
++ REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
++ up->port.icount.tx++;
++ if (xmit->head == xmit->tail)
++ break;
++ rstat = REG_RD(ser, regi_ser, r_stat_din);
++ } while ((--count > 0) && rstat.tr_rdy);
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&up->port);
++} /* transmit_chars_no_dma */
++
++static struct etrax_recv_buffer *
++alloc_recv_buffer(unsigned int size)
++{
++ struct etrax_recv_buffer *buffer;
++
++ if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
++ panic("%s: Could not allocate %d bytes buffer\n",
++ __FUNCTION__, size);
++
++ buffer->next = NULL;
++ buffer->length = 0;
++ buffer->error = TTY_NORMAL;
++
++ return buffer;
++}
++
++static void
++append_recv_buffer(struct uart_cris_port *up,
++ struct etrax_recv_buffer *buffer)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ if (!up->first_recv_buffer)
++ up->first_recv_buffer = buffer;
++ else
++ up->last_recv_buffer->next = buffer;
++
++ up->last_recv_buffer = buffer;
++
++ up->recv_cnt += buffer->length;
++ if (up->recv_cnt > up->max_recv_cnt)
++ up->max_recv_cnt = up->recv_cnt;
++
++ local_irq_restore(flags);
++}
++
++static int
++add_char_and_flag(struct uart_cris_port *up, unsigned char data,
++ unsigned char flag)
++{
++ struct etrax_recv_buffer *buffer;
++
++ buffer = alloc_recv_buffer(4);
++ buffer->length = 1;
++ buffer->error = flag;
++ buffer->buffer[0] = data;
++
++ append_recv_buffer(up, buffer);
++
++ up->port.icount.rx++;
++
++ return 1;
++}
++
++static void
++flush_to_flip_buffer(struct uart_cris_port *up)
++{
++ struct tty_struct *tty;
++ struct etrax_recv_buffer *buffer;
++
++ tty = up->port.info->tty;
++ if (!up->first_recv_buffer || !tty)
++ return;
++
++ while ((buffer = up->first_recv_buffer)) {
++ unsigned int count = (unsigned int)
++ tty_insert_flip_string(tty, buffer->buffer,
++ buffer->length);
++
++ up->recv_cnt -= count;
++
++ if (count == buffer->length) {
++ up->first_recv_buffer = buffer->next;
++ kfree(buffer);
++ } else {
++ buffer->length -= count;
++ memmove(buffer->buffer, buffer->buffer + count,
++ buffer->length);
++ buffer->error = TTY_NORMAL;
++ }
++ }
++
++ if (!up->first_recv_buffer)
++ up->last_recv_buffer = NULL;
++
++ /* This call includes a check for low-latency. */
++ tty_flip_buffer_push(tty);
++}
++
++static unsigned int
++handle_descr_data(struct uart_cris_port *up, struct dma_descr_data *descr,
++ unsigned int recvl)
++{
++ struct etrax_recv_buffer *buffer
++ = phys_to_virt((unsigned long)descr->buf) - sizeof *buffer;
++
++ if (up->recv_cnt + recvl > 65536) {
++ printk(KERN_ERR "Too much pending incoming data on %s!"
++ " Dropping %u bytes.\n", up->port.info->tty->name,
++ recvl);
++ return 0;
++ }
++
++ buffer->length = recvl;
++
++ append_recv_buffer(up, buffer);
++
++ flush_to_flip_buffer(up);
++
++ buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
++ descr->buf = (void*)virt_to_phys(buffer->buffer);
++ descr->after = descr->buf + SERIAL_DESCR_BUF_SIZE;
++
++ return recvl;
++}
++
++static unsigned int
++handle_all_descr_data(struct uart_cris_port *up)
++{
++ struct dma_descr_data *descr
++ = &up->rec_descr[(up->cur_rec_descr - 1)
++ % SERIAL_RECV_DESCRIPTORS];
++ struct dma_descr_data *prev_descr;
++ unsigned int recvl;
++ unsigned int ret = 0;
++ reg_scope_instances regi_dmain = up->regi_dmain;
++
++ while (1) {
++ prev_descr = descr;
++ descr = &up->rec_descr[up->cur_rec_descr];
++
++ if (descr == phys_to_virt(REG_RD(dma, regi_dmain, rw_data)))
++ break;
++
++ if (++up->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
++ up->cur_rec_descr = 0;
++
++ /* Find out how many bytes were read. */
++ recvl = descr->after - descr->buf;
++
++ /* Update stats. */
++ up->port.icount.rx += recvl;
++
++ ret += handle_descr_data(up, descr, recvl);
++ descr->eol = 1;
++ /*
++ * Make sure GCC doesn't move this eol clear before the
++ * eol set above.
++ */
++ barrier();
++ prev_descr->eol = 0;
++ flush_dma_descr(descr,1); // Cache bug workaround
++ flush_dma_descr(prev_descr,0); // Cache bug workaround
++ }
++
++ return ret;
++}
++
++static void
++receive_chars_dma(struct uart_cris_port *up)
++{
++ reg_ser_r_stat_din rstat;
++ reg_dma_rw_ack_intr ack_intr = {0};
++
++ /* Acknowledge both dma_descr and dma_eop irq. */
++ ack_intr.data = 1;
++ ack_intr.in_eop = 1;
++ REG_WR(dma, up->regi_dmain, rw_ack_intr, ack_intr);
++
++ handle_all_descr_data(up);
++
++ /* Read the status register to detect errors. */
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++
++ if (rstat.framing_err | rstat.par_err | rstat.orun) {
++ /*
++ * If we got an error, we must reset it by reading the
++ * rs_stat_din register and put the data in buffer manually.
++ */
++ reg_ser_rs_stat_din stat_din;
++ stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
++
++ if (stat_din.par_err)
++ add_char_and_flag(up, stat_din.data, TTY_PARITY);
++ else if (stat_din.orun)
++ add_char_and_flag(up, stat_din.data, TTY_OVERRUN);
++ else if (stat_din.framing_err)
++ add_char_and_flag(up, stat_din.data, TTY_FRAME);
++ }
++
++ /* Restart the receiving DMA, in case it got stuck on an EOL. */
++ DMA_CONTINUE_DATA(up->regi_dmain);
++}
++
++void receive_chars_no_dma(struct uart_cris_port *up)
++{
++ reg_ser_rs_stat_din stat_din;
++ reg_ser_r_stat_din rstat;
++ struct tty_struct *tty;
++ struct uart_icount *icount;
++ int max_count = 16;
++ char flag;
++ reg_ser_rw_ack_intr ack_intr = { 0 };
++
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++ up->last_rx_active_usec = GET_JIFFIES_USEC();
++ up->last_rx_active = jiffies;
++ icount = &up->port.icount;
++ tty = up->port.info->tty;
++
++ do {
++ stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
++
++ flag = TTY_NORMAL;
++ ack_intr.dav = 1;
++ REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
++ icount->rx++;
++
++ if (stat_din.framing_err | stat_din.par_err | stat_din.orun) {
++ if (stat_din.data == 0x00 &&
++ stat_din.framing_err) {
++ /* Most likely a break. */
++ flag = TTY_BREAK;
++ icount->brk++;
++ } else if (stat_din.par_err) {
++ flag = TTY_PARITY;
++ icount->parity++;
++ } else if (stat_din.orun) {
++ flag = TTY_OVERRUN;
++ icount->overrun++;
++ } else if (stat_din.framing_err) {
++ flag = TTY_FRAME;
++ icount->frame++;
++ }
++ }
++
++ /*
++ * If this becomes important, we probably *could* handle this
++ * gracefully by keeping track of the unhandled character.
++ */
++ if (!tty_insert_flip_char(tty, stat_din.data, flag))
++ panic("%s: No tty buffer space", __FUNCTION__);
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++ } while (rstat.dav && (max_count-- > 0));
++ spin_unlock(&up->port.lock);
++ tty_flip_buffer_push(tty);
++ spin_lock(&up->port.lock);
++} /* receive_chars_no_dma */
++
++/*
++ * DMA output channel interrupt handler.
++ * this interrupt is called from DMA2(ser2), DMA8(ser3), DMA6(ser0) or
++ * DMA4(ser1) when they have finished a descriptor with the intr flag set.
++ */
++
++static irqreturn_t
++dma_tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
++ reg_dma_r_masked_intr masked_intr;
++ reg_scope_instances regi_dmaout;
++ int handled = 0;
++
++ spin_lock(&up->port.lock);
++ regi_dmaout = up->regi_dmaout;
++ if (!regi_dmaout) {
++ spin_unlock(&up->port.lock);
++ return IRQ_NONE;
++ }
++
++ /*
++ * Check for dma_descr (don't need to check for dma_eop in
++ * output DMA for serial).
++ */
++ masked_intr = REG_RD(dma, regi_dmaout, r_masked_intr);
++
++ if (masked_intr.data) {
++ /* We can send a new dma bunch. make it so. */
++
++ /*
++ * Read jiffies_usec first.
++ * We want this time to be as late as possible.
++ */
++ up->last_tx_active_usec = GET_JIFFIES_USEC();
++ up->last_tx_active = jiffies;
++ transmit_chars_dma(up);
++ handled = 1;
++ }
++ check_modem_status(up);
++ spin_unlock(&up->port.lock);
++ return IRQ_RETVAL(handled);
++}
++
++/* DMA input channel interrupt handler. */
++
++static irqreturn_t
++dma_rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
++ reg_dma_r_masked_intr masked_intr;
++ reg_scope_instances regi_dmain;
++ int handled = 0;
++
++ spin_lock(&up->port.lock);
++ regi_dmain = up->regi_dmain;
++ if (!regi_dmain) {
++ spin_unlock(&up->port.lock);
++ return IRQ_NONE;
++ }
++
++ /* Check for both dma_eop and dma_descr for the input dma channel. */
++ masked_intr = REG_RD(dma, regi_dmain, r_masked_intr);
++ if (masked_intr.data || masked_intr.in_eop) {
++ /* We have received something. */
++ receive_chars_dma(up);
++ handled = 1;
++ }
++ check_modem_status(up);
++ spin_unlock(&up->port.lock);
++ return IRQ_RETVAL(handled);
++}
++
++/* "Normal" serial port interrupt handler - both rx and tx. */
++
++static irqreturn_t
++ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
++ reg_scope_instances regi_ser;
++ int handled = 0;
++
++ spin_lock(&up->port.lock);
++ if (up->regi_dmain && up->regi_dmaout) {
++ spin_unlock(&up->port.lock);
++ return IRQ_NONE;
++ }
++
++ regi_ser = up->regi_ser;
++
++ if (regi_ser) {
++ reg_ser_r_masked_intr masked_intr;
++ masked_intr = REG_RD(ser, regi_ser, r_masked_intr);
++ /*
++ * Check what interrupts are active before taking
++ * actions. If DMA is used the interrupt shouldn't
++ * be enabled.
++ */
++ if (masked_intr.dav) {
++ receive_chars_no_dma(up);
++ handled = 1;
++ }
++ check_modem_status(up);
++
++ if (masked_intr.tr_rdy) {
++ transmit_chars_no_dma(up);
++ handled = 1;
++ }
++ }
++ spin_unlock(&up->port.lock);
++ return IRQ_RETVAL(handled);
++} /* ser_interrupt */
++
++static int start_recv_dma(struct uart_cris_port *up)
++{
++ struct dma_descr_data *descr = up->rec_descr;
++ struct etrax_recv_buffer *buffer;
++ int i;
++
++ /* Set up the receiving descriptors. */
++ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
++ buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
++ descr[i].next = (void*)virt_to_phys(&descr[i+1]);
++ descr[i].buf = (void*)virt_to_phys(buffer->buffer);
++ descr[i].after = descr[i].buf + SERIAL_DESCR_BUF_SIZE;
++ descr[i].eol = 0;
++ descr[i].out_eop = 0;
++ descr[i].intr = 1;
++ descr[i].wait = 0;
++ descr[i].in_eop = 0;
++ descr[i].md = 0;
++
++ }
++
++ /* Link the last descriptor to the first. */
++ descr[i-1].next = (void*)virt_to_phys(&descr[0]);
++
++ /* And mark it as end of list. */
++ descr[i-1].eol = 1;
++
++ /* Start with the first descriptor in the list. */
++ up->cur_rec_descr = 0;
++ up->rec_context_descr.next = 0;
++ up->rec_context_descr.saved_data
++ = (dma_descr_data *)virt_to_phys(&descr[up->cur_rec_descr]);
++ up->rec_context_descr.saved_data_buf = descr[up->cur_rec_descr].buf;
++
++ /* Start the DMA. */
++ DMA_START_CONTEXT(up->regi_dmain,
++ virt_to_phys(&up->rec_context_descr));
++
++ /* Input DMA should be running now. */
++ return 1;
++}
++
++
++static void start_receive(struct uart_cris_port *up)
++{
++ reg_scope_instances regi_dmain = up->regi_dmain;
++ if (regi_dmain) {
++ start_recv_dma(up);
++ }
++}
++
++
++static void start_transmitter(struct uart_cris_port *up)
++{
++ int i;
++ reg_scope_instances regi_dmaout = up->regi_dmaout;
++ if (regi_dmaout) {
++ for (i = 0; i < SERIAL_TX_DESCRIPTORS; i++) {
++ memset(&up->tr_descr[i], 0, sizeof(up->tr_descr[i]));
++ up->tr_descr[i].eol = 1;
++ up->tr_descr[i].intr = 1;
++ up->tr_descr[i].next = (dma_descr_data *)
++ virt_to_phys(&up->tr_descr[i+1]);
++ }
++ up->tr_descr[i-1].next = (dma_descr_data *)
++ virt_to_phys(&up->tr_descr[0]);
++ up->first_tx_descr = &up->tr_descr[0];
++
++ /*
++ * We'll be counting up to up->last_tx_descr->next from
++ * up->first_tx_descr when starting DMA, so we should make
++ * them the same for the very first round. If instead we'd
++ * set last_tx_descr = first_tx_descr, we'd rely on
++ * accidentally working code and data as we'd take a pass over
++ * the first, unused, descriptor.
++ */
++ up->last_tx_descr = &up->tr_descr[i-1];
++ up->tx_started = 0;
++ up->tx_pending_chars = 0;
++ }
++}
++
++static int serial_cris_startup(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ unsigned long flags;
++ reg_intr_vect_rw_mask intr_mask;
++ reg_ser_rw_intr_mask ser_intr_mask = {0};
++ reg_dma_rw_intr_mask dmain_intr_mask = {0};
++ reg_dma_rw_intr_mask dmaout_intr_mask = {0};
++ reg_dma_rw_cfg cfg = {.en = 1};
++ reg_scope_instances regi_dma;
++
++ spin_lock_irqsave(&up->port.lock, flags);
++
++ intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
++
++ dmain_intr_mask.data = dmain_intr_mask.in_eop = regk_dma_yes;
++ dmaout_intr_mask.data = regk_dma_yes;
++ if (!up->regi_dmain)
++ ser_intr_mask.dav = regk_ser_yes;
++
++ if (port->line == 0) {
++ if (request_irq(SER0_INTR_VECT, ser_interrupt,
++ IRQF_SHARED | IRQF_DISABLED, "ser0",
++ &serial_cris_ports[0]))
++ panic("irq ser0");
++ /* Enable the ser0 irq in global config. */
++ intr_mask.ser0 = 1;
++ /* Port ser0 can use dma6 for tx and dma7 for rx. */
++#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
++ if (request_irq(DMA6_INTR_VECT, dma_tr_interrupt,
++ IRQF_DISABLED, "serial 0 dma tr",
++ &serial_cris_ports[0]))
++ panic("irq ser0txdma");
++ crisv32_request_dma(6, "ser0", DMA_PANIC_ON_ERROR, 0,
++ dma_ser0);
++ /* Enable the dma6 irq in global config. */
++ intr_mask.dma6 = 1;
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
++ if (request_irq(DMA7_INTR_VECT, dma_rec_interrupt,
++ IRQF_DISABLED, "serial 0 dma rec",
++ &serial_cris_ports[0]))
++ panic("irq ser0rxdma");
++ crisv32_request_dma(7, "ser0", DMA_PANIC_ON_ERROR, 0,
++ dma_ser0);
++ /* Enable the dma7 irq in global config. */
++ intr_mask.dma7 = 1;
++#endif
++ } else if (port->line == 1) {
++ if (request_irq(SER1_INTR_VECT, ser_interrupt,
++ IRQF_SHARED | IRQF_DISABLED, "ser1",
++ &serial_cris_ports[1]))
++ panic("irq ser1");
++ /* Enable the ser1 irq in global config. */
++ intr_mask.ser1 = 1;
++
++ /* Port ser1 can use dma4 for tx and dma5 for rx. */
++#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
++ if (request_irq(DMA4_INTR_VECT, dma_tr_interrupt,
++ IRQF_DISABLED, "serial 1 dma tr",
++ &serial_cris_ports[1]))
++ panic("irq ser1txdma");
++ crisv32_request_dma(4, "ser1", DMA_PANIC_ON_ERROR, 0,
++ dma_ser1);
++ /* Enable the dma4 irq in global config. */
++ intr_mask.dma4 = 1;
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
++ if (request_irq(DMA5_INTR_VECT, dma_rec_interrupt,
++ IRQF_DISABLED, "serial 1 dma rec",
++ &serial_cris_ports[1]))
++ panic("irq ser1rxdma");
++ crisv32_request_dma(5, "ser1", DMA_PANIC_ON_ERROR, 0,
++ dma_ser1);
++ /* Enable the dma5 irq in global config. */
++ intr_mask.dma5 = 1;
++#endif
++ } else if (port->line == 2) {
++ if (request_irq(SER2_INTR_VECT, ser_interrupt,
++ IRQF_SHARED | IRQF_DISABLED, "ser2",
++ &serial_cris_ports[2]))
++ panic("irq ser2");
++ /* Enable the ser2 irq in global config. */
++ intr_mask.ser2 = 1;
++
++ /* Port ser2 can use dma2 for tx and dma3 for rx. */
++#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
++ if (request_irq(DMA2_INTR_VECT, dma_tr_interrupt,
++ IRQF_DISABLED, "serial 2 dma tr",
++ &serial_cris_ports[2]))
++ panic("irq ser2txdma");
++ crisv32_request_dma(2, "ser2", DMA_PANIC_ON_ERROR, 0,
++ dma_ser2);
++ /* Enable the dma2 irq in global config. */
++ intr_mask.dma2 = 1;
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
++ if (request_irq(DMA3_INTR_VECT, dma_rec_interrupt,
++ IRQF_DISABLED, "serial 2 dma rec",
++ &serial_cris_ports[2]))
++ panic("irq ser2rxdma");
++ crisv32_request_dma(3, "ser2", DMA_PANIC_ON_ERROR, 0,
++ dma_ser2);
++ /* Enable the dma3 irq in global config. */
++ intr_mask.dma3 = 1;
++#endif
++ } else if (port->line == 3) {
++ if (request_irq(SER3_INTR_VECT, ser_interrupt,
++ IRQF_SHARED | IRQF_DISABLED, "ser3",
++ &serial_cris_ports[3]))
++ panic("irq ser3" );
++ /* Enable the ser3 irq in global config. */
++ intr_mask.ser3 = 1;
++
++ /* Port ser3 can use dma8 for tx and dma9 for rx. */
++#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
++ if (request_irq(DMA8_INTR_VECT, dma_tr_interrupt,
++ IRQF_DISABLED, "serial 3 dma tr",
++ &serial_cris_ports[3]))
++ panic("irq ser3txdma");
++ crisv32_request_dma(8, "ser3", DMA_PANIC_ON_ERROR, 0,
++ dma_ser3);
++ /* Enable the dma2 irq in global config. */
++ intr_mask.dma8 = 1;
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
++ if (request_irq(DMA9_INTR_VECT, dma_rec_interrupt,
++ IRQF_DISABLED, "serial 3 dma rec",
++ &serial_cris_ports[3]))
++ panic("irq ser3rxdma");
++ crisv32_request_dma(9, "ser3", DMA_PANIC_ON_ERROR, 0,
++ dma_ser3);
++ /* Enable the dma3 irq in global config. */
++ intr_mask.dma9 = 1;
++#endif
++ }
++
++ /*
++ * Reset the DMA channels and make sure their interrupts are cleared.
++ */
++
++ regi_dma = up->regi_dmain;
++ if (regi_dma) {
++ reg_dma_rw_ack_intr ack_intr = { 0 };
++ DMA_RESET(regi_dma);
++ /* Wait until reset cycle is complete. */
++ DMA_WAIT_UNTIL_RESET(regi_dma);
++ REG_WR(dma, regi_dma, rw_cfg, cfg);
++ /* Make sure the irqs are cleared. */
++ ack_intr.group = 1;
++ ack_intr.ctxt = 1;
++ ack_intr.data = 1;
++ ack_intr.in_eop = 1;
++ ack_intr.stream_cmd = 1;
++ REG_WR(dma, regi_dma, rw_ack_intr, ack_intr);
++ }
++ regi_dma = up->regi_dmaout;
++ if (regi_dma) {
++ reg_dma_rw_ack_intr ack_intr = { 0 };
++ DMA_RESET(regi_dma);
++ /* Wait until reset cycle is complete. */
++ DMA_WAIT_UNTIL_RESET(regi_dma);
++ REG_WR(dma, regi_dma, rw_cfg, cfg);
++ /* Make sure the irqs are cleared. */
++ ack_intr.group = 1;
++ ack_intr.ctxt = 1;
++ ack_intr.data = 1;
++ ack_intr.in_eop = 1;
++ ack_intr.stream_cmd = 1;
++ REG_WR(dma, regi_dma, rw_ack_intr, ack_intr);
++ }
++
++ REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
++ REG_WR(ser, up->regi_ser, rw_intr_mask, ser_intr_mask);
++ if (up->regi_dmain)
++ REG_WR(dma, up->regi_dmain, rw_intr_mask, dmain_intr_mask);
++ if (up->regi_dmaout)
++ REG_WR(dma, up->regi_dmaout, rw_intr_mask, dmaout_intr_mask);
++
++ start_receive(up);
++ start_transmitter(up);
++
++ serial_cris_set_mctrl(&up->port, up->port.mctrl);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++
++ return 0;
++}
++
++static void serial_cris_shutdown(struct uart_port *port)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ unsigned long flags;
++ reg_intr_vect_rw_mask intr_mask;
++
++ spin_lock_irqsave(&up->port.lock, flags);
++
++ intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
++ serial_cris_stop_tx(port);
++ serial_cris_stop_rx(port);
++
++ if (port->line == 0) {
++ intr_mask.ser0 = 0;
++ free_irq(SER0_INTR_VECT, &serial_cris_ports[0]);
++#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
++ intr_mask.dma6 = 0;
++ crisv32_free_dma(6);
++ free_irq(DMA6_INTR_VECT, &serial_cris_ports[0]);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
++ intr_mask.dma7 = 0;
++ crisv32_free_dma(7);
++ free_irq(DMA7_INTR_VECT, &serial_cris_ports[0]);
++#endif
++ } else if (port->line == 1) {
++ intr_mask.ser1 = 0;
++ free_irq(SER1_INTR_VECT, &serial_cris_ports[1]);
++#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA4_OUT
++ intr_mask.dma4 = 0;
++ crisv32_free_dma(4);
++ free_irq(DMA4_INTR_VECT, &serial_cris_ports[1]);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA5_IN
++ intr_mask.dma5 = 0;
++ crisv32_free_dma(5);
++ free_irq(DMA5_INTR_VECT, &serial_cris_ports[1]);
++#endif
++ } else if (port->line == 2) {
++ intr_mask.ser2 = 0;
++ free_irq(SER2_INTR_VECT, &serial_cris_ports[2]);
++#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
++ intr_mask.dma2 = 0;
++ crisv32_free_dma(2);
++ free_irq(DMA2_INTR_VECT, &serial_cris_ports[2]);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
++ intr_mask.dma3 = 0;
++ crisv32_free_dma(3);
++ free_irq(DMA3_INTR_VECT, &serial_cris_ports[2]);
++#endif
++ } else if (port->line == 3) {
++ intr_mask.ser3 = 0;
++ free_irq(SER3_INTR_VECT, &serial_cris_ports[3]);
++#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT
++ intr_mask.dma8 = 0;
++ crisv32_free_dma(8);
++ free_irq(DMA8_INTR_VECT, &serial_cris_ports[3]);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN
++ intr_mask.dma9 = 0;
++ crisv32_free_dma(9);
++ free_irq(DMA9_INTR_VECT, &serial_cris_ports[3]);
++#endif
++ }
++
++ REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
++
++ serial_cris_set_mctrl(&up->port, up->port.mctrl);
++
++ if (up->regi_dmain) {
++ struct etrax_recv_buffer *rb;
++ struct etrax_recv_buffer *rb_next;
++ int i;
++ struct dma_descr_data *descr;
++
++ /*
++ * In case of DMA and receive errors, there might be pending
++ * receive buffers still linked here and not flushed upwards.
++ * Release them.
++ */
++ for (rb = up->first_recv_buffer; rb != NULL; rb = rb_next) {
++ rb_next = rb->next;
++ kfree (rb);
++ }
++ up->first_recv_buffer = NULL;
++ up->last_recv_buffer = NULL;
++
++ /*
++ * Also release buffers that were attached to the DMA
++ * before we shut down the hardware above.
++ */
++ for (i = 0, descr = up->rec_descr;
++ i < SERIAL_RECV_DESCRIPTORS;
++ i++)
++ if (descr[i].buf) {
++ rb = phys_to_virt((u32) descr[i].buf)
++ - sizeof *rb;
++ kfree(rb);
++ descr[i].buf = NULL;
++ }
++ }
++
++ spin_unlock_irqrestore(&up->port.lock, flags);
++
++}
++
++static void
++serial_cris_set_termios(struct uart_port *port, struct termios *termios,
++ struct termios *old)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ unsigned long flags;
++ reg_ser_rw_xoff xoff;
++ reg_ser_rw_xoff_clr xoff_clr = {0};
++ reg_ser_rw_tr_ctrl tx_ctrl = {0};
++ reg_ser_rw_tr_dma_en tx_dma_en = {0};
++ reg_ser_rw_rec_ctrl rx_ctrl = {0};
++ reg_ser_rw_tr_baud_div tx_baud_div = {0};
++ reg_ser_rw_rec_baud_div rx_baud_div = {0};
++ reg_ser_r_stat_din rstat;
++ int baud;
++
++ if (old &&
++ termios->c_cflag == old->c_cflag &&
++ termios->c_iflag == old->c_iflag)
++ return;
++
++ /* Start with default settings and then fill in changes. */
++
++ /* Tx: 8 bit, no/even parity, 1 stop bit, no cts. */
++ tx_ctrl.base_freq = regk_ser_f29_493;
++ tx_ctrl.en = 0;
++ tx_ctrl.stop = 0;
++#ifdef CONFIG_ETRAX_RS485
++ if (up->rs485.enabled && (up->port_type != TYPE_485FD)) {
++ tx_ctrl.auto_rts = regk_ser_yes;
++ } else
++#endif
++ tx_ctrl.auto_rts = regk_ser_no;
++ tx_ctrl.txd = 1;
++ tx_ctrl.auto_cts = 0;
++ /* Rx: 8 bit, no/even parity. */
++ if (up->regi_dmain) {
++ rx_ctrl.dma_mode = 1;
++ rx_ctrl.auto_eop = 1;
++ }
++ rx_ctrl.dma_err = regk_ser_stop;
++ rx_ctrl.sampling = regk_ser_majority;
++ rx_ctrl.timeout = 1;
++
++#ifdef CONFIG_ETRAX_RS485
++ if (up->rs485.enabled && (up->port_type != TYPE_485FD)) {
++# ifdef CONFIG_ETRAX_RS485_DISABLE_RECEIVER
++ rx_ctrl.half_duplex = regk_ser_yes;
++# endif
++ rx_ctrl.rts_n = up->rs485.rts_after_sent ?
++ regk_ser_active : regk_ser_inactive;
++ } else if (up->port_type == TYPE_485FD) {
++ rx_ctrl.rts_n = regk_ser_active;
++ } else
++#endif
++ rx_ctrl.rts_n = regk_ser_inactive;
++
++ /* Common for tx and rx: 8N1. */
++ tx_ctrl.data_bits = regk_ser_bits8;
++ rx_ctrl.data_bits = regk_ser_bits8;
++ tx_ctrl.par = regk_ser_even;
++ rx_ctrl.par = regk_ser_even;
++ tx_ctrl.par_en = regk_ser_no;
++ rx_ctrl.par_en = regk_ser_no;
++
++ tx_ctrl.stop_bits = regk_ser_bits1;
++
++
++ /* Change baud-rate and write it to the hardware. */
++
++ /* baud_clock = base_freq / (divisor*8)
++ * divisor = base_freq / (baud_clock * 8)
++ * base_freq is either:
++ * off, ext, 29.493MHz, 32.000 MHz, 32.768 MHz or 100 MHz
++ * 20.493MHz is used for standard baudrates
++ */
++
++ /*
++ * For the console port we keep the original baudrate here. Not very
++ * beautiful.
++ */
++ if ((port != console_port) || old)
++ baud = uart_get_baud_rate(port, termios, old, 0,
++ port->uartclk / 8);
++ else
++ baud = console_baud;
++
++ tx_baud_div.div = 29493000 / (8 * baud);
++ /* Rx uses same as tx. */
++ rx_baud_div.div = tx_baud_div.div;
++ rx_ctrl.base_freq = tx_ctrl.base_freq;
++
++ if ((termios->c_cflag & CSIZE) == CS7) {
++ /* Set 7 bit mode. */
++ tx_ctrl.data_bits = regk_ser_bits7;
++ rx_ctrl.data_bits = regk_ser_bits7;
++ }
++
++ if (termios->c_cflag & CSTOPB) {
++ /* Set 2 stop bit mode. */
++ tx_ctrl.stop_bits = regk_ser_bits2;
++ }
++
++ if (termios->c_cflag & PARENB) {
++ /* Enable parity. */
++ tx_ctrl.par_en = regk_ser_yes;
++ rx_ctrl.par_en = regk_ser_yes;
++ }
++
++ if (termios->c_cflag & CMSPAR) {
++ if (termios->c_cflag & PARODD) {
++ /* Set mark parity if PARODD and CMSPAR. */
++ tx_ctrl.par = regk_ser_mark;
++ rx_ctrl.par = regk_ser_mark;
++ } else {
++ tx_ctrl.par = regk_ser_space;
++ rx_ctrl.par = regk_ser_space;
++ }
++ } else {
++ if (termios->c_cflag & PARODD) {
++ /* Set odd parity. */
++ tx_ctrl.par = regk_ser_odd;
++ rx_ctrl.par = regk_ser_odd;
++ }
++ }
++
++ if (termios->c_cflag & CRTSCTS) {
++ /* Enable automatic CTS handling. */
++ tx_ctrl.auto_cts = regk_ser_yes;
++ }
++
++ /* Make sure the tx and rx are enabled. */
++ tx_ctrl.en = regk_ser_yes;
++ rx_ctrl.en = regk_ser_yes;
++
++ /*
++ * Wait for tr_idle in case a character is being output, so it won't
++ * be damaged by the changes we do below. It seems the termios
++ * changes "sometimes" (we can't see e.g. a tcsetattr TCSANOW
++ * parameter here) should take place no matter what state. However,
++ * in case we should wait, we may have a non-empty transmitter state
++ * as we tell the upper layers that we're all done when we've passed
++ * characters to the hardware, but we don't wait for them being
++ * actually shifted out.
++ */
++ spin_lock_irqsave(&port->lock, flags);
++
++ /*
++ * None of our interrupts re-enable DMA, so it's thankfully ok to
++ * disable it once, outside the loop.
++ */
++ tx_dma_en.en = 0;
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
++ do {
++ /*
++ * Make sure we have integrity between the read r_stat status
++ * and us writing the registers below, but don't busy-wait
++ * with interrupts off. We need to keep the port lock though
++ * (if we go SMP), so nobody else writes characters.
++ */
++ local_irq_restore(flags);
++ local_irq_save(flags);
++ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
++ } while (!rstat.tr_idle);
++
++ /* Actually write the control regs (if modified) to the hardware. */
++
++ uart_update_timeout(port, termios->c_cflag, port->uartclk/8);
++ MODIFY_REG(up->regi_ser, rw_rec_baud_div, rx_baud_div);
++ MODIFY_REG(up->regi_ser, rw_rec_ctrl, rx_ctrl);
++
++ MODIFY_REG(up->regi_ser, rw_tr_baud_div, tx_baud_div);
++ MODIFY_REG(up->regi_ser, rw_tr_ctrl, tx_ctrl);
++
++ tx_dma_en.en = up->regi_dmaout != 0;
++ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
++
++ xoff = REG_RD(ser, up->regi_ser, rw_xoff);
++
++ if (up->port.info && (up->port.info->tty->termios->c_iflag & IXON)) {
++ xoff.chr = STOP_CHAR(up->port.info->tty);
++ xoff.automatic = regk_ser_yes;
++ } else
++ xoff.automatic = regk_ser_no;
++
++ MODIFY_REG(up->regi_ser, rw_xoff, xoff);
++
++ /*
++ * Make sure we don't start in an automatically shut-off state due to
++ * a previous early exit.
++ */
++ xoff_clr.clr = 1;
++ REG_WR(ser, up->regi_ser, rw_xoff_clr, xoff_clr);
++
++ serial_cris_set_mctrl(&up->port, up->port.mctrl);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++}
++
++static const char *
++serial_cris_type(struct uart_port *port)
++{
++ return "CRISv32";
++}
++
++static void serial_cris_release_port(struct uart_port *port)
++{
++}
++
++static int serial_cris_request_port(struct uart_port *port)
++{
++ return 0;
++}
++
++static void serial_cris_config_port(struct uart_port *port, int flags)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ up->port.type = PORT_CRIS;
++}
++
++#if defined(CONFIG_ETRAX_RS485)
++
++static void cris_set_rs485_mode(struct uart_cris_port* up) {
++ reg_ser_rw_tr_ctrl tr_ctrl;
++ reg_ser_rw_rec_ctrl rec_ctrl;
++ reg_scope_instances regi_ser = up->regi_ser;
++
++ if (up->port_type == TYPE_485FD)
++ /* We do not want to change anything if we are in 485FD mode */
++ return;
++
++ tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
++ rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
++
++ /* Set port in RS-485 mode */
++ if (up->rs485.enabled) {
++ tr_ctrl.auto_rts = regk_ser_yes;
++ rec_ctrl.rts_n = up->rs485.rts_after_sent ?
++ regk_ser_active : regk_ser_inactive;
++#ifdef CONFIG_ETRAX_RS485_DISABLE_RECEIVER
++ rec_ctrl.half_duplex = regk_ser_yes;
++#endif
++ }
++ /* Set port to RS-232 mode */
++ else {
++ rec_ctrl.rts_n = regk_ser_inactive;
++ tr_ctrl.auto_rts = regk_ser_no;
++ rec_ctrl.half_duplex = regk_ser_no;
++ }
++
++ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
++ REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
++}
++
++/* Enable/disable RS-485 mode on selected port. */
++static int
++cris_enable_rs485(struct uart_cris_port* up, struct rs485_control *r)
++{
++ if (up->port_type == TYPE_485FD)
++ /* Port in 485FD mode can not chage mode */
++ goto out;
++
++ up->rs485.enabled = 0x1 & r->enabled;
++ up->rs485.rts_on_send = 0x01 & r->rts_on_send;
++ up->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
++ up->rs485.delay_rts_before_send = r->delay_rts_before_send;
++
++ cris_set_rs485_mode(up);
++ out:
++ return 0;
++}
++
++
++/* Enable RS485 mode on port and send the data. Port will stay
++ * in 485 mode after the data has been sent.
++ */
++static int
++cris_write_rs485(struct uart_cris_port* up, const unsigned char *buf,
++ int count)
++{
++ up->rs485.enabled = 1;
++
++ /* Set the port in RS485 mode */
++ cris_set_rs485_mode(up);
++
++ /* Send the data */
++ count = serial_cris_driver.tty_driver->write(up->port.info->tty, buf, count);
++
++ return count;
++}
++
++#endif /* CONFIG_ETRAX_RS485 */
++
++static int serial_cris_ioctl(struct uart_port *port, unsigned int cmd,
++ unsigned long arg)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++
++ switch (cmd) {
++#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 cris_enable_rs485(up, &rs485ctrl);
++ }
++
++ case TIOCSERWRRS485: {
++ struct rs485_write rs485wr;
++ if (copy_from_user(&rs485wr, (struct rs485_write*)arg,
++ sizeof(rs485wr)))
++ return -EFAULT;
++
++ return cris_write_rs485(up, rs485wr.outc, rs485wr.outc_size);
++ }
++#endif
++ default:
++ return -ENOIOCTLCMD;
++ }
++
++ return 0;
++}
++
++static const struct uart_ops serial_cris_pops = {
++ .tx_empty = serial_cris_tx_empty,
++ .set_mctrl = serial_cris_set_mctrl,
++ .get_mctrl = serial_cris_get_mctrl,
++ .stop_tx = serial_cris_stop_tx,
++ .start_tx = serial_cris_start_tx,
++ .send_xchar = serial_cris_send_xchar,
++ .stop_rx = serial_cris_stop_rx,
++ .enable_ms = serial_cris_enable_ms,
++ .break_ctl = serial_cris_break_ctl,
++ .startup = serial_cris_startup,
++ .shutdown = serial_cris_shutdown,
++ .set_termios = serial_cris_set_termios,
++ .type = serial_cris_type,
++ .release_port = serial_cris_release_port,
++ .request_port = serial_cris_request_port,
++ .config_port = serial_cris_config_port,
++ .ioctl = serial_cris_ioctl,
++};
++
++/*
++ * It's too easy to break CONFIG_ETRAX_DEBUG_PORT_NULL and the
++ * no-config choices by adding and moving code to before a necessary
++ * early exit in all functions for the special case of
++ * up->regi_ser == 0. This collection of dummy functions lets us
++ * avoid that. Maybe there should be a generic table of dummy serial
++ * functions?
++ */
++
++static unsigned int serial_cris_tx_empty_dummy(struct uart_port *port)
++{
++ return TIOCSER_TEMT;
++}
++
++static void serial_cris_set_mctrl_dummy(struct uart_port *port,
++ unsigned int mctrl)
++{
++}
++
++static unsigned int serial_cris_get_mctrl_dummy(struct uart_port *port)
++{
++ return 0;
++}
++
++static void serial_cris_stop_tx_dummy(struct uart_port *port)
++{
++}
++
++static void serial_cris_start_tx_dummy(struct uart_port *port)
++{
++ /* Discard outbound characters. */
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ struct circ_buf *xmit = &up->port.info->xmit;
++ xmit->tail = xmit->head;
++ uart_write_wakeup(port);
++}
++
++#define serial_cris_stop_rx_dummy serial_cris_stop_tx_dummy
++
++#define serial_cris_enable_ms_dummy serial_cris_stop_tx_dummy
++
++static void serial_cris_break_ctl_dummy(struct uart_port *port,
++ int break_state)
++{
++}
++
++static int serial_cris_startup_dummy(struct uart_port *port)
++{
++ return 0;
++}
++
++#define serial_cris_shutdown_dummy serial_cris_stop_tx_dummy
++
++static void
++serial_cris_set_termios_dummy(struct uart_port *port, struct termios *termios,
++ struct termios *old)
++{
++}
++
++#define serial_cris_release_port_dummy serial_cris_stop_tx_dummy
++#define serial_cris_request_port_dummy serial_cris_startup_dummy
++
++static const struct uart_ops serial_cris_dummy_pops = {
++ /*
++ * We *could* save one or two of those with different
++ * signature by casting and knowledge of the ABI, but it's
++ * just not worth the maintenance headache.
++ * For the ones we don't define here, the default (usually meaning
++ * "unimplemented") makes sense.
++ */
++ .tx_empty = serial_cris_tx_empty_dummy,
++ .set_mctrl = serial_cris_set_mctrl_dummy,
++ .get_mctrl = serial_cris_get_mctrl_dummy,
++ .stop_tx = serial_cris_stop_tx_dummy,
++ .start_tx = serial_cris_start_tx_dummy,
++ .stop_rx = serial_cris_stop_rx_dummy,
++ .enable_ms = serial_cris_enable_ms_dummy,
++ .break_ctl = serial_cris_break_ctl_dummy,
++ .startup = serial_cris_startup_dummy,
++ .shutdown = serial_cris_shutdown_dummy,
++ .set_termios = serial_cris_set_termios_dummy,
++
++ /* This one we keep the same. */
++ .type = serial_cris_type,
++
++ .release_port = serial_cris_release_port_dummy,
++ .request_port = serial_cris_request_port_dummy,
++
++ /*
++ * This one we keep the same too, as long as it doesn't do
++ * anything else but to set the type.
++ */
++ .config_port = serial_cris_config_port,
++};
++
++static void cris_serial_port_init(struct uart_port *port, int line)
++{
++ struct uart_cris_port *up = (struct uart_cris_port *)port;
++ static int first = 1;
++
++ if (up->initialized)
++ return;
++ up->initialized = 1;
++ port->line = line;
++ spin_lock_init(&port->lock);
++ port->ops =
++ up->regi_ser == 0 ? &serial_cris_dummy_pops :
++ &serial_cris_pops;
++ port->irq = up->irq;
++ port->iobase = up->regi_ser ? up->regi_ser : 1;
++ port->uartclk = 29493000;
++
++ /*
++ * We can't fit any more than 255 here (unsigned char), though
++ * actually UART_XMIT_SIZE characters could be pending output (if it
++ * wasn't for the single test in transmit_chars_dma). At time of this
++ * writing, the definition of "fifosize" is here the amount of
++ * characters that can be pending output after a start_tx call until
++ * tx_empty returns 1: see serial_core.c:uart_wait_until_sent. This
++ * matters for timeout calculations unfortunately, but keeping larger
++ * amounts at the DMA wouldn't win much so let's just play nice.
++ */
++ port->fifosize = 255;
++ port->flags = UPF_BOOT_AUTOCONF;
++
++#ifdef CONFIG_ETRAX_RS485
++ /* Set sane defaults. */
++ up->rs485.rts_on_send = 0;
++ up->rs485.rts_after_sent = 1;
++ up->rs485.delay_rts_before_send = 0;
++ if (up->port_type > TYPE_232)
++ up->rs485.enabled = 1;
++ else
++ up->rs485.enabled = 0;
++#endif
++
++ if (first) {
++ first = 0;
++#ifdef CONFIG_ETRAX_SERIAL_PORT0
++ SETUP_PINS(0);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT1
++ SETUP_PINS(1);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT2
++ SETUP_PINS(2);
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT3
++ SETUP_PINS(3);
++#endif
++ }
++}
++
++static int __init serial_cris_init(void)
++{
++ int ret, i;
++ reg_ser_rw_rec_ctrl rec_ctrl;
++ printk(KERN_INFO "Serial: CRISv32 driver $Revision: 1.78 $ ");
++
++ ret = uart_register_driver(&serial_cris_driver);
++ if (ret)
++ goto out;
++
++ for (i = 0; i < UART_NR; i++) {
++ if (serial_cris_ports[i].used) {
++#ifdef CONFIG_ETRAX_RS485
++ /* Make sure that the RTS pin stays low when allocating
++ * pins for a port in 485 mode.
++ */
++ if (serial_cris_ports[i].port_type > TYPE_232) {
++ rec_ctrl = REG_RD(ser, serial_cris_ports[i].regi_ser, rw_rec_ctrl);
++ rec_ctrl.rts_n = regk_ser_active;
++ REG_WR(ser, serial_cris_ports[i].regi_ser, rw_rec_ctrl, rec_ctrl);
++ }
++#endif
++ switch (serial_cris_ports[i].regi_ser) {
++ case regi_ser1:
++ if (crisv32_pinmux_alloc_fixed(pinmux_ser1)) {
++ printk("Failed to allocate pins for ser1, disable port\n");
++ serial_cris_ports[i].used = 0;
++ continue;
++ }
++ break;
++ case regi_ser2:
++ if (crisv32_pinmux_alloc_fixed(pinmux_ser2)) {
++ printk("Failed to allocate pins for ser2, disable port\n");
++ serial_cris_ports[i].used = 0;
++ continue;
++ }
++ break;
++ case regi_ser3:
++ if (crisv32_pinmux_alloc_fixed(pinmux_ser3)) {
++ printk("Failed to allocate pins for ser3, disable port\n");
++ serial_cris_ports[i].used = 0;
++ continue;
++ }
++ break;
++ }
++
++ struct uart_port *port = &serial_cris_ports[i].port;
++ cris_console.index = i;
++ cris_serial_port_init(port, i);
++ uart_add_one_port(&serial_cris_driver, port);
++ }
++ }
++
++out:
++ return ret;
++}
++
++static void __exit serial_cris_exit(void)
++{
++ int i;
++ for (i = 0; i < UART_NR; i++)
++ if (serial_cris_ports[i].used) {
++ switch (serial_cris_ports[i].regi_ser) {
++ case regi_ser1:
++ crisv32_pinmux_dealloc_fixed(pinmux_ser1);
++ break;
++ case regi_ser2:
++ crisv32_pinmux_dealloc_fixed(pinmux_ser2);
++ break;
++ case regi_ser3:
++ crisv32_pinmux_dealloc_fixed(pinmux_ser3);
++ break;
++ }
++ uart_remove_one_port(&serial_cris_driver,
++ &serial_cris_ports[i].port);
++ }
++ uart_unregister_driver(&serial_cris_driver);
++}
++
++module_init(serial_cris_init);
++module_exit(serial_cris_exit);
+--- linux-2.6.19.2.orig/drivers/usb/host/hc_crisv10.c 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/usb/host/hc-crisv10.c 2007-02-26 20:58:29.000000000 +0100
+@@ -1,219 +1,51 @@
+ /*
+- * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
+ *
+- * Copyright (c) 2002, 2003 Axis Communications AB.
++ * ETRAX 100LX USB Host Controller Driver
++ *
++ * Copyright (C) 2005, 2006 Axis Communications AB
++ *
++ * Author: Konrad Eriksson <konrad.eriksson@axis.se>
++ *
+ */
+
++#include <linux/module.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/list.h>
++#include <linux/moduleparam.h>
+ #include <linux/spinlock.h>
++#include <linux/usb.h>
++#include <linux/platform_device.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 <asm/arch/dma.h>
++#include <asm/arch/io_interface_mux.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 "hc_crisv10.h"
++#include "../core/hcd.h"
++#include "../core/hub.h"
++#include "hc-crisv10.h"
++#include "hc-cris-dbg.h"
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Host Controller settings */
++/***************************************************************************/
++/***************************************************************************/
++
++#define VERSION "1.00"
++#define COPYRIGHT "(c) 2005, 2006 Axis Communications AB"
++#define DESCRIPTION "ETRAX 100LX USB Host Controller"
+
+ #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, /* __le16 bcdUSB; v1.0 */
+- 0x01,
+- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+- 0x00, /* __u8 bDeviceSubClass; */
+- 0x00, /* __u8 bDeviceProtocol; */
+- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+- 0x00, /* __le16 idVendor; */
+- 0x00,
+- 0x00, /* __le16 idProduct; */
+- 0x00,
+- 0x00, /* __le16 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, /* __le16 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, /* __le16 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 DEFINE_TIMER(bulk_start_timer, NULL, 0, 0);
+-static DEFINE_TIMER(bulk_eot_timer, 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); \
+- } \
+-}
+-*/
+-
++/* Number of physical ports in Etrax 100LX */
++#define USB_ROOT_HUB_PORTS 2
+
+-/* 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)
++const char hc_name[] = "hc-crisv10";
++const char product_desc[] = DESCRIPTION;
+
+ /* The number of epids is, among other things, used for pre-allocating
+ ctrl, bulk and isoc EP descriptors (one for each epid).
+@@ -221,4332 +53,4632 @@
+ #define NBR_OF_EPIDS 32
+
+ /* Support interrupt traffic intervals up to 128 ms. */
+-#define MAX_INTR_INTERVAL 128
++#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
++/* 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)));
++#define DUMMY_EPID 30
+
+-/* Cache for allocating new EP and SB descriptors. */
+-static kmem_cache_t *usb_desc_cache;
++/* Module settings */
+
+-/* Cache for the registers allocated in the top half. */
+-static kmem_cache_t *top_half_reg_cache;
++MODULE_DESCRIPTION(DESCRIPTION);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Konrad Eriksson <konrad.eriksson@axis.se>");
+
+-/* 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;
++/* Module parameters */
+
+-/* 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];
++/* 0 = No ports enabled
++ 1 = Only port 1 enabled (on board ethernet on devboard)
++ 2 = Only port 2 enabled (external connector on devboard)
++ 3 = Both ports enabled
++*/
++static unsigned int ports = 3;
++module_param(ports, uint, S_IRUGO);
++MODULE_PARM_DESC(ports, "Bitmask indicating USB ports to use");
+
+-/* 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;
++/***************************************************************************/
++/***************************************************************************/
++/* Shared global variables for this module */
++/***************************************************************************/
++/***************************************************************************/
+
+-/* for returning string descriptors in UTF-16LE */
+-static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+-{
+- int retval;
++/* EP descriptor lists for non period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+
+- for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+- *utf++ = *ascii++ & 0x7f;
+- *utf++ = 0;
+- }
+- return retval;
+-}
++static volatile struct USB_EP_Desc TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+
+-static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+-{
+- char buf [30];
++/* EP descriptor lists for period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIntrSB_zout __attribute__ ((aligned (4)));
+
+- // assert (len > (2 * (sizeof (buf) + 1)));
+- // assert (strlen (type) <= 8);
++static volatile struct USB_EP_Desc TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIsocSB_zout __attribute__ ((aligned (4)));
+
+- // 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];
+-}
++static volatile struct USB_SB_Desc TxIsocSBList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+
+-/* Wrappers around the list functions (include/linux/list.h). */
++/* After each enabled bulk EP IN 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 struct USB_EP_Desc TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
+
+-static inline int urb_list_empty(int epid)
++/* List of URB pointers, where each points to the active URB for a epid.
++ For Bulk, Ctrl and Intr this means which URB that currently is added to
++ DMA lists (Isoc URBs are all directly added to DMA lists). As soon as
++ URB has completed is the queue examined and the first URB in queue is
++ removed and moved to the activeUrbList while its state change to STARTED and
++ its transfer(s) gets added to DMA list (exception Isoc where URBs enter
++ state STARTED directly and added transfers added to DMA lists). */
++static struct urb *activeUrbList[NBR_OF_EPIDS];
++
++/* Additional software state info for each epid */
++static struct etrax_epid epid_state[NBR_OF_EPIDS];
++
++/* Timer handles for bulk traffic timer used to avoid DMA bug where DMA stops
++ even if there is new data waiting to be processed */
++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/50) /* 20 ms */
++#define BULK_EOT_TIMER_INTERVAL (HZ/16) /* 60 ms */
++
++/* Delay before a URB completion happen when it's scheduled to be delayed */
++#define LATER_TIMER_DELAY (HZ/50) /* 20 ms */
++
++/* Simplifying macros for checking software state info of a epid */
++/* ----------------------------------------------------------------------- */
++#define epid_inuse(epid) epid_state[epid].inuse
++#define epid_out_traffic(epid) epid_state[epid].out_traffic
++#define epid_isoc(epid) (epid_state[epid].type == PIPE_ISOCHRONOUS ? 1 : 0)
++#define epid_intr(epid) (epid_state[epid].type == PIPE_INTERRUPT ? 1 : 0)
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* DEBUG FUNCTIONS */
++/***************************************************************************/
++/***************************************************************************/
++/* 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)
+ {
+- return list_empty(&urb_list[epid]);
++ struct crisv10_urb_priv *urb_priv = purb->hcpriv;
++ int urb_num = -1;
++ if(urb_priv) {
++ urb_num = urb_priv->urb_num;
++ }
++ printk("\nURB:0x%x[%d]\n", (unsigned int)purb, urb_num);
++ 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 struct USB_IN_Desc *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 struct USB_SB_Desc *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(" USB_SB_Desc at 0x%08lx ", (unsigned long)sb);
++ printk(" command:0x%04x (", sb->command);
++ printk("rem:%d ", (sb->command & 0x3f00) >> 8);
++ printk("full:%d ", (sb->command & 0x40) >> 6);
++ printk("tt:%d(%s) ", tt, tt_string);
++ printk("intr:%d ", (sb->command & 0x8) >> 3);
++ printk("eot:%d ", (sb->command & 0x2) >> 1);
++ printk("eol:%d)", sb->command & 0x1);
++ printk(" sw_len:0x%04x(%d)", sb->sw_len, sb->sw_len);
++ printk(" next:0x%08lx", sb->next);
++ printk(" buf:0x%08lx\n", sb->buf);
++}
++
++
++static void __dump_ep_desc(volatile struct USB_EP_Desc *ep)
++{
++ printk("USB_EP_Desc at 0x%08lx ", (unsigned long)ep);
++ printk(" command:0x%04x (", ep->command);
++ printk("ep_id:%d ", (ep->command & 0x1f00) >> 8);
++ printk("enable:%d ", (ep->command & 0x10) >> 4);
++ printk("intr:%d ", (ep->command & 0x8) >> 3);
++ printk("eof:%d ", (ep->command & 0x2) >> 1);
++ printk("eol:%d)", ep->command & 0x1);
++ printk(" hw_len:0x%04x(%d)", ep->hw_len, ep->hw_len);
++ printk(" next:0x%08lx", ep->next);
++ printk(" sub:0x%08lx\n", ep->sub);
+ }
+
+-/* Returns first urb for this epid, or NULL if list is empty. */
+-static inline struct urb *urb_list_first(int epid)
++static inline void __dump_ep_list(int pipe_type)
+ {
+- struct urb *first_urb = 0;
++ volatile struct USB_EP_Desc *ep;
++ volatile struct USB_EP_Desc *first_ep;
++ volatile struct USB_SB_Desc *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 struct USB_EP_Desc *)(phys_to_virt(ep->next));
+
+- 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;
++ } while (ep != first_ep);
+ }
+
+-/* Adds an urb_entry last in the list for this epid. */
+-static inline void urb_list_add(struct urb *urb, int epid)
++static inline void __dump_ept_data(int epid)
+ {
+- urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
+- assert(urb_entry);
++ unsigned long flags;
++ __u32 r_usb_ept_data;
+
+- urb_entry->urb = urb;
+- list_add_tail(&urb_entry->list, &urb_list[epid]);
++ if (epid < 0 || epid > 31) {
++ printk("Cannot dump ept data for invalid epid %d\n", epid);
++ return;
++ }
++
++ local_irq_save(flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ r_usb_ept_data = *R_USB_EPT_DATA;
++ local_irq_restore(flags);
++
++ printk(" R_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_iso(int epid)
++{
++ unsigned long flags;
++ __u32 ept_data;
++
++ if (epid < 0 || epid > 31) {
++ printk("Cannot dump ept data for invalid epid %d\n", epid);
++ return;
++ }
++
++ local_irq_save(flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ ept_data = *R_USB_EPT_DATA_ISO;
++ local_irq_restore(flags);
++
++ printk(" R_USB_EPT_DATA = 0x%x for epid %d :\n", ept_data, epid);
++ if (ept_data == 0) {
++ /* No need for more detailed printing. */
++ return;
++ }
++ printk(" valid : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, valid,
++ ept_data));
++ printk(" port : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, port,
++ ept_data));
++ printk(" error_code : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code,
++ ept_data));
++ printk(" max_len : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len,
++ ept_data));
++ printk(" ep : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, ep,
++ ept_data));
++ printk(" dev : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, dev,
++ ept_data));
+ }
+
+-/* 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)
++static inline void __dump_ept_data_list(void)
+ {
+- 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;
+-}
++ int i;
+
+-/* 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);
++ printk("Dumping the whole R_USB_EPT_DATA list\n");
+
+- /* Delete entry and free. */
+- list_del(&urb_entry->list);
+- kfree(urb_entry);
++ for (i = 0; i < 32; i++) {
++ __dump_ept_data(i);
++ }
++}
++
++static void debug_epid(int epid) {
++ int i;
++
++ if(epid_isoc(epid)) {
++ __dump_ept_data_iso(epid);
++ } else {
++ __dump_ept_data(epid);
++ }
++
++ printk("Bulk:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxBulkEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxBulkEPList[i]));
++ }
++ }
++
++ printk("Ctrl:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxCtrlEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxCtrlEPList[i]));
++ }
++ }
++
++ printk("Intr:\n");
++ for(i = 0; i < MAX_INTR_INTERVAL; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxIntrEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxIntrEPList[i]));
++ }
++ }
++
++ printk("Isoc:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxIsocEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxIsocEPList[i]));
++ }
++ }
++
++ __dump_ept_data_list();
++ __dump_ep_list(PIPE_INTERRUPT);
++ printk("\n\n");
++}
++
++
++
++char* hcd_status_to_str(__u8 bUsbStatus) {
++ static char hcd_status_str[128];
++ hcd_status_str[0] = '\0';
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, ourun, yes)) {
++ strcat(hcd_status_str, "ourun ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, perror, yes)) {
++ strcat(hcd_status_str, "perror ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, device_mode, yes)) {
++ strcat(hcd_status_str, "device_mode ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, host_mode, yes)) {
++ strcat(hcd_status_str, "host_mode ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, started, yes)) {
++ strcat(hcd_status_str, "started ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, running, yes)) {
++ strcat(hcd_status_str, "running ");
++ }
++ return hcd_status_str;
++}
++
++
++char* sblist_to_str(struct USB_SB_Desc* sb_desc) {
++ static char sblist_to_str_buff[128];
++ char tmp[32], tmp2[32];
++ sblist_to_str_buff[0] = '\0';
++ while(sb_desc != NULL) {
++ switch(IO_EXTRACT(USB_SB_command, tt, sb_desc->command)) {
++ case 0: sprintf(tmp, "zout"); break;
++ case 1: sprintf(tmp, "in"); break;
++ case 2: sprintf(tmp, "out"); break;
++ case 3: sprintf(tmp, "setup"); break;
++ }
++ sprintf(tmp2, "(%s %d)", tmp, sb_desc->sw_len);
++ strcat(sblist_to_str_buff, tmp2);
++ if(sb_desc->next != 0) {
++ sb_desc = phys_to_virt(sb_desc->next);
++ } else {
++ sb_desc = NULL;
++ }
++ }
++ return sblist_to_str_buff;
++}
++
++char* port_status_to_str(__u16 wPortStatus) {
++ static char port_status_str[128];
++ port_status_str[0] = '\0';
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) {
++ strcat(port_status_str, "connected ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) {
++ strcat(port_status_str, "enabled ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, suspended, yes)) {
++ strcat(port_status_str, "suspended ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes)) {
++ strcat(port_status_str, "reset ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, speed, full)) {
++ strcat(port_status_str, "full-speed ");
++ } else {
++ strcat(port_status_str, "low-speed ");
++ }
++ return port_status_str;
++}
++
++
++char* endpoint_to_str(struct usb_endpoint_descriptor *ed) {
++ static char endpoint_to_str_buff[128];
++ char tmp[32];
++ int epnum = ed->bEndpointAddress & 0x0F;
++ int dir = ed->bEndpointAddress & 0x80;
++ int type = ed->bmAttributes & 0x03;
++ endpoint_to_str_buff[0] = '\0';
++ sprintf(endpoint_to_str_buff, "ep:%d ", epnum);
++ switch(type) {
++ case 0:
++ sprintf(tmp, " ctrl");
++ break;
++ case 1:
++ sprintf(tmp, " isoc");
++ break;
++ case 2:
++ sprintf(tmp, " bulk");
++ break;
++ case 3:
++ sprintf(tmp, " intr");
++ break;
++ }
++ strcat(endpoint_to_str_buff, tmp);
++ if(dir) {
++ sprintf(tmp, " in");
++ } else {
++ sprintf(tmp, " out");
++ }
++ strcat(endpoint_to_str_buff, tmp);
++
++ return endpoint_to_str_buff;
++}
++
++/* Debug helper functions for Transfer Controller */
++char* pipe_to_str(unsigned int pipe) {
++ static char pipe_to_str_buff[128];
++ char tmp[64];
++ sprintf(pipe_to_str_buff, "dir:%s", str_dir(pipe));
++ sprintf(tmp, " type:%s", str_type(pipe));
++ strcat(pipe_to_str_buff, tmp);
++
++ sprintf(tmp, " dev:%d", usb_pipedevice(pipe));
++ strcat(pipe_to_str_buff, tmp);
++ sprintf(tmp, " ep:%d", usb_pipeendpoint(pipe));
++ strcat(pipe_to_str_buff, tmp);
++ return pipe_to_str_buff;
+ }
+
+-/* 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_move_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);
++#define USB_DEBUG_DESC 1
+
+- assert(urb_entry);
++#ifdef USB_DEBUG_DESC
++#define dump_in_desc(x) __dump_in_desc(x)
++#define dump_sb_desc(...) __dump_sb_desc(...)
++#define dump_ep_desc(x) __dump_ep_desc(x)
++#define dump_ept_data(x) __dump_ept_data(x)
++#else
++#define dump_in_desc(...) do {} while (0)
++#define dump_sb_desc(...) do {} while (0)
++#define dump_ep_desc(...) do {} while (0)
++#endif
+
+- 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;
+- }
+-}
+
++/* Uncomment this to enable massive function call trace
++ #define USB_DEBUG_TRACE */
+
++#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
+
+-/* 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);
+- }
+-}
++#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
++{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
+
+-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,
+- unsigned 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, unsigned 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 irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc);
+-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc);
+-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc);
+-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);
++/* Most helpful debugging aid */
++#define ASSERT(expr) ((void) ((expr) ? 0 : (err("assert failed at: %s %d",__FUNCTION__, __LINE__))))
+
+-static int etrax_usb_hc_init(void);
+-static void etrax_usb_hc_cleanup(void);
+
+-static struct usb_operations etrax_usb_device_operations =
+-{
+- .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
+-};
++/***************************************************************************/
++/***************************************************************************/
++/* Forward declarations */
++/***************************************************************************/
++/***************************************************************************/
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg);
++
++void rh_port_status_change(__u16[]);
++int rh_clear_port_feature(__u8, __u16);
++int rh_set_port_feature(__u8, __u16);
++static void rh_disable_port(unsigned int port);
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++ int timer);
++
++static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++ int mem_flags);
++static void tc_free_epid(struct usb_host_endpoint *ep);
++static int tc_allocate_epid(void);
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status);
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++ int status);
++
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++ int mem_flags);
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb);
++
++static inline struct urb *urb_list_first(int epid);
++static inline void urb_list_add(struct urb *urb, int epid,
++ int mem_flags);
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid);
++static inline void urb_list_del(struct urb *urb, int epid);
++static inline void urb_list_move_last(struct urb *urb, int epid);
++static inline struct urb *urb_list_next(struct urb *urb, int epid);
++
++int create_sb_for_urb(struct urb *urb, int mem_flags);
++int init_intr_urb(struct urb *urb, int mem_flags);
++
++static inline void etrax_epid_set(__u8 index, __u32 data);
++static inline void etrax_epid_clear_error(__u8 index);
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++ __u8 toggle);
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout);
++static inline __u32 etrax_epid_get(__u8 index);
++
++/* We're accessing the same register position in Etrax so
++ when we do full access the internal difference doesn't matter */
++#define etrax_epid_iso_set(index, data) etrax_epid_set(index, data)
++#define etrax_epid_iso_get(index) etrax_epid_get(index)
++
++
++static void tc_dma_process_isoc_urb(struct urb *urb);
++static void tc_dma_process_queue(int epid);
++static void tc_dma_unlink_intr_urb(struct urb *urb);
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc);
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc);
++
++static void tc_bulk_start_timer_func(unsigned long dummy);
++static void tc_bulk_eot_timer_func(unsigned long dummy);
++
++
++/*************************************************************/
++/*************************************************************/
++/* Host Controler Driver block */
++/*************************************************************/
++/*************************************************************/
++
++/* HCD operations */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void*);
++static int crisv10_hcd_reset(struct usb_hcd *);
++static int crisv10_hcd_start(struct usb_hcd *);
++static void crisv10_hcd_stop(struct usb_hcd *);
++#ifdef CONFIG_PM
++static int crisv10_hcd_suspend(struct device *, u32, u32);
++static int crisv10_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++static int crisv10_hcd_get_frame(struct usb_hcd *);
++
++static int tc_urb_enqueue(struct usb_hcd *, struct usb_host_endpoint *ep, struct urb *, gfp_t mem_flags);
++static int tc_urb_dequeue(struct usb_hcd *, struct urb *);
++static void tc_endpoint_disable(struct usb_hcd *, struct usb_host_endpoint *ep);
++
++static int rh_status_data_request(struct usb_hcd *, char *);
++static int rh_control_request(struct usb_hcd *, u16, u16, u16, char*, u16);
++
++#ifdef CONFIG_PM
++static int crisv10_hcd_hub_suspend(struct usb_hcd *);
++static int crisv10_hcd_hub_resume(struct usb_hcd *);
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++static int crisv10_hcd_start_port_reset(struct usb_hcd *, unsigned);
++#endif /* CONFIG_USB_OTG */
++
++/* host controller driver interface */
++static const struct hc_driver crisv10_hc_driver =
++ {
++ .description = hc_name,
++ .product_desc = product_desc,
++ .hcd_priv_size = sizeof(struct crisv10_hcd),
++
++ /* Attaching IRQ handler manualy in probe() */
++ /* .irq = crisv10_hcd_irq, */
++
++ .flags = HCD_USB11,
++
++ /* called to init HCD and root hub */
++ .reset = crisv10_hcd_reset,
++ .start = crisv10_hcd_start,
++
++ /* cleanly make HCD stop writing memory and doing I/O */
++ .stop = crisv10_hcd_stop,
++
++ /* return current frame number */
++ .get_frame_number = crisv10_hcd_get_frame,
++
++
++ /* Manage i/o requests via the Transfer Controller */
++ .urb_enqueue = tc_urb_enqueue,
++ .urb_dequeue = tc_urb_dequeue,
++
++ /* hw synch, freeing endpoint resources that urb_dequeue can't */
++ .endpoint_disable = tc_endpoint_disable,
++
++
++ /* Root Hub support */
++ .hub_status_data = rh_status_data_request,
++ .hub_control = rh_control_request,
++#ifdef CONFIG_PM
++ .hub_suspend = rh_suspend_request,
++ .hub_resume = rh_resume_request,
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++ .start_port_reset = crisv10_hcd_start_port_reset,
++#endif /* CONFIG_USB_OTG */
++ };
+
+-/* 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);
+-}
++/*
++ * conversion between pointers to a hcd and the corresponding
++ * crisv10_hcd
++ */
+
+-static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
++static inline struct crisv10_hcd *hcd_to_crisv10_hcd(struct usb_hcd *hcd)
+ {
+- 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);
++ return (struct crisv10_hcd *) hcd->hcd_priv;
+ }
+
+-
+-static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
++static inline struct usb_hcd *crisv10_hcd_to_hcd(struct crisv10_hcd *hcd)
+ {
+- 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);
++ return container_of((void *) hcd, struct usb_hcd, hcd_priv);
+ }
+
+-static inline void __dump_ep_list(int pipe_type)
++/* check if specified port is in use */
++static inline int port_in_use(unsigned int port)
+ {
+- 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);
++ return ports & (1 << port);
+ }
+
+-static inline void __dump_ept_data(int epid)
++/* number of ports in use */
++static inline unsigned int num_ports(void)
+ {
+- 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));
++ unsigned int i, num = 0;
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++ if (port_in_use(i))
++ num++;
++ return num;
+ }
+
+-static inline void __dump_ept_data_list(void)
++/* map hub port number to the port number used internally by the HC */
++static inline unsigned int map_port(unsigned int port)
+ {
+- int i;
+-
+- printk("Dumping the whole R_USB_EPT_DATA list\n");
+-
+- for (i = 0; i < 32; i++) {
+- __dump_ept_data(i);
+- }
++ unsigned int i, num = 0;
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++ if (port_in_use(i))
++ if (++num == port)
++ return i;
++ return -1;
+ }
+-#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)
++/* size of descriptors in slab cache */
++#ifndef MAX
++#define MAX(x, y) ((x) > (y) ? (x) : (y))
+ #endif
+
+-static void init_rx_buffers(void)
+-{
+- int i;
+
+- DBFENTER;
++/******************************************************************/
++/* Hardware Interrupt functions */
++/******************************************************************/
++
++/* Fast interrupt handler for HC */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void *vcd)
++{
++ struct usb_hcd *hcd = vcd;
++ struct crisv10_irq_reg reg;
++ __u32 irq_mask;
++ unsigned long flags;
++
++ DBFENTER;
++
++ ASSERT(hcd != NULL);
++ reg.hcd = hcd;
++
++ /* Turn of other interrupts while handling these sensitive cases */
++ local_irq_save(flags);
++
++ /* Read out which interrupts that are flaged */
++ irq_mask = *R_USB_IRQ_MASK_READ;
++ reg.r_usb_irq_mask_read = irq_mask;
++
++ /* 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. */
++ reg.r_usb_status = *R_USB_STATUS;
++
++ /* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn
++ interrupts. */
++ reg.r_usb_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. */
++ reg.r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1;
++ reg.r_usb_rh_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. */
++ reg.r_usb_fm_number = *R_USB_FM_NUMBER;
++
++ /* Interrupts are handled in order of priority. */
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
++ crisv10_hcd_port_status_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
++ crisv10_hcd_epid_attn_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
++ crisv10_hcd_ctl_status_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
++ crisv10_hcd_isoc_eof_irq(&reg);
++ }
++ 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);
++
++ /* Check for finished bulk transfers on epids */
++ check_finished_bulk_tx_epids(hcd, 0);
++ }
++ local_irq_restore(flags);
++
++ DBFEXIT;
++ return IRQ_HANDLED;
++}
++
++
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg) {
++ struct usb_hcd *hcd = reg->hcd;
++ struct crisv10_urb_priv *urb_priv;
++ int epid;
++ DBFENTER;
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
++ struct urb *urb;
++ __u32 ept_data;
++ int error_code;
++
++ if (epid == DUMMY_EPID || epid == INVALID_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 INVALID_EPID or DUMMY_EPID (%d).", epid);
++ continue;
++ }
++
++ if(!epid_inuse(epid)) {
++ irq_err("Epid attention on epid:%d that isn't in use\n", epid);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ debug_epid(epid);
++ continue;
++ }
++
++ /* 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. */
++ ept_data = etrax_epid_get(epid);
++ error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, ept_data);
++
++ /* Get the active URB for this epid. We blatantly assume
++ that only this URB could have caused the epid attention. */
++ urb = activeUrbList[epid];
++ if (urb == NULL) {
++ irq_err("Attention on epid:%d error:%d with no active URB.\n",
++ epid, error_code);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ debug_epid(epid);
++ continue;
++ }
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* 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, ept_data) == 3 ||
++ IO_EXTRACT(R_USB_EPT_DATA, error_count_out, ept_data) == 3)) {
++ /* Check if URB allready is marked for late-finish, we can get
++ several 3rd error for Intr traffic when a device is unplugged */
++ if(urb_priv->later_data == NULL) {
++ /* 3rd error. */
++ irq_warn("3rd error for epid:%d (%s %s) URB:0x%x[%d]\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe),
++ (unsigned int)urb, urb_priv->urb_num);
++
++ tc_finish_urb_later(hcd, urb, -EPROTO);
++ }
++
++ } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
++ irq_warn("Perror for epid:%d\n", epid);
++ printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
++
++ if (!(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. */
++ 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 */
++ printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
+
+- 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]);
++ panic("Buffer overrun/underrun for epid:%d. DMA too busy?", epid);
++ } else {
++ irq_warn("Attention on epid:%d (%s %s) with no error code\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(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");
+ }
+
+- 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;
++ tc_dbg("Stall for epid:%d (%s %s) URB:0x%x\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe), (unsigned int)urb);
++ tc_finish_urb(hcd, 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\n",
++ epid);
++
++ } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++ buffer_error)) {
++ /* DMA overrun or underrun. */
++ irq_warn("Buffer overrun/underrun for epid:%d (%s %s)\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++
++ /* 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. */
++ tc_finish_urb(hcd, urb, -EPROTO);
++ } else {
++ irq_warn("Unknown attention on epid:%d (%s %s)\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++ dump_ept_data(epid);
++ }
++ }
++ }
++ DBFEXIT;
++}
++
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg)
++{
++ __u16 port_reg[USB_ROOT_HUB_PORTS];
++ DBFENTER;
++ port_reg[0] = reg->r_usb_rh_port_status_1;
++ port_reg[1] = reg->r_usb_rh_port_status_2;
++ rh_port_status_change(port_reg);
++ DBFEXIT;
++}
++
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg)
++{
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv *urb_priv;
++
++ DBFENTER;
++
++ for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++
++ /* Only check epids that are in use, is valid and has SB list */
++ if (!epid_inuse(epid) || epid == INVALID_EPID ||
++ TxIsocEPList[epid].sub == 0 || epid == DUMMY_EPID) {
++ /* Nothing here to see. */
++ continue;
++ }
++ ASSERT(epid_isoc(epid));
++
++ /* Get the active URB for this epid (if any). */
++ urb = activeUrbList[epid];
++ if (urb == 0) {
++ isoc_warn("Ignoring NULL urb for epid:%d\n", epid);
++ continue;
++ }
++ if(!epid_out_traffic(epid)) {
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++
++ urb_priv = (struct crisv10_urb_priv *)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))) {
++ /* EP should not be enabled if we're waiting for start_frame */
++ ASSERT((TxIsocEPList[epid].command &
++ IO_STATE(USB_EP_command, enable, yes)) == 0);
++
++ isoc_warn("Enabling isoc IN EP descr for epid %d\n", epid);
++ TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ /* This urb is now active. */
++ urb_priv->urb_state = STARTED;
++ continue;
++ }
++ }
++ }
++ }
++
++ DBFEXIT;
++}
++
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg)
++{
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(reg->hcd);
++
++ DBFENTER;
++ ASSERT(crisv10_hcd);
++
++ irq_dbg("ctr_status_irq, controller status: %s\n",
++ hcd_status_to_str(reg->r_usb_status));
++
++ /* 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.");
++ }
++
++ /* Keep track of USB Controller, if it's running or not */
++ if(reg->r_usb_status & IO_STATE(R_USB_STATUS, running, yes)) {
++ crisv10_hcd->running = 1;
++ } else {
++ crisv10_hcd->running = 0;
++ }
++
++ 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.");
++ }
++
++ /* Set the flag to avoid getting "Unlink after no-IRQ? Controller is probably
++ using the wrong IRQ" from hcd_unlink_urb() in drivers/usb/core/hcd.c */
++ set_bit(HCD_FLAG_SAW_IRQ, &reg->hcd->flags);
++
++ DBFEXIT;
++}
++
++
++/******************************************************************/
++/* Host Controller interface functions */
++/******************************************************************/
++
++static inline void crisv10_ready_wait(void) {
++ volatile int timeout = 10000;
++ /* Check the busy bit of USB controller in Etrax */
++ while((*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for USB controller to be idle\n");
++ }
++}
++
++/* reset host controller */
++static int crisv10_hcd_reset(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "reset\n");
++
++
++ /* 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);
++ nop();
++ */
++ DBFEXIT;
++ return 0;
++}
++
++/* start host controller */
++static int crisv10_hcd_start(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "start\n");
++
++ crisv10_ready_wait();
++
++ /* 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);
++
++ nop();
++
++ hcd->state = HC_STATE_RUNNING;
++
++ DBFEXIT;
++ return 0;
++}
++
++/* stop host controller */
++static void crisv10_hcd_stop(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "stop\n");
++ crisv10_hcd_reset(hcd);
++ DBFEXIT;
++}
++
++/* return the current frame number */
++static int crisv10_hcd_get_frame(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ DBFEXIT;
++ return (*R_USB_FM_NUMBER & 0x7ff);
++}
++
++#ifdef CONFIG_USB_OTG
++
++static int crisv10_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
++{
++ return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_USB_OTG */
++
++
++/******************************************************************/
++/* Root Hub functions */
++/******************************************************************/
++
++/* root hub status */
++static const struct usb_hub_status rh_hub_status =
++ {
++ .wHubStatus = 0,
++ .wHubChange = 0,
++ };
++
++/* root hub descriptor */
++static const u8 rh_hub_descr[] =
++ {
++ 0x09, /* bDescLength */
++ 0x29, /* bDescriptorType */
++ USB_ROOT_HUB_PORTS, /* bNbrPorts */
++ 0x00, /* wHubCharacteristics */
++ 0x00,
++ 0x01, /* bPwrOn2pwrGood */
++ 0x00, /* bHubContrCurrent */
++ 0x00, /* DeviceRemovable */
++ 0xff /* PortPwrCtrlMask */
++ };
++
++/* Actual holder of root hub status*/
++struct crisv10_rh rh;
++
++/* Initialize root hub data structures (called from dvdrv_hcd_probe()) */
++int rh_init(void) {
++ int i;
++ /* Reset port status flags */
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++ rh.wPortChange[i] = 0;
++ rh.wPortStatusPrev[i] = 0;
++ }
++ return 0;
++}
++
++#define RH_FEAT_MASK ((1<<USB_PORT_FEAT_CONNECTION)|\
++ (1<<USB_PORT_FEAT_ENABLE)|\
++ (1<<USB_PORT_FEAT_SUSPEND)|\
++ (1<<USB_PORT_FEAT_RESET))
++
++/* Handle port status change interrupt (called from bottom part interrupt) */
++void rh_port_status_change(__u16 port_reg[]) {
++ int i;
++ __u16 wChange;
++
++ for(i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++ /* Xor out changes since last read, masked for important flags */
++ wChange = (port_reg[i] & RH_FEAT_MASK) ^ rh.wPortStatusPrev[i];
++ /* Or changes together with (if any) saved changes */
++ rh.wPortChange[i] |= wChange;
++ /* Save new status */
++ rh.wPortStatusPrev[i] = port_reg[i];
++
++ if(wChange) {
++ rh_dbg("Interrupt port_status change port%d: %s Current-status:%s\n", i+1,
++ port_status_to_str(wChange),
++ port_status_to_str(port_reg[i]));
++ }
++ }
++}
++
++/* Construct port status change bitmap for the root hub */
++static int rh_status_data_request(struct usb_hcd *hcd, char *buf)
++{
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ unsigned int i;
++
++ DBFENTER;
++ /*
++ * corresponds to hub status change EP (USB 2.0 spec section 11.13.4)
++ * return bitmap indicating ports with status change
++ */
++ *buf = 0;
++ spin_lock(&crisv10_hcd->lock);
++ for (i = 1; i <= crisv10_hcd->num_ports; i++) {
++ if (rh.wPortChange[map_port(i)]) {
++ *buf |= (1 << i);
++ rh_dbg("rh_status_data_request, change on port %d: %s Current Status: %s\n", i,
++ port_status_to_str(rh.wPortChange[map_port(i)]),
++ port_status_to_str(rh.wPortStatusPrev[map_port(i)]));
++ }
++ }
++ spin_unlock(&crisv10_hcd->lock);
++ DBFEXIT;
++ return *buf == 0 ? 0 : 1;
++}
++
++/* Handle a control request for the root hub (called from hcd_driver) */
++static int rh_control_request(struct usb_hcd *hcd,
++ u16 typeReq,
++ u16 wValue,
++ u16 wIndex,
++ char *buf,
++ u16 wLength) {
++
++ struct crisv10_hcd *crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ int retval = 0;
++ int len;
++ DBFENTER;
++
++ switch (typeReq) {
++ case GetHubDescriptor:
++ rh_dbg("GetHubDescriptor\n");
++ len = min_t(unsigned int, sizeof rh_hub_descr, wLength);
++ memcpy(buf, rh_hub_descr, len);
++ buf[2] = crisv10_hcd->num_ports;
++ break;
++ case GetHubStatus:
++ rh_dbg("GetHubStatus\n");
++ len = min_t(unsigned int, sizeof rh_hub_status, wLength);
++ memcpy(buf, &rh_hub_status, len);
++ break;
++ case GetPortStatus:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ rh_dbg("GetportStatus, port:%d change:%s status:%s\n", wIndex,
++ port_status_to_str(rh.wPortChange[map_port(wIndex)]),
++ port_status_to_str(rh.wPortStatusPrev[map_port(wIndex)]));
++ *(u16 *) buf = cpu_to_le16(rh.wPortStatusPrev[map_port(wIndex)]);
++ *(u16 *) (buf + 2) = cpu_to_le16(rh.wPortChange[map_port(wIndex)]);
++ break;
++ case SetHubFeature:
++ rh_dbg("SetHubFeature\n");
++ case ClearHubFeature:
++ rh_dbg("ClearHubFeature\n");
++ switch (wValue) {
++ case C_HUB_OVER_CURRENT:
++ case C_HUB_LOCAL_POWER:
++ rh_warn("Not implemented hub request:%d \n", typeReq);
++ /* not implemented */
++ break;
++ default:
++ goto error;
++ }
++ break;
++ case SetPortFeature:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ if(rh_set_port_feature(map_port(wIndex), wValue))
++ goto error;
++ break;
++ case ClearPortFeature:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ if(rh_clear_port_feature(map_port(wIndex), wValue))
++ goto error;
++ break;
++ default:
++ rh_warn("Unknown hub request: %d\n", typeReq);
++ error:
++ retval = -EPIPE;
++ }
++ DBFEXIT;
++ return retval;
++}
++
++int rh_set_port_feature(__u8 bPort, __u16 wFeature) {
++ __u8 bUsbCommand = 0;
++ switch(wFeature) {
++ case USB_PORT_FEAT_RESET:
++ rh_dbg("SetPortFeature: reset\n");
++ bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, reset);
++ goto set;
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ rh_dbg("SetPortFeature: suspend\n");
++ bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, suspend);
++ goto set;
++ break;
++ case USB_PORT_FEAT_POWER:
++ rh_dbg("SetPortFeature: power\n");
++ break;
++ case USB_PORT_FEAT_C_CONNECTION:
++ rh_dbg("SetPortFeature: c_connection\n");
++ break;
++ case USB_PORT_FEAT_C_RESET:
++ rh_dbg("SetPortFeature: c_reset\n");
++ break;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ rh_dbg("SetPortFeature: c_over_current\n");
++ break;
++
++ set:
++ /* Select which port via the port_sel field */
++ bUsbCommand |= IO_FIELD(R_USB_COMMAND, port_sel, bPort+1);
++
++ /* Make sure the controller isn't busy. */
++ crisv10_ready_wait();
++ /* Send out the actual command to the USB controller */
++ *R_USB_COMMAND = bUsbCommand;
++
++ /* If port reset then also bring USB controller into running state */
++ if(wFeature == USB_PORT_FEAT_RESET) {
++ /* Wait a while for controller to first become started after port reset */
++ udelay(12000); /* 12ms blocking wait */
++
++ /* Make sure the controller isn't busy. */
++ crisv10_ready_wait();
++
++ /* 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);
++ }
++
++ break;
++ default:
++ rh_dbg("SetPortFeature: unknown feature\n");
++ return -1;
++ }
++ return 0;
++}
++
++int rh_clear_port_feature(__u8 bPort, __u16 wFeature) {
++ switch(wFeature) {
++ case USB_PORT_FEAT_ENABLE:
++ rh_dbg("ClearPortFeature: enable\n");
++ rh_disable_port(bPort);
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ rh_dbg("ClearPortFeature: suspend\n");
++ break;
++ case USB_PORT_FEAT_POWER:
++ rh_dbg("ClearPortFeature: power\n");
++ break;
++
++ case USB_PORT_FEAT_C_ENABLE:
++ rh_dbg("ClearPortFeature: c_enable\n");
++ goto clear;
++ case USB_PORT_FEAT_C_SUSPEND:
++ rh_dbg("ClearPortFeature: c_suspend\n");
++ goto clear;
++ case USB_PORT_FEAT_C_CONNECTION:
++ rh_dbg("ClearPortFeature: c_connection\n");
++ goto clear;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ rh_dbg("ClearPortFeature: c_over_current\n");
++ goto clear;
++ case USB_PORT_FEAT_C_RESET:
++ rh_dbg("ClearPortFeature: c_reset\n");
++ goto clear;
++ clear:
++ rh.wPortChange[bPort] &= ~(1 << (wFeature - 16));
++ break;
++ default:
++ rh_dbg("ClearPortFeature: unknown feature\n");
++ return -1;
++ }
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++/* Handle a suspend request for the root hub (called from hcd_driver) */
++static int rh_suspend_request(struct usb_hcd *hcd)
++{
++ return 0; /* no-op for now */
++}
++
++/* Handle a resume request for the root hub (called from hcd_driver) */
++static int rh_resume_request(struct usb_hcd *hcd)
++{
++ return 0; /* no-op for now */
++}
++#endif /* CONFIG_PM */
++
++
++
++/* Wrapper function for workaround port disable registers in USB controller */
++static void rh_disable_port(unsigned int port) {
++ volatile int timeout = 10000;
++ volatile char* usb_portx_disable;
++ switch(port) {
++ case 0:
++ usb_portx_disable = R_USB_PORT1_DISABLE;
++ break;
++ case 1:
++ usb_portx_disable = R_USB_PORT2_DISABLE;
++ break;
++ default:
++ /* Invalid port index */
++ return;
++ }
++ /* Set disable flag in special register */
++ *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++ /* Wait until not enabled anymore */
++ while((rh.wPortStatusPrev[port] &
++ IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for port %d to become disabled\n", port);
++ }
++ /* clear disable flag in special register */
++ *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++ rh_info("Physical port %d disabled\n", port+1);
++}
++
++
++/******************************************************************/
++/* Transfer Controller (TC) functions */
++/******************************************************************/
++
++/* 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)
+
+- 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);
++/* Local variables for Transfer Controller */
++/* --------------------------------------- */
+
+- DBFEXIT;
+-}
++/* 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 (which includes spin_locks) */
++static struct list_head urb_list[NBR_OF_EPIDS];
+
+-static void init_tx_bulk_ep(void)
+-{
+- int i;
++/* Read about the need and usage of this lock in submit_ctrl_urb. */
++/* Lock for URB lists for each EPID */
++static spinlock_t urb_list_lock;
+
+- DBFENTER;
++/* Lock for EPID array register (R_USB_EPT_x) in Etrax */
++static spinlock_t etrax_epid_lock;
+
+- 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]);
+- }
++/* Lock for dma8 sub0 handling */
++static spinlock_t etrax_dma8_sub0_lock;
+
+- /* 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;
+-}
++/* 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 struct USB_IN_Desc RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
+
+-static void init_tx_ctrl_ep(void)
+-{
+- int i;
++/* Pointers into RxDescList. */
++static volatile struct USB_IN_Desc *myNextRxDesc;
++static volatile struct USB_IN_Desc *myLastRxDesc;
+
+- DBFENTER;
++/* 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)));
+
+- 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]);
+- }
++/* Cache for allocating new EP and SB descriptors. */
++static kmem_cache_t *usb_desc_cache;
+
+- 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));
++/* Cache for the data allocated in the isoc descr top half. */
++static kmem_cache_t *isoc_compl_cache;
+
+- TxCtrlEPList[i].sub = 0;
+- TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
++/* Cache for the data allocated when delayed finishing of URBs */
++static kmem_cache_t *later_data_cache;
+
+- *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;
++/* Counter to keep track of how many Isoc EP we have sat up. Used to enable
++ and disable iso_eof interrupt. We only need these interrupts when we have
++ Isoc data endpoints (consumes CPU cycles).
++ FIXME: This could be more fine granular, so this interrupt is only enabled
++ when we have a In Isoc URB not URB_ISO_ASAP flaged queued. */
++static int isoc_epid_counter;
++
++/* Protecting wrapper functions for R_USB_EPT_x */
++/* -------------------------------------------- */
++static inline void etrax_epid_set(__u8 index, __u32 data) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ *R_USB_EPT_DATA = data;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_clear_error(__u8 index) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ *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, error_code));
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++ __u8 toggle) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ if(dirout) {
++ *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 {
++ *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);
++ }
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout) {
++ unsigned long flags;
++ __u8 toggle;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ if (dirout) {
++ toggle = IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
++ } else {
++ toggle = IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
++ }
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++ return toggle;
++}
++
++
++static inline __u32 etrax_epid_get(__u8 index) {
++ unsigned long flags;
++ __u32 data;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ data = *R_USB_EPT_DATA;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++ return data;
++}
++
++
++
++
++/* Main functions for Transfer Controller */
++/* -------------------------------------- */
++
++/* Init structs, memories and lists used by Transfer Controller */
++int tc_init(struct usb_hcd *hcd) {
++ int i;
++ /* Clear software state info for all epids */
++ memset(epid_state, 0, sizeof(struct etrax_epid) * NBR_OF_EPIDS);
++
++ /* Set Invalid and Dummy as being in use and disabled */
++ epid_state[INVALID_EPID].inuse = 1;
++ epid_state[DUMMY_EPID].inuse = 1;
++ epid_state[INVALID_EPID].disabled = 1;
++ epid_state[DUMMY_EPID].disabled = 1;
++
++ /* Clear counter for how many Isoc epids we have sat up */
++ isoc_epid_counter = 0;
++
++ /* Initialize the urb list by initiating a head for each list.
++ Also reset list hodling active URB for each epid */
++ for (i = 0; i < NBR_OF_EPIDS; i++) {
++ INIT_LIST_HEAD(&urb_list[i]);
++ activeUrbList[i] = NULL;
++ }
++
++ /* Init lock for URB lists */
++ spin_lock_init(&urb_list_lock);
++ /* Init lock for Etrax R_USB_EPT register */
++ spin_lock_init(&etrax_epid_lock);
++ /* Init lock for Etrax dma8 sub0 handling */
++ spin_lock_init(&etrax_dma8_sub0_lock);
++
++ /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
++
++ /* Note that we specify sizeof(struct USB_EP_Desc) as the size, but also
++ allocate SB descriptors from this cache. This is ok since
++ sizeof(struct USB_EP_Desc) == sizeof(struct USB_SB_Desc). */
++ usb_desc_cache = kmem_cache_create("usb_desc_cache",
++ sizeof(struct USB_EP_Desc), 0,
++ SLAB_HWCACHE_ALIGN, 0, 0);
++ if(usb_desc_cache == NULL) {
++ return -ENOMEM;
++ }
++
++ /* Create slab cache for speedy allocation of memory for isoc bottom-half
++ interrupt handling */
++ isoc_compl_cache =
++ kmem_cache_create("isoc_compl_cache",
++ sizeof(struct crisv10_isoc_complete_data),
++ 0, SLAB_HWCACHE_ALIGN, 0, 0);
++ if(isoc_compl_cache == NULL) {
++ return -ENOMEM;
++ }
++
++ /* Create slab cache for speedy allocation of memory for later URB finish
++ struct */
++ later_data_cache =
++ kmem_cache_create("later_data_cache",
++ sizeof(struct urb_later_data),
++ 0, SLAB_HWCACHE_ALIGN, 0, 0);
++ if(later_data_cache == NULL) {
++ return -ENOMEM;
++ }
++
++
++ /* Initiate the bulk start timer. */
++ init_timer(&bulk_start_timer);
++ bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
++ bulk_start_timer.function = tc_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 = tc_bulk_eot_timer_func;
++ bulk_eot_timer.data = (unsigned long)hcd;
++ add_timer(&bulk_eot_timer);
++
++ return 0;
++}
++
++/* Uninitialize all resources used by Transfer Controller */
++void tc_destroy(void) {
++
++ /* Destroy all slab cache */
++ kmem_cache_destroy(usb_desc_cache);
++ kmem_cache_destroy(isoc_compl_cache);
++ kmem_cache_destroy(later_data_cache);
++
++ /* Remove timers */
++ del_timer(&bulk_start_timer);
++ del_timer(&bulk_eot_timer);
++}
++
++static void restart_dma8_sub0(void) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_dma8_sub0_lock, flags);
++ /* Verify that the dma is not running */
++ if ((*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd)) == 0) {
++ struct USB_EP_Desc *ep = (struct USB_EP_Desc *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
++ while (DUMMY_EPID == IO_EXTRACT(USB_EP_command, epid, ep->command)) {
++ ep = (struct USB_EP_Desc *)phys_to_virt(ep->next);
++ }
++ /* Advance the DMA to the next EP descriptor that is not a DUMMY_EPID.
++ * ep->next is already a physical address; no need for a virt_to_phys. */
++ *R_DMA_CH8_SUB0_EP = ep->next;
++ /* Restart the DMA */
++ *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
++ }
++ spin_unlock_irqrestore(&etrax_dma8_sub0_lock, flags);
++}
++
++/* queue an URB with the transfer controller (called from hcd_driver) */
++static int tc_urb_enqueue(struct usb_hcd *hcd,
++ struct usb_host_endpoint *ep,
++ struct urb *urb,
++ gfp_t mem_flags) {
++ int epid;
++ int retval;
++ int bustime = 0;
++ int maxpacket;
++ unsigned long flags;
++ struct crisv10_urb_priv *urb_priv;
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ DBFENTER;
++
++ if(!(crisv10_hcd->running)) {
++ /* The USB Controller is not running, probably because no device is
++ attached. No idea to enqueue URBs then */
++ tc_warn("Rejected enqueueing of URB:0x%x because no dev attached\n",
++ (unsigned int)urb);
++ return -ENOENT;
++ }
++
++ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++ /* Special case check for In Isoc transfers. Specification states that each
++ In Isoc transfer consists of one packet and therefore it should fit into
++ the transfer-buffer of an URB.
++ We do the check here to be sure (an invalid scenario can be produced with
++ parameters to the usbtest suite) */
++ if(usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe) &&
++ (urb->transfer_buffer_length < maxpacket)) {
++ tc_err("Submit In Isoc URB with buffer length:%d to pipe with maxpacketlen: %d\n", urb->transfer_buffer_length, maxpacket);
++ return -EMSGSIZE;
++ }
++
++ /* Check if there is enough bandwidth for periodic transfer */
++ if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe)) {
++ /* only check (and later claim) if not already claimed */
++ if (urb->bandwidth == 0) {
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0) {
++ tc_err("Not enough periodic bandwidth\n");
++ return -ENOSPC;
++ }
++ }
++ }
++
++ /* Check if there is a epid for URBs destination, if not this function
++ set up one. */
++ epid = tc_setup_epid(ep, urb, mem_flags);
++ if (epid < 0) {
++ tc_err("Failed setup epid:%d for URB:0x%x\n", epid, (unsigned int)urb);
++ DBFEXIT;
++ return -ENOMEM;
++ }
++
++ if(urb == activeUrbList[epid]) {
++ tc_err("Resubmition of allready active URB:0x%x\n", (unsigned int)urb);
++ return -ENXIO;
++ }
++
++ if(urb_list_entry(urb, epid)) {
++ tc_err("Resubmition of allready queued URB:0x%x\n", (unsigned int)urb);
++ return -ENXIO;
++ }
++
++ /* If we actively have flaged endpoint as disabled then refuse submition */
++ if(epid_state[epid].disabled) {
++ return -ENOENT;
++ }
++
++ /* Allocate and init HC-private data for URB */
++ if(urb_priv_create(hcd, urb, epid, mem_flags) != 0) {
++ DBFEXIT;
++ return -ENOMEM;
++ }
++ urb_priv = urb->hcpriv;
++
++ tc_dbg("Enqueue URB:0x%x[%d] epid:%d (%s) bufflen:%d\n",
++ (unsigned int)urb, urb_priv->urb_num, epid,
++ pipe_to_str(urb->pipe), urb->transfer_buffer_length);
++
++ /* Create and link SBs required for this URB */
++ retval = create_sb_for_urb(urb, mem_flags);
++ if(retval != 0) {
++ tc_err("Failed to create SBs for URB:0x%x[%d]\n", (unsigned int)urb,
++ urb_priv->urb_num);
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++
++ /* Init intr EP pool if this URB is a INTR transfer. This pool is later
++ used when inserting EPs in the TxIntrEPList. We do the alloc here
++ so we can't run out of memory later */
++ if(usb_pipeint(urb->pipe)) {
++ retval = init_intr_urb(urb, mem_flags);
++ if(retval != 0) {
++ tc_warn("Failed to init Intr URB\n");
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++ }
++
++ /* Disable other access when inserting USB */
++ local_irq_save(flags);
++
++ /* Claim bandwidth, if needed */
++ if(bustime) {
++ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
++ }
++
++ /* Add URB to EP queue */
++ urb_list_add(urb, epid, mem_flags);
++
++ if(usb_pipeisoc(urb->pipe)) {
++ /* Special processing of Isoc URBs. */
++ tc_dma_process_isoc_urb(urb);
++ } else {
++ /* Process EP queue for rest of the URB types (Bulk, Ctrl, Intr) */
++ tc_dma_process_queue(epid);
++ }
++
++ local_irq_restore(flags);
++
++ DBFEXIT;
++ return 0;
++}
++
++/* remove an URB from the transfer controller queues (called from hcd_driver)*/
++static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv;
++ unsigned long flags;
++ int epid;
++
++ DBFENTER;
++ /* Disable interrupts here since a descriptor interrupt for the isoc epid
++ will modify the sb list. This could possibly be done more granular, but
++ urb_dequeue should not be used frequently anyway.
++ */
++ local_irq_save(flags);
++
++ urb_priv = urb->hcpriv;
++
++ if (!urb_priv) {
++ /* This happens if a device driver calls unlink on an urb that
++ was never submitted (lazy driver) or if the urb was completed
++ while dequeue was being called. */
++ tc_warn("Dequeing of not enqueued URB:0x%x\n", (unsigned int)urb);
++ local_irq_restore(flags);
++ return 0;
++ }
++ epid = urb_priv->epid;
++
++ tc_warn("Dequeing %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ /* For Bulk, Ctrl and Intr are only one URB active at a time. So any URB
++ that isn't active can be dequeued by just removing it from the queue */
++ if(usb_pipebulk(urb->pipe) || usb_pipecontrol(urb->pipe) ||
++ usb_pipeint(urb->pipe)) {
++
++ /* Check if URB haven't gone further than the queue */
++ if(urb != activeUrbList[epid]) {
++ ASSERT(urb_priv->later_data == NULL);
++ tc_warn("Dequeing URB:0x%x[%d] (%s %s epid:%d) from queue"
++ " (not active)\n", (unsigned int)urb, urb_priv->urb_num,
++ str_dir(urb->pipe), str_type(urb->pipe), epid);
++
++ /* Finish the URB with error status from USB core */
++ tc_finish_urb(hcd, urb, urb->status);
++ local_irq_restore(flags);
++ return 0;
++ }
++ }
++
++ /* Set URB status to Unlink for handling when interrupt comes. */
++ urb_priv->urb_state = UNLINK;
++
++ /* Differentiate dequeing of Bulk and Ctrl from Isoc and Intr */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Check if EP still is enabled */
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ /* Kicking dummy list out of the party. */
++ TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
++ break;
++ case PIPE_CONTROL:
++ /* Check if EP still is enabled */
++ if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ break;
++ case PIPE_ISOCHRONOUS:
++ /* Disabling, busy-wait and unlinking of Isoc SBs will be done in
++ finish_isoc_urb(). Because there might the case when URB is dequeued
++ but there are other valid URBs waiting */
++
++ /* Check if In Isoc EP still is enabled */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ break;
++ case PIPE_INTERRUPT:
++ /* Special care is taken for interrupt URBs. EPs are unlinked in
++ tc_finish_urb */
++ break;
++ default:
++ break;
++ }
++
++ /* Asynchronous unlink, finish the URB later from scheduled or other
++ event (data finished, error) */
++ tc_finish_urb_later(hcd, urb, urb->status);
++
++ local_irq_restore(flags);
++ DBFEXIT;
++ return 0;
++}
++
++
++static void tc_sync_finish_epid(struct usb_hcd *hcd, int epid) {
++ volatile int timeout = 10000;
++ struct urb* urb;
++ struct crisv10_urb_priv* urb_priv;
++ unsigned long flags;
++
++ volatile struct USB_EP_Desc *first_ep; /* First EP in the list. */
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++
++ int type = epid_state[epid].type;
++
++ /* Setting this flag will cause enqueue() to return -ENOENT for new
++ submitions on this endpoint and finish_urb() wont process queue further */
++ epid_state[epid].disabled = 1;
++
++ switch(type) {
++ case PIPE_BULK:
++ /* Check if EP still is enabled */
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++ /* Do busy-wait until DMA not using this EP descriptor anymore */
++ while((*R_DMA_CH8_SUB0_EP ==
++ virt_to_phys(&TxBulkEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Bulk to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++
++ case PIPE_CONTROL:
++ /* Check if EP still is enabled */
++ if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++ /* Do busy-wait until DMA not using this EP descriptor anymore */
++ while((*R_DMA_CH8_SUB1_EP ==
++ virt_to_phys(&TxCtrlEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Ctrl to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++
++ case PIPE_INTERRUPT:
++ local_irq_save(flags);
++ /* Disable all Intr EPs belonging to epid */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* Disable EP */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++ local_irq_restore(flags);
++ break;
++
++ case PIPE_ISOCHRONOUS:
++ /* Check if EP still is enabled */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ tc_warn("sync_finish: Disabling Isoc EP for epid:%d\n", epid);
++ /* The EP was enabled, disable it. */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++
++ while((*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Isoc to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++ }
++
++ local_irq_save(flags);
++
++ /* Finish if there is active URB for this endpoint */
++ if(activeUrbList[epid] != NULL) {
++ urb = activeUrbList[epid];
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv);
++ tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ tc_finish_urb(hcd, activeUrbList[epid], -ENOENT);
++ ASSERT(activeUrbList[epid] == NULL);
++ }
++
++ /* Finish any queued URBs for this endpoint. There won't be any resubmitions
++ because epid_disabled causes enqueue() to fail for this endpoint */
++ while((urb = urb_list_first(epid)) != NULL) {
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv);
++
++ tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ tc_finish_urb(hcd, urb, -ENOENT);
++ }
++ epid_state[epid].disabled = 0;
++ local_irq_restore(flags);
++}
++
++/* free resources associated with an endpoint (called from hcd_driver) */
++static void tc_endpoint_disable(struct usb_hcd *hcd,
++ struct usb_host_endpoint *ep) {
++ DBFENTER;
++ /* Only free epid if it has been allocated. We get two endpoint_disable
++ requests for ctrl endpoints so ignore the second one */
++ if(ep->hcpriv != NULL) {
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ int epid = ep_priv->epid;
++ tc_warn("endpoint_disable ep:0x%x ep-priv:0x%x (%s) (epid:%d freed)\n",
++ (unsigned int)ep, (unsigned int)ep->hcpriv,
++ endpoint_to_str(&(ep->desc)), epid);
++
++ tc_sync_finish_epid(hcd, epid);
++
++ ASSERT(activeUrbList[epid] == NULL);
++ ASSERT(list_empty(&urb_list[epid]));
++
++ tc_free_epid(ep);
++ } else {
++ tc_dbg("endpoint_disable ep:0x%x ep-priv:0x%x (%s)\n", (unsigned int)ep,
++ (unsigned int)ep->hcpriv, endpoint_to_str(&(ep->desc)));
++ }
++ DBFEXIT;
++}
++
++static void tc_finish_urb_later_proc(void *data) {
++ unsigned long flags;
++ struct urb_later_data* uld = (struct urb_later_data*)data;
++ local_irq_save(flags);
++ if(uld->urb == NULL) {
++ late_dbg("Later finish of URB = NULL (allready finished)\n");
++ } else {
++ struct crisv10_urb_priv* urb_priv = uld->urb->hcpriv;
++ ASSERT(urb_priv);
++ if(urb_priv->urb_num == uld->urb_num) {
++ late_dbg("Later finish of URB:0x%x[%d]\n", (unsigned int)(uld->urb),
++ urb_priv->urb_num);
++ if(uld->status != uld->urb->status) {
++ errno_dbg("Later-finish URB with status:%d, later-status:%d\n",
++ uld->urb->status, uld->status);
++ }
++ if(uld != urb_priv->later_data) {
++ panic("Scheduled uld not same as URBs uld\n");
++ }
++ tc_finish_urb(uld->hcd, uld->urb, uld->status);
++ } else {
++ late_warn("Ignoring later finish of URB:0x%x[%d]"
++ ", urb_num doesn't match current URB:0x%x[%d]",
++ (unsigned int)(uld->urb), uld->urb_num,
++ (unsigned int)(uld->urb), urb_priv->urb_num);
++ }
++ }
++ local_irq_restore(flags);
++ kmem_cache_free(later_data_cache, uld);
++}
++
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++ int status) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ struct urb_later_data* uld;
++
++ ASSERT(urb_priv);
++
++ if(urb_priv->later_data != NULL) {
++ /* Later-finish allready scheduled for this URB, just update status to
++ return when finishing later */
++ errno_dbg("Later-finish schedule change URB status:%d with new"
++ " status:%d\n", urb_priv->later_data->status, status);
++
++ urb_priv->later_data->status = status;
++ return;
++ }
++
++ uld = kmem_cache_alloc(later_data_cache, SLAB_ATOMIC);
++ ASSERT(uld);
++
++ uld->hcd = hcd;
++ uld->urb = urb;
++ uld->urb_num = urb_priv->urb_num;
++ uld->status = status;
++
++ INIT_WORK(&uld->ws, tc_finish_urb_later_proc, uld);
++ urb_priv->later_data = uld;
++
++ /* Schedule the finishing of the URB to happen later */
++ schedule_delayed_work(&uld->ws, LATER_TIMER_DELAY);
++}
++
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++ int status);
++
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status) {
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid;
++ char toggle;
++ int urb_num;
++
++ DBFENTER;
++ ASSERT(urb_priv != NULL);
++ epid = urb_priv->epid;
++ urb_num = urb_priv->urb_num;
++
++ if(urb != activeUrbList[epid]) {
++ if(urb_list_entry(urb, epid)) {
++ /* Remove this URB from the list. Only happens when URB are finished
++ before having been processed (dequeing) */
++ urb_list_del(urb, epid);
++ } else {
++ tc_warn("Finishing of URB:0x%x[%d] neither active or in queue for"
++ " epid:%d\n", (unsigned int)urb, urb_num, epid);
++ }
++ }
++
++ /* Cancel any pending later-finish of this URB */
++ if(urb_priv->later_data) {
++ urb_priv->later_data->urb = NULL;
++ }
++
++ /* 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. */
++ if (status == 0 && urb->status == -EINPROGRESS) {
++ urb->actual_length = urb->transfer_buffer_length;
++ } else {
++ /* We wouldn't know of any partial writes if there was an error. */
++ urb->actual_length = 0;
++ }
++ }
++
++
++ /* URB status mangling */
++ if(urb->status == -EINPROGRESS) {
++ /* The USB core hasn't changed the status, let's set our finish status */
++ urb->status = status;
++
++ if ((status == 0) && (urb->transfer_flags & URB_SHORT_NOT_OK) &&
++ usb_pipein(urb->pipe) &&
++ (urb->actual_length != urb->transfer_buffer_length)) {
++ /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's
++ max length) is to be treated as an error. */
++ errno_dbg("Finishing URB:0x%x[%d] with SHORT_NOT_OK flag and short"
++ " data:%d\n", (unsigned int)urb, urb_num,
++ urb->actual_length);
++ urb->status = -EREMOTEIO;
++ }
++
++ if(urb_priv->urb_state == UNLINK) {
++ /* URB has been requested to be unlinked asynchronously */
++ urb->status = -ECONNRESET;
++ errno_dbg("Fixing unlink status of URB:0x%x[%d] to:%d\n",
++ (unsigned int)urb, urb_num, urb->status);
++ }
++ } else {
++ /* The USB Core wants to signal some error via the URB, pass it through */
++ }
++
++ /* use completely different finish function for Isoc URBs */
++ if(usb_pipeisoc(urb->pipe)) {
++ tc_finish_isoc_urb(hcd, urb, status);
++ return;
++ }
++
++ /* Do special unlinking of EPs for Intr traffic */
++ if(usb_pipeint(urb->pipe)) {
++ tc_dma_unlink_intr_urb(urb);
++ }
++
++ /* Release allocated bandwidth for periodic transfers */
++ if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe))
++ usb_release_bandwidth(urb->dev, urb, 0);
++
++ /* This URB is active on EP */
++ if(urb == activeUrbList[epid]) {
++ /* We need to fiddle with the toggle bits because the hardware doesn't do
++ it for us. */
++ toggle = etrax_epid_get_toggle(epid, usb_pipeout(urb->pipe));
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), toggle);
++
++ /* Checks for Ctrl and Bulk EPs */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Check so Bulk EP realy is disabled before finishing active URB */
++ ASSERT((TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++ IO_STATE(USB_EP_command, enable, no));
++ /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++ process Bulk EP. */
++ TxBulkEPList[epid].sub = 0;
++ /* 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]);
++ break;
++ case PIPE_CONTROL:
++ /* Check so Ctrl EP realy is disabled before finishing active URB */
++ ASSERT((TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++ IO_STATE(USB_EP_command, enable, no));
++ /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++ process Ctrl EP. */
++ TxCtrlEPList[epid].sub = 0;
++ break;
++ }
++ }
++
++ /* Free HC-private URB data*/
++ urb_priv_free(hcd, urb);
++
++ if(urb->status) {
++ errno_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++ (unsigned int)urb, urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb->actual_length, urb->status);
++ } else {
++ tc_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++ (unsigned int)urb, urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb->actual_length, urb->status);
++ }
++
++ /* If we just finished an active URB, clear active pointer. */
++ if (urb == activeUrbList[epid]) {
++ /* Make URB not active on EP anymore */
++ activeUrbList[epid] = NULL;
++
++ if(urb->status == 0) {
++ /* URB finished sucessfully, process queue to see if there are any more
++ URBs waiting before we call completion function.*/
++ if(crisv10_hcd->running) {
++ /* Only process queue if USB controller is running */
++ tc_dma_process_queue(epid);
++ } else {
++ tc_warn("No processing of queue for epid:%d, USB Controller not"
++ " running\n", epid);
++ }
++ }
++ }
++
++ /* Hand the URB from HCD to its USB device driver, using its completion
++ functions */
++ usb_hcd_giveback_urb (hcd, urb);
++
++ /* Check the queue once more if the URB returned with error, because we
++ didn't do it before the completion function because the specification
++ states that the queue should not restart until all it's unlinked
++ URBs have been fully retired, with the completion functions run */
++ if(crisv10_hcd->running) {
++ /* Only process queue if USB controller is running */
++ tc_dma_process_queue(epid);
++ } else {
++ tc_warn("No processing of queue for epid:%d, USB Controller not running\n",
++ epid);
++ }
++
++ DBFEXIT;
++}
++
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++ int status) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid, i;
++ volatile int timeout = 10000;
++
++ ASSERT(urb_priv);
++ epid = urb_priv->epid;
++
++ ASSERT(usb_pipeisoc(urb->pipe));
++
++ /* Set 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;
++ }
++
++ /* Check if the URB is currently active (done or error) */
++ if(urb == activeUrbList[epid]) {
++ /* Check if there are another In Isoc URB queued for this epid */
++ if (!list_empty(&urb_list[epid])&& !epid_state[epid].disabled) {
++ /* Move it from queue to active and mark it started so Isoc transfers
++ won't be interrupted.
++ All Isoc URBs data transfers are already added to DMA lists so we
++ don't have to insert anything in DMA lists here. */
++ activeUrbList[epid] = urb_list_first(epid);
++ ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_state =
++ STARTED;
++ urb_list_del(activeUrbList[epid], epid);
++
++ if(urb->status) {
++ errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++ " status:%d, new waiting URB:0x%x[%d]\n",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb_priv->isoc_packet_counter,
++ urb->number_of_packets, urb->status,
++ (unsigned int)activeUrbList[epid],
++ ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_num);
++ }
++
++ } else { /* No other URB queued for this epid */
++ if(urb->status) {
++ errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++ " status:%d, no new URB waiting\n",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb_priv->isoc_packet_counter,
++ urb->number_of_packets, urb->status);
++ }
++
++ /* Check if EP is still enabled, then shut it down. */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ isoc_dbg("Isoc EP enabled for epid:%d, disabling it\n", epid);
++
++ /* Should only occur for In Isoc EPs where SB isn't consumed. */
++ ASSERT(usb_pipein(urb->pipe));
++
++ /* Disable it and wait for it to stop */
++ 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])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Isoc to leave EP for epid:%d\n", epid);
++ }
++ }
++
++ /* Unlink SB to say that epid is finished. */
++ TxIsocEPList[epid].sub = 0;
++ TxIsocEPList[epid].hw_len = 0;
++
++ /* No URB active for EP anymore */
++ activeUrbList[epid] = NULL;
++ }
++ } else { /* Finishing of not active URB (queued up with SBs thought) */
++ isoc_warn("finish_isoc_urb (URB:0x%x %s) (%d of %d packets) status:%d,"
++ " SB queued but not active\n",
++ (unsigned int)urb, str_dir(urb->pipe),
++ urb_priv->isoc_packet_counter, urb->number_of_packets,
++ urb->status);
++ if(usb_pipeout(urb->pipe)) {
++ /* Finishing of not yet active Out Isoc URB needs unlinking of SBs. */
++ struct USB_SB_Desc *iter_sb, *prev_sb, *next_sb;
++
++ iter_sb = TxIsocEPList[epid].sub ?
++ phys_to_virt(TxIsocEPList[epid].sub) : 0;
++ prev_sb = 0;
++
++ /* SB that is linked before this URBs first SB */
++ 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. */
++ isoc_dbg("Isoc urb not found, already sent?\n");
++ 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;
++ }
++ }
++ }
++
++ /* Free HC-private URB data*/
++ urb_priv_free(hcd, urb);
++
++ usb_release_bandwidth(urb->dev, urb, 0);
++
++ /* Hand the URB from HCD to its USB device driver, using its completion
++ functions */
++ usb_hcd_giveback_urb (hcd, urb);
++}
++
++static __u32 urb_num = 0;
++
++/* allocate and initialize URB private data */
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++ int mem_flags) {
++ struct crisv10_urb_priv *urb_priv;
++
++ urb_priv = kmalloc(sizeof *urb_priv, mem_flags);
++ if (!urb_priv)
++ return -ENOMEM;
++ memset(urb_priv, 0, sizeof *urb_priv);
++
++ urb_priv->epid = epid;
++ urb_priv->urb_state = NOT_STARTED;
++
++ urb->hcpriv = urb_priv;
++ /* Assign URB a sequence number, and increment counter */
++ urb_priv->urb_num = urb_num;
++ urb_num++;
++ return 0;
++}
++
++/* free URB private data */
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb) {
++ int i;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ ASSERT(urb_priv != 0);
++
++ /* Check it has any SBs linked that needs to be freed*/
++ if(urb_priv->first_sb != NULL) {
++ struct USB_SB_Desc *next_sb, *first_sb, *last_sb;
++ int i = 0;
++ first_sb = urb_priv->first_sb;
++ last_sb = urb_priv->last_sb;
++ ASSERT(last_sb);
++ while(first_sb != last_sb) {
++ next_sb = (struct USB_SB_Desc *)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++;
++ }
++
++ /* Check if it has any EPs in its Intr pool that also needs to be freed */
++ if(urb_priv->intr_ep_pool_length > 0) {
++ for(i = 0; i < urb_priv->intr_ep_pool_length; i++) {
++ kfree(urb_priv->intr_ep_pool[i]);
++ }
++ /*
++ tc_dbg("Freed %d EPs from URB:0x%x EP pool\n",
++ urb_priv->intr_ep_pool_length, (unsigned int)urb);
++ */
++ }
++
++ kfree(urb_priv);
++ urb->hcpriv = NULL;
++}
++
++static int ep_priv_create(struct usb_host_endpoint *ep, int mem_flags) {
++ struct crisv10_ep_priv *ep_priv;
++
++ ep_priv = kmalloc(sizeof *ep_priv, mem_flags);
++ if (!ep_priv)
++ return -ENOMEM;
++ memset(ep_priv, 0, sizeof *ep_priv);
++
++ ep->hcpriv = ep_priv;
++ return 0;
++}
++
++static void ep_priv_free(struct usb_host_endpoint *ep) {
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ ASSERT(ep_priv);
++ kfree(ep_priv);
++ ep->hcpriv = NULL;
++}
++
++/* EPID handling functions, managing EP-list in Etrax through wrappers */
++/* ------------------------------------------------------------------- */
++
++/* Sets up a new EPID for an endpoint or returns existing if found */
++static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++ int mem_flags) {
++ int epid;
++ char devnum, endpoint, out_traffic, slow;
++ int maxlen;
++ __u32 epid_data;
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++
++ DBFENTER;
++
++ /* Check if a valid epid already is setup for this endpoint */
++ if(ep_priv != NULL) {
++ return ep_priv->epid;
++ }
++
++ /* We must find and initiate a new epid for this urb. */
++ epid = tc_allocate_epid();
++
++ if (epid == -1) {
++ /* Failed to allocate a new epid. */
++ DBFEXIT;
++ return epid;
++ }
++
++ /* We now have a new epid to use. Claim it. */
++ epid_state[epid].inuse = 1;
++
++ /* Init private data for new endpoint */
++ if(ep_priv_create(ep, mem_flags) != 0) {
++ return -ENOMEM;
++ }
++ ep_priv = ep->hcpriv;
++ ep_priv->epid = epid;
++
++ devnum = usb_pipedevice(urb->pipe);
++ endpoint = usb_pipeendpoint(urb->pipe);
++ slow = (urb->dev->speed == USB_SPEED_LOW);
++ 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);
++ }
++
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ epid_data = 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);
++ etrax_epid_iso_set(epid, epid_data);
++ } else {
++ epid_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);
++ etrax_epid_set(epid, epid_data);
++ }
++
++ epid_state[epid].out_traffic = out_traffic;
++ epid_state[epid].type = usb_pipetype(urb->pipe);
++
++ tc_warn("Setting up ep:0x%x epid:%d (addr:%d endp:%d max_len:%d %s %s %s)\n",
++ (unsigned int)ep, epid, devnum, endpoint, maxlen,
++ str_type(urb->pipe), out_traffic ? "out" : "in",
++ slow ? "low" : "full");
++
++ /* Enable Isoc eof interrupt if we set up the first Isoc epid */
++ if(usb_pipeisoc(urb->pipe)) {
++ isoc_epid_counter++;
++ if(isoc_epid_counter == 1) {
++ isoc_warn("Enabled Isoc eof interrupt\n");
++ *R_USB_IRQ_MASK_SET |= IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++ }
++ }
++
++ DBFEXIT;
++ return epid;
++}
++
++static void tc_free_epid(struct usb_host_endpoint *ep) {
++ unsigned long flags;
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ int epid;
++ volatile int timeout = 10000;
++
++ DBFENTER;
++
++ if (ep_priv == NULL) {
++ tc_warn("Trying to free unused epid on ep:0x%x\n", (unsigned int)ep);
++ DBFEXIT;
++ return;
++ }
++
++ epid = ep_priv->epid;
++
++ /* Disable Isoc eof interrupt if we free the last Isoc epid */
++ if(epid_isoc(epid)) {
++ ASSERT(isoc_epid_counter > 0);
++ isoc_epid_counter--;
++ if(isoc_epid_counter == 0) {
++ *R_USB_IRQ_MASK_SET &= ~IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++ isoc_warn("Disabled Isoc eof interrupt\n");
++ }
++ }
++
++ /* Take lock manualy instead of in epid_x_x wrappers,
++ because we need to be polling here */
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++
++ *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)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for epid:%d to drop hold\n", epid);
++ }
++ /* This will, among other things, set the valid field to 0. */
++ *R_USB_EPT_DATA = 0;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++
++ /* Free resource in software state info list */
++ epid_state[epid].inuse = 0;
++
++ /* Free private endpoint data */
++ ep_priv_free(ep);
++
++ DBFEXIT;
++}
++
++static int tc_allocate_epid(void) {
++ int i;
++ DBFENTER;
++ for (i = 0; i < NBR_OF_EPIDS; i++) {
++ if (!epid_inuse(i)) {
++ DBFEXIT;
++ return i;
++ }
++ }
++
++ tc_warn("Found no free epids\n");
++ DBFEXIT;
++ return -1;
+ }
+
+
+-static void init_tx_intr_ep(void)
+-{
+- int i;
++/* Wrappers around the list functions (include/linux/list.h). */
++/* ---------------------------------------------------------- */
++static inline int __urb_list_empty(int epid) {
++ int retval;
++ retval = list_empty(&urb_list[epid]);
++ return retval;
++}
+
+- DBFENTER;
++/* Returns first urb for this epid, or NULL if list is empty. */
++static inline struct urb *urb_list_first(int epid) {
++ unsigned long flags;
++ struct urb *first_urb = 0;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ 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;
++ }
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return first_urb;
++}
+
+- /* 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]);
+- }
++/* Adds an urb_entry last in the list for this epid. */
++static inline void urb_list_add(struct urb *urb, int epid, int mem_flags) {
++ unsigned long flags;
++ urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), mem_flags);
++ ASSERT(urb_entry);
++
++ urb_entry->urb = urb;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ list_add_tail(&urb_entry->list, &urb_list[epid]);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++}
+
+- 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;
++/* 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.)
++ Should be protected by spin_locks in calling function */
++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;
++}
++
++/* Same function as above but for global use. Protects list by spinlock */
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return (urb_entry);
+ }
+
+-static void init_tx_isoc_ep(void)
+-{
+- int i;
++/* Delete an urb from the list. */
++static inline void urb_list_del(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ /* Delete entry and free. */
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ list_del(&urb_entry->list);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ kfree(urb_entry);
++}
+
+- DBFENTER;
++/* Move an urb to the end of the list. */
++static inline void urb_list_move_last(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ list_del(&urb_entry->list);
++ list_add_tail(&urb_entry->list, &urb_list[epid]);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++}
+
+- /* 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]);
++/* Get the next urb in the list. */
++static inline struct urb *urb_list_next(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ spin_lock_irqsave(&urb_list_lock, flags);
++ 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);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return urb_entry->urb;
++ } else {
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return NULL;
++ }
++}
++
++struct USB_EP_Desc* create_ep(int epid, struct USB_SB_Desc* sb_desc,
++ int mem_flags) {
++ struct USB_EP_Desc *ep_desc;
++ ep_desc = (struct USB_EP_Desc *) kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(ep_desc == NULL)
++ return NULL;
++ memset(ep_desc, 0, sizeof(struct USB_EP_Desc));
++
++ ep_desc->hw_len = 0;
++ ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
++ IO_STATE(USB_EP_command, enable, yes));
++ if(sb_desc == NULL) {
++ ep_desc->sub = 0;
++ } else {
++ ep_desc->sub = virt_to_phys(sb_desc);
++ }
++ return ep_desc;
++}
++
++#define TT_ZOUT 0
++#define TT_IN 1
++#define TT_OUT 2
++#define TT_SETUP 3
++
++#define CMD_EOL IO_STATE(USB_SB_command, eol, yes)
++#define CMD_INTR IO_STATE(USB_SB_command, intr, yes)
++#define CMD_FULL IO_STATE(USB_SB_command, full, yes)
++
++/* Allocation and setup of a generic SB. Used to create SETUP, OUT and ZOUT
++ SBs. Also used by create_sb_in() to avoid same allocation procedure at two
++ places */
++struct USB_SB_Desc* create_sb(struct USB_SB_Desc* sb_prev, int tt, void* data,
++ int datalen, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++ memset(sb_desc, 0, sizeof(struct USB_SB_Desc));
++
++ sb_desc->command = IO_FIELD(USB_SB_command, tt, tt) |
++ IO_STATE(USB_SB_command, eot, yes);
++
++ sb_desc->sw_len = datalen;
++ if(data != NULL) {
++ sb_desc->buf = virt_to_phys(data);
++ } else {
++ sb_desc->buf = 0;
++ }
++ if(sb_prev != NULL) {
++ sb_prev->next = virt_to_phys(sb_desc);
++ }
++ return sb_desc;
++}
++
++/* Creates a copy of an existing SB by allocation space for it and copy
++ settings */
++struct USB_SB_Desc* create_sb_copy(struct USB_SB_Desc* sb_orig, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++
++ memcpy(sb_desc, sb_orig, sizeof(struct USB_SB_Desc));
++ return sb_desc;
++}
++
++/* A specific create_sb function for creation of in SBs. This is due to
++ that datalen in In SBs shows how many packets we are expecting. It also
++ sets up the rem field to show if how many bytes we expect in last packet
++ if it's not a full one */
++struct USB_SB_Desc* create_sb_in(struct USB_SB_Desc* sb_prev, int datalen,
++ int maxlen, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = create_sb(sb_prev, TT_IN, NULL,
++ datalen ? (datalen - 1) / maxlen + 1 : 0, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++ sb_desc->command |= IO_FIELD(USB_SB_command, rem, datalen % maxlen);
++ return sb_desc;
++}
++
++void set_sb_cmds(struct USB_SB_Desc *sb_desc, __u16 flags) {
++ sb_desc->command |= flags;
++}
++
++int create_sb_for_urb(struct urb *urb, int mem_flags) {
++ int is_out = !usb_pipein(urb->pipe);
++ int type = usb_pipetype(urb->pipe);
++ int maxlen = usb_maxpacket(urb->dev, urb->pipe, is_out);
++ int buf_len = urb->transfer_buffer_length;
++ void *buf = buf_len > 0 ? urb->transfer_buffer : NULL;
++ struct USB_SB_Desc *sb_desc = NULL;
++
++ struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv != NULL);
++
++ switch(type) {
++ case PIPE_CONTROL:
++ /* Setup stage */
++ sb_desc = create_sb(NULL, TT_SETUP, urb->setup_packet, 8, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++
++ /* Attach first SB to URB */
++ urb_priv->first_sb = sb_desc;
++
++ if (is_out) { /* Out Control URB */
++ /* If this Control OUT transfer has an optional data stage we add
++ an OUT token before the mandatory IN (status) token */
++ if ((buf_len > 0) && buf) {
++ sb_desc = create_sb(sb_desc, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++
++ /* Status stage */
++ /* The data length has to be exactly 1. This is due to a requirement
++ of the USB specification that a host must be prepared to receive
++ data in the status phase */
++ sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ } else { /* In control URB */
++ /* Data stage */
++ sb_desc = create_sb_in(sb_desc, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* Status stage */
++ /* Read comment at zout_buffer declaration for an explanation to this. */
++ sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* Set descriptor interrupt flag for in URBs so we can finish URB after
++ zout-packet has been sent */
++ set_sb_cmds(sb_desc, CMD_INTR | CMD_FULL);
++ }
++ /* Set end-of-list flag in last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++ /* Attach last SB to URB */
++ urb_priv->last_sb = sb_desc;
++ break;
++
++ case PIPE_BULK:
++ if (is_out) { /* Out Bulk URB */
++ sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* 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)) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ } else { /* In Bulk URB */
++ sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ }
++ /* Set end-of-list flag for last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++ break;
++
++ case PIPE_INTERRUPT:
++ if(is_out) { /* Out Intr URB */
++ sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* 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)) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ /* Only generate TX interrupt if it's a Out URB*/
++ set_sb_cmds(sb_desc, CMD_INTR);
++
++ } else { /* In Intr URB */
++ sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ }
++ /* Set end-of-list flag for last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++
++ break;
++ case PIPE_ISOCHRONOUS:
++ if(is_out) { /* Out Isoc URB */
++ int i;
++ if(urb->number_of_packets == 0) {
++ tc_err("Can't create SBs for Isoc URB with zero packets\n");
++ return -EPIPE;
++ }
++ /* 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 > 0) {
++
++ sb_desc = create_sb(sb_desc, TT_OUT, urb->transfer_buffer +
++ urb->iso_frame_desc[i].offset,
++ urb->iso_frame_desc[i].length, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* Check if it's a full length packet */
++ if (urb->iso_frame_desc[i].length ==
++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++
++ } else { /* zero length packet */
++ sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ /* Attach first SB descriptor to URB */
++ if (i == 0) {
++ urb_priv->first_sb = sb_desc;
++ }
++ }
++ /* Set interrupt and end-of-list flags in last SB */
++ set_sb_cmds(sb_desc, CMD_INTR | CMD_EOL);
++ /* Attach last SB descriptor to URB */
++ urb_priv->last_sb = sb_desc;
++ tc_dbg("Created %d out SBs for Isoc URB:0x%x\n",
++ urb->number_of_packets, (unsigned int)urb);
++ } else { /* In Isoc URB */
++ /* Actual number of packets is not relevant for periodic in traffic as
++ long as it is more than zero. Set to 1 always. */
++ sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* Set end-of-list flags for SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++ }
++ break;
++ default:
++ tc_err("Unknown pipe-type\n");
++ return -EPIPE;
++ break;
++ }
++ return 0;
++}
++
++int init_intr_urb(struct urb *urb, int mem_flags) {
++ struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ struct USB_EP_Desc* ep_desc;
++ int interval;
++ int i;
++ int ep_count;
++
++ ASSERT(urb_priv != NULL);
++ ASSERT(usb_pipeint(urb->pipe));
++ /* We can't support interval longer than amount of eof descriptors in
++ TxIntrEPList */
++ if(urb->interval > MAX_INTR_INTERVAL) {
++ tc_err("Interrupt interval %dms too big (max: %dms)\n", urb->interval,
++ MAX_INTR_INTERVAL);
++ return -EINVAL;
++ }
++
++ /* We assume that the SB descriptors already have been setup */
++ ASSERT(urb_priv->first_sb != NULL);
++
++ /* 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. */
++ interval = urb->interval;
++ for (i = 0; interval; i++) {
++ interval = interval >> 1;
++ }
++ urb_priv->interval = 1 << (i - 1);
++
++ /* We can only have max interval for Out Interrupt due to that we can only
++ handle one linked in EP for a certain epid in the Intr descr array at the
++ time. The USB Controller in the Etrax 100LX continues to process Intr EPs
++ so we have no way of knowing which one that caused the actual transfer if
++ we have several linked in. */
++ if(usb_pipeout(urb->pipe)) {
++ urb_priv->interval = MAX_INTR_INTERVAL;
++ }
++
++ /* Calculate amount of EPs needed */
++ ep_count = MAX_INTR_INTERVAL / urb_priv->interval;
++
++ for(i = 0; i < ep_count; i++) {
++ ep_desc = create_ep(urb_priv->epid, urb_priv->first_sb, mem_flags);
++ if(ep_desc == NULL) {
++ /* Free any descriptors that we may have allocated before failure */
++ while(i > 0) {
++ i--;
++ kfree(urb_priv->intr_ep_pool[i]);
++ }
++ return -ENOMEM;
++ }
++ urb_priv->intr_ep_pool[i] = ep_desc;
++ }
++ urb_priv->intr_ep_pool_length = ep_count;
++ return 0;
++}
++
++/* DMA RX/TX functions */
++/* ----------------------- */
++
++static void tc_dma_init_rx_list(void) {
++ int i;
++
++ /* Setup descriptor list except last one */
++ 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]);
++
++ }
++ /* Special handling of last descriptor */
++ 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;
++
++ /* Setup list pointers that show progress in list */
++ myNextRxDesc = &RxDescList[0];
++ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
++
++ flush_etrax_cache();
++ /* Point DMA to first descriptor in list and start it */
++ *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
++ *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
++}
++
++
++static void tc_dma_init_tx_bulk_list(void) {
++ int i;
++ volatile struct USB_EP_Desc *epDescr;
++
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ epDescr = &(TxBulkEPList[i]);
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->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]);
++ }
++
++ /* Special handling of last descr in list, make list circular */
++ epDescr = &TxBulkEPList[i];
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxBulkEPList[0]);
++
++ /* Init DMA sub-channel pointers to last item in each list */
++ *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); */
++}
++
++static void tc_dma_init_tx_ctrl_list(void) {
++ int i;
++ volatile struct USB_EP_Desc *epDescr;
++
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ epDescr = &(TxCtrlEPList[i]);
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxCtrlEPList[i + 1]);
++ }
++ /* Special handling of last descr in list, make list circular */
++ epDescr = &TxCtrlEPList[i];
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxCtrlEPList[0]);
++
++ /* Init DMA sub-channel pointers to last item in each list */
++ *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[i]);
++ /* No point in starting the ctrl channel yet.
++ *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
++}
++
++
++static void tc_dma_init_tx_intr_list(void) {
++ int i;
++
++ 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]);
++ }
++
++ /* Special handling of last descr in list, make list circular */
++ 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]);
++
++ intr_dbg("Initiated Intr EP descriptor list\n");
++
++
++ /* Connect DMA 8 sub-channel 2 to first in list */
++ *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
++}
++
++static void tc_dma_init_tx_isoc_list(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);
++}
++
++static int tc_dma_init(struct usb_hcd *hcd) {
++ tc_dma_init_rx_list();
++ tc_dma_init_tx_bulk_list();
++ tc_dma_init_tx_ctrl_list();
++ tc_dma_init_tx_intr_list();
++ tc_dma_init_tx_isoc_list();
++
++ if (cris_request_dma(USB_TX_DMA_NBR,
++ "ETRAX 100LX built-in USB (Tx)",
++ DMA_VERBOSE_ON_ERROR,
++ dma_usb)) {
++ err("Could not allocate DMA ch 8 for USB");
++ return -EBUSY;
++ }
++
++ if (cris_request_dma(USB_RX_DMA_NBR,
++ "ETRAX 100LX built-in USB (Rx)",
++ DMA_VERBOSE_ON_ERROR,
++ dma_usb)) {
++ err("Could not allocate DMA ch 9 for USB");
++ return -EBUSY;
++ }
++
++ *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);
++
++ if (request_irq(ETRAX_USB_RX_IRQ, tc_dma_rx_interrupt, 0,
++ "ETRAX 100LX built-in USB (Rx)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
++ return -EBUSY;
++ }
++
++ if (request_irq(ETRAX_USB_TX_IRQ, tc_dma_tx_interrupt, 0,
++ "ETRAX 100LX built-in USB (Tx)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++static void tc_dma_destroy(void) {
++ free_irq(ETRAX_USB_RX_IRQ, NULL);
++ free_irq(ETRAX_USB_TX_IRQ, NULL);
++
++ cris_free_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)");
++ cris_free_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)");
++
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb);
++
++/* Handle processing of Bulk, Ctrl and Intr queues */
++static void tc_dma_process_queue(int epid) {
++ struct urb *urb;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ unsigned long flags;
++ char toggle;
++
++ if(epid_state[epid].disabled) {
++ /* Don't process any URBs on a disabled endpoint */
++ return;
++ }
++
++ /* Do not disturb us while fiddling with EPs and epids */
++ local_irq_save(flags);
++
++ /* For bulk, Ctrl and Intr can we only have one URB active at a time for
++ a specific EP. */
++ if(activeUrbList[epid] != NULL) {
++ /* An URB is already active on EP, skip checking queue */
++ local_irq_restore(flags);
++ return;
++ }
++
++ urb = urb_list_first(epid);
++ if(urb == NULL) {
++ /* No URB waiting in EP queue. Nothing do to */
++ local_irq_restore(flags);
++ return;
++ }
++
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv != NULL);
++ ASSERT(urb_priv->urb_state == NOT_STARTED);
++ ASSERT(!usb_pipeisoc(urb->pipe));
++
++ /* Remove this URB from the queue and move it to active */
++ activeUrbList[epid] = urb;
++ urb_list_del(urb, epid);
++
++ urb_priv->urb_state = STARTED;
++
++ /* Reset error counters (regardless of which direction this traffic is). */
++ etrax_epid_clear_error(epid);
++
++ /* Special handling of Intr EP lists */
++ if(usb_pipeint(urb->pipe)) {
++ tc_dma_link_intr_urb(urb);
++ local_irq_restore(flags);
++ return;
++ }
++
++ /* Software must preset the toggle bits for Bulk and Ctrl */
++ if(usb_pipecontrol(urb->pipe)) {
++ /* Toggle bits are initialized only during setup transaction in a
++ CTRL transfer */
++ etrax_epid_set_toggle(epid, 0, 0);
++ etrax_epid_set_toggle(epid, 1, 0);
++ } else {
++ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe));
++ etrax_epid_set_toggle(epid, usb_pipeout(urb->pipe), toggle);
++ }
++
++ tc_dbg("Added SBs from (URB:0x%x %s %s) to epid %d: %s\n",
++ (unsigned int)urb, str_dir(urb->pipe), str_type(urb->pipe), epid,
++ sblist_to_str(urb_priv->first_sb));
++
++ /* 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. */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Assert that the EP descriptor is disabled. */
++ ASSERT(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
++
++ /* Set up and enable the EP descriptor. */
++ TxBulkEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ TxBulkEPList[epid].hw_len = 0;
++ TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ /* Check if the dummy list is already with us (if several urbs were queued). */
++ if (usb_pipein(urb->pipe) && (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0]))) {
++ tc_dbg("Inviting dummy list to the party for urb 0x%lx, epid %d",
++ (unsigned long)urb, epid);
++
++ /* 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]);
++ }
++
++ restart_dma8_sub0();
++
++ /* 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);
++ break;
++ case PIPE_CONTROL:
++ /* 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(urb_priv->first_sb);
++ TxCtrlEPList[epid].hw_len = 0;
++ TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
++ break;
++ }
++ local_irq_restore(flags);
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ volatile struct USB_EP_Desc *tmp_ep;
++ struct USB_EP_Desc *ep_desc;
++ int i = 0, epid;
++ int pool_idx = 0;
++
++ ASSERT(urb_priv != NULL);
++ epid = urb_priv->epid;
++ ASSERT(urb_priv->interval > 0);
++ ASSERT(urb_priv->intr_ep_pool_length > 0);
++
++ tmp_ep = &TxIntrEPList[0];
++
++ /* Only insert one EP descriptor in list for Out Intr URBs.
++ We can only handle Out Intr with interval of 128ms because
++ it's not possible to insert several Out Intr EPs because they
++ are not consumed by the DMA. */
++ if(usb_pipeout(urb->pipe)) {
++ ep_desc = urb_priv->intr_ep_pool[0];
++ ASSERT(ep_desc);
++ ep_desc->next = tmp_ep->next;
++ tmp_ep->next = virt_to_phys(ep_desc);
++ i++;
++ } else {
++ /* Loop through Intr EP descriptor list and insert EP for URB at
++ specified interval */
++ do {
++ /* Each EP descriptor with eof flag sat signals a new frame */
++ if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
++ /* Insert a EP from URBs EP pool at correct interval */
++ if ((i % urb_priv->interval) == 0) {
++ ep_desc = urb_priv->intr_ep_pool[pool_idx];
++ ASSERT(ep_desc);
++ ep_desc->next = tmp_ep->next;
++ tmp_ep->next = virt_to_phys(ep_desc);
++ pool_idx++;
++ ASSERT(pool_idx <= urb_priv->intr_ep_pool_length);
+ }
++ i++;
++ }
++ tmp_ep = (struct USB_EP_Desc *)phys_to_virt(tmp_ep->next);
++ } while(tmp_ep != &TxIntrEPList[0]);
++ }
++
++ intr_dbg("Added SBs to intr epid %d: %s interval:%d (%d EP)\n", epid,
++ sblist_to_str(urb_priv->first_sb), urb_priv->interval, pool_idx);
++
++ /* 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);
++}
++
++static void tc_dma_process_isoc_urb(struct urb *urb) {
++ unsigned long flags;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid;
++
++ /* Do not disturb us while fiddling with EPs and epids */
++ local_irq_save(flags);
++
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->first_sb);
++ epid = urb_priv->epid;
++
++ if(activeUrbList[epid] == NULL) {
++ /* EP is idle, so make this URB active */
++ activeUrbList[epid] = urb;
++ urb_list_del(urb, epid);
++ ASSERT(TxIsocEPList[epid].sub == 0);
++ ASSERT(!(TxIsocEPList[epid].command &
++ IO_STATE(USB_EP_command, enable, yes)));
++
++ /* Differentiate between In and Out Isoc. Because In SBs are not consumed*/
++ if(usb_pipein(urb->pipe)) {
++ /* Each EP for In Isoc will have only one SB descriptor, setup when
++ submitting the first active urb. We do it here by copying from URBs
++ pre-allocated SB. */
++ memcpy((void *)&(TxIsocSBList[epid]), urb_priv->first_sb,
++ sizeof(TxIsocSBList[epid]));
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(&(TxIsocSBList[epid]));
++ } else {
++ /* For Out Isoc we attach the pre-allocated list of SBs for the URB */
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++
++ isoc_dbg("Attached first URB:0x%x[%d] to epid:%d first_sb:0x%x"
++ " last_sb::0x%x\n",
++ (unsigned int)urb, urb_priv->urb_num, epid,
++ (unsigned int)(urb_priv->first_sb),
++ (unsigned int)(urb_priv->last_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;
++ isoc_dbg("URB_ISO_ASAP set, urb->start_frame set to %d\n",
++ urb->start_frame);
++ } else {
++ /* Not started yet. */
++ urb_priv->urb_state = NOT_STARTED;
++ isoc_warn("urb_priv->urb_state set to NOT_STARTED for URB:0x%x\n",
++ (unsigned int)urb);
++ }
++
++ } else {
++ /* An URB is already active on the EP. Leave URB in queue and let
++ finish_isoc_urb process it after current active URB */
++ ASSERT(TxIsocEPList[epid].sub != 0);
++
++ if(usb_pipein(urb->pipe)) {
++ /* Because there already is a active In URB on this epid we do nothing
++ and the finish_isoc_urb() function will handle switching to next URB*/
++
++ } else { /* For Out Isoc, insert new URBs traffic last in SB-list. */
++ struct USB_SB_Desc *temp_sb_desc;
++
++ /* Set state STARTED to all Out Isoc URBs added to SB list because we
++ don't know how many of them that are finished before descr interrupt*/
++ urb_priv->urb_state = STARTED;
++
++ /* Find end of current SB list by looking for SB with eol flag sat */
++ 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);
++ }
++
++ isoc_dbg("Appended URB:0x%x[%d] (first:0x%x last:0x%x) to epid:%d"
++ " sub:0x%x eol:0x%x\n",
++ (unsigned int)urb, urb_priv->urb_num,
++ (unsigned int)(urb_priv->first_sb),
++ (unsigned int)(urb_priv->last_sb), epid,
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)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))) {
++ __u32 epid_data;
++ /* 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. */
++ epid_data = etrax_epid_iso_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) !=
++ IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++ isoc_err("Disabled Isoc EP with error:%d on epid:%d when appending"
++ " URB:0x%x[%d]\n",
++ IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data), epid,
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++
++ /* 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. */
++
++ if(virt_to_phys(temp_sb_desc) == TxIsocEPList[epid].sub) {
++ isoc_dbg("EP for epid:%d stoped at SB:0x%x before newly inserted"
++ ", restarting from this URBs SB:0x%x\n",
++ epid, (unsigned int)temp_sb_desc,
++ (unsigned int)(urb_priv->first_sb));
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
++ /* Enable the EP again so data gets processed this time */
++ TxIsocEPList[epid].command |=
++ IO_STATE(USB_EP_command, enable, yes);
++
++ } else {
++ /* The EP has been disabled but not at end this URB (god knows
++ where). This should generate an epid_attn so we should not be
++ here */
++ isoc_warn("EP was disabled on sb:0x%x before SB list for"
++ " URB:0x%x[%d] got processed\n",
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++ } else {
++ /* This might happend if we are slow on this function and isn't
++ an error. */
++ isoc_dbg("EP was disabled and finished with SBs from appended"
++ " URB:0x%x[%d]\n", (unsigned int)urb, urb_priv->urb_num);
++ }
++ }
++ }
++ }
++
++ /* Start the DMA sub channel */
++ *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
++
++ local_irq_restore(flags);
++}
++
++static void tc_dma_unlink_intr_urb(struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ volatile struct USB_EP_Desc *first_ep; /* First EP in the list. */
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++ volatile struct USB_EP_Desc *unlink_ep; /* The one we should remove from
++ the list. */
++ int count = 0;
++ volatile int timeout = 10000;
++ int epid;
++
++ /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the
++ List". */
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->intr_ep_pool_length > 0);
++ epid = urb_priv->epid;
++
++ /* First disable all Intr EPs belonging to epid for this URB */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* Disable EP */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++
++ /* Now unlink all EPs belonging to this epid from Descr list */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == 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)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Intr to leave unlink EP\n");
++ }
++
++ count++;
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++ if(count != urb_priv->intr_ep_pool_length) {
++ intr_warn("Unlinked %d of %d Intr EPs for URB:0x%x[%d]\n", count,
++ urb_priv->intr_ep_pool_length, (unsigned int)urb,
++ urb_priv->urb_num);
++ } else {
++ intr_dbg("Unlinked %d of %d interrupt EPs for URB:0x%x\n", count,
++ urb_priv->intr_ep_pool_length, (unsigned int)urb);
++ }
++}
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++ int timer) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ __u32 epid_data;
++
++ /* Protect TxEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ /* A finished EP descriptor is disabled and has a valid sub pointer */
++ if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++ (TxBulkEPList[epid].sub != 0)) {
++
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++ /* Sanity checks */
++ ASSERT(urb);
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Only handle finished out Bulk EPs here,
++ and let RX interrupt take care of the rest */
++ if(!epid_out_traffic(epid)) {
++ continue;
++ }
++
++ if(timer) {
++ tc_warn("Found finished %s Bulk epid:%d URB:0x%x[%d] from timeout\n",
++ epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++ urb_priv->urb_num);
++ } else {
++ tc_dbg("Found finished %s Bulk epid:%d URB:0x%x[%d] from interrupt\n",
++ epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++ urb_priv->urb_num);
++ }
++
++ if(urb_priv->urb_state == UNLINK) {
++ /* This Bulk URB is requested to be unlinked, that means that the EP
++ has been disabled and we might not have sent all data */
++ tc_finish_urb(hcd, urb, urb->status);
++ continue;
++ }
++
++ ASSERT(urb_priv->urb_state == STARTED);
++ if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
++ tc_err("Endpoint got disabled before reaching last sb\n");
++ }
++
++ epid_data = etrax_epid_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_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. */
++ tc_finish_urb(hcd, urb, 0);
++ } else {
++ /* Shouldn't happen. We expect errors to be caught by epid
++ attention. */
++ tc_err("Found disabled bulk EP desc (epid:%d error:%d)\n",
++ epid, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++ }
++ } else {
++ tc_dbg("Ignoring In Bulk epid:%d, let RX interrupt handle it\n", epid);
++ }
++ }
++
++ local_irq_restore(flags);
++}
++
++static void check_finished_ctrl_tx_epids(struct usb_hcd *hcd) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ __u32 epid_data;
++
++ /* Protect TxEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if(epid == DUMMY_EPID)
++ continue;
++
++ /* A finished EP descriptor is disabled and has a valid sub pointer */
++ if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++ (TxCtrlEPList[epid].sub != 0)) {
++
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++
++ if(urb == NULL) {
++ tc_warn("Found finished Ctrl epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ /* Sanity checks */
++ ASSERT(usb_pipein(urb->pipe));
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ if (phys_to_virt(TxCtrlEPList[epid].sub) != urb_priv->last_sb) {
++ tc_err("Endpoint got disabled before reaching last sb\n");
++ }
++
++ epid_data = etrax_epid_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_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. */
++
++ /* Check if RX-interrupt for In Ctrl has been processed before
++ finishing the URB */
++ if(urb_priv->ctrl_rx_done) {
++ tc_dbg("Finishing In Ctrl URB:0x%x[%d] in tx_interrupt\n",
++ (unsigned int)urb, urb_priv->urb_num);
++ tc_finish_urb(hcd, urb, 0);
++ } else {
++ /* If we get zout descriptor interrupt before RX was done for a
++ In Ctrl transfer, then we flag that and it will be finished
++ in the RX-Interrupt */
++ urb_priv->ctrl_zout_done = 1;
++ tc_dbg("Got zout descr interrupt before RX interrupt\n");
++ }
++ } else {
++ /* Shouldn't happen. We expect errors to be caught by epid
++ attention. */
++ tc_err("Found disabled Ctrl EP desc (epid:%d URB:0x%x[%d]) error_code:%d\n", epid, (unsigned int)urb, urb_priv->urb_num, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++ __dump_ep_desc(&(TxCtrlEPList[epid]));
++ __dump_ept_data(epid);
++ }
++ }
++ }
++ local_irq_restore(flags);
++}
++
++/* This function goes through all epids that are setup for Out Isoc transfers
++ and marks (isoc_out_done) all queued URBs that the DMA has finished
++ transfer for.
++ No URB completetion is done here to make interrupt routine return quickly.
++ URBs are completed later with help of complete_isoc_bottom_half() that
++ becomes schedules when this functions is finished. */
++static void check_finished_isoc_tx_epids(void) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ struct USB_SB_Desc* sb_desc;
++ int epid_done;
++
++ /* Protect TxIsocEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (TxIsocEPList[epid].sub == 0 || epid == INVALID_EPID ||
++ !epid_out_traffic(epid)) {
++ /* Nothing here to see. */
++ continue;
++ }
++ ASSERT(epid_inuse(epid));
++ ASSERT(epid_isoc(epid));
++
++ 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);
++
++ isoc_dbg("Descr IRQ checking epid:%d sub:0x%x intr:0x%x\n",
++ epid, (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)sb_desc);
++
++ urb = activeUrbList[epid];
++ if(urb == NULL) {
++ isoc_err("Isoc Descr irq on epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ epid_done = 0;
++ while(urb && !epid_done) {
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->urb_state == STARTED ||
++ urb_priv->urb_state == UNLINK);
++
++ if (sb_desc != urb_priv->last_sb) {
++ /* This urb has been sent. */
++ urb_priv->isoc_out_done = 1;
++
++ } else { /* Found URB that has last_sb as the interrupt reason */
++
++ /* Check if EP has been disabled, meaning that all transfers are done*/
++ if(!(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);
++ urb_priv->isoc_out_done = 1;
++ } else {
++ isoc_dbg("Skipping URB:0x%x[%d] because EP not disabled yet\n",
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++ /* Stop looking any further in queue */
++ epid_done = 1;
++ }
++
++ if (!epid_done) {
++ if(urb == activeUrbList[epid]) {
++ urb = urb_list_first(epid);
++ } else {
++ urb = urb_list_next(urb, epid);
++ }
++ }
++ } /* END: while(urb && !epid_done) */
++ }
++
++ local_irq_restore(flags);
++}
++
++
++/* This is where the Out Isoc URBs are realy completed. This function is
++ scheduled from tc_dma_tx_interrupt() when one or more Out Isoc transfers
++ are done. This functions completes all URBs earlier marked with
++ isoc_out_done by fast interrupt routine check_finished_isoc_tx_epids() */
++
++static void complete_isoc_bottom_half(void *data) {
++ struct crisv10_isoc_complete_data *comp_data;
++ struct usb_iso_packet_descriptor *packet;
++ struct crisv10_urb_priv * urb_priv;
++ unsigned long flags;
++ struct urb* urb;
++ int epid_done;
++ int epid;
++ int i;
++
++ comp_data = (struct crisv10_isoc_complete_data*)data;
++
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++ if(!epid_inuse(epid) || !epid_isoc(epid) || !epid_out_traffic(epid) || epid == DUMMY_EPID) {
++ /* Only check valid Out Isoc epids */
++ continue;
++ }
++
++ isoc_dbg("Isoc bottom-half checking epid:%d, sub:0x%x\n", epid,
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub));
++
++ /* The descriptor interrupt handler has marked all transmitted Out Isoc
++ URBs with isoc_out_done. Now we traverse all epids and for all that
++ have out Isoc traffic we traverse its URB list and complete the
++ transmitted URBs. */
++ epid_done = 0;
++ while (!epid_done) {
++
++ /* Get the active urb (if any) */
++ urb = activeUrbList[epid];
++ if (urb == 0) {
++ isoc_dbg("No active URB on epid:%d anymore\n", epid);
++ epid_done = 1;
++ continue;
++ }
++
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ if (!(urb_priv->isoc_out_done)) {
++ /* We have reached URB that isn't flaged done yet, stop traversing. */
++ isoc_dbg("Stoped traversing Out Isoc URBs on epid:%d"
++ " before not yet flaged URB:0x%x[%d]\n",
++ epid, (unsigned int)urb, urb_priv->urb_num);
++ epid_done = 1;
++ continue;
++ }
++
++ /* This urb has been sent. */
++ isoc_dbg("Found URB:0x%x[%d] that is flaged isoc_out_done\n",
++ (unsigned int)urb, urb_priv->urb_num);
++
++ /* Set ok on transfered packets for this URB and finish it */
++ for (i = 0; i < urb->number_of_packets; i++) {
++ packet = &urb->iso_frame_desc[i];
++ packet->status = 0;
++ packet->actual_length = packet->length;
++ }
++ urb_priv->isoc_packet_counter = urb->number_of_packets;
++ tc_finish_urb(comp_data->hcd, urb, 0);
++
++ } /* END: while(!epid_done) */
++ } /* END: for(epid...) */
++
++ local_irq_restore(flags);
++ kmem_cache_free(isoc_compl_cache, comp_data);
++}
++
++
++static void check_finished_intr_tx_epids(struct usb_hcd *hcd) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++
++ /* Protect TxintrEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if(!epid_inuse(epid) || !epid_intr(epid) || !epid_out_traffic(epid)) {
++ /* Nothing to see on this epid. Only check valid Out Intr epids */
++ continue;
++ }
++
++ urb = activeUrbList[epid];
++ if(urb == 0) {
++ intr_warn("Found Out Intr epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_INTERRUPT);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Go through EPs between first and second sof-EP. It's here Out Intr EPs
++ are inserted.*/
++ curr_ep = &TxIntrEPList[0];
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if(next_ep == urb_priv->intr_ep_pool[0]) {
++ /* We found the Out Intr EP for this epid */
++
++ /* Disable it so it doesn't get processed again */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++
++ /* Finish the active Out Intr URB with status OK */
++ tc_finish_urb(hcd, urb, 0);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != &TxIntrEPList[1]);
++
++ }
++ local_irq_restore(flags);
++}
++
++/* Interrupt handler for DMA8/IRQ24 with subchannels (called from hardware intr) */
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc) {
++ struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++ ASSERT(hcd);
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
++ restart_dma8_sub0();
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
++ check_finished_ctrl_tx_epids(hcd);
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
++ check_finished_intr_tx_epids(hcd);
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
++ struct crisv10_isoc_complete_data* comp_data;
++
++ /* Flag done Out Isoc for later completion */
++ check_finished_isoc_tx_epids();
++
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
++ /* Schedule bottom half of Out Isoc completion function. This function
++ finishes the URBs marked with isoc_out_done */
++ comp_data = (struct crisv10_isoc_complete_data*)
++ kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
++ ASSERT(comp_data != NULL);
++ comp_data ->hcd = hcd;
++
++ INIT_WORK(&comp_data->usb_bh, complete_isoc_bottom_half, comp_data);
++ schedule_work(&comp_data->usb_bh);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/* Interrupt handler for DMA9/IRQ25 (called from hardware intr) */
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc) {
++ unsigned long flags;
++ struct urb *urb;
++ struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++ struct crisv10_urb_priv *urb_priv;
++ int epid = 0;
++ int real_error;
++
++ ASSERT(hcd);
++
++ /* Clear this interrupt. */
++ *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
++
++ /* Custom clear interrupt for this interrupt */
++ /* The reason we cli here is that we call the driver's callback functions. */
++ local_irq_save(flags);
++
++ /* Note that this while loop assumes that all packets span only
++ one rx descriptor. */
++ while(myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
++ epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++
++ ASSERT(epid_inuse(epid));
++ if (!urb) {
++ dma_err("No urb for epid %d in rx interrupt\n", epid);
++ goto skip_out;
++ }
++
++ /* Check if any errors on epid */
++ real_error = 0;
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
++ __u32 r_usb_ept_data;
++
++ if (usb_pipeisoc(urb->pipe)) {
++ r_usb_ept_data = etrax_epid_iso_get(epid);
++ 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. Continue processing.
++ */
++ } else real_error = 1;
++ } else real_error = 1;
++ }
++
++ if(real_error) {
++ dma_err("Error in RX descr on epid:%d for URB 0x%x",
++ epid, (unsigned int)urb);
++ dump_ept_data(epid);
++ dump_in_desc(myNextRxDesc);
++ goto skip_out;
++ }
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->urb_state == STARTED ||
++ urb_priv->urb_state == UNLINK);
++
++ if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
++ (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
++ (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
++
++ /* 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. */
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
++ /* No data to copy */
++ } else {
++ /*
++ dma_dbg("Processing RX for URB:0x%x epid:%d (data:%d ofs:%d)\n",
++ (unsigned int)urb, epid, myNextRxDesc->hw_len,
++ urb_priv->rx_offset);
++ */
++ /* Only copy data if URB isn't flaged to be unlinked*/
++ if(urb_priv->urb_state != UNLINK) {
++ /* Make sure the data fits in the buffer. */
++ if(urb_priv->rx_offset + myNextRxDesc->hw_len
++ <= urb->transfer_buffer_length) {
++
++ /* Copy the data to URBs buffer */
++ memcpy(urb->transfer_buffer + urb_priv->rx_offset,
++ phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
++ urb_priv->rx_offset += myNextRxDesc->hw_len;
++ } else {
++ /* Signal overflow when returning URB */
++ urb->status = -EOVERFLOW;
++ tc_finish_urb_later(hcd, urb, urb->status);
++ }
++ }
++ }
++
++ /* Check if it was the last packet in the transfer */
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
++ /* Special handling for In Ctrl URBs. */
++ if(usb_pipecontrol(urb->pipe) && usb_pipein(urb->pipe) &&
++ !(urb_priv->ctrl_zout_done)) {
++ /* Flag that RX part of Ctrl transfer is done. Because zout descr
++ interrupt hasn't happend yet will the URB be finished in the
++ TX-Interrupt. */
++ urb_priv->ctrl_rx_done = 1;
++ tc_dbg("Not finishing In Ctrl URB:0x%x from rx_interrupt, waiting"
++ " for zout\n", (unsigned int)urb);
++ } else {
++ tc_finish_urb(hcd, urb, 0);
++ }
++ }
++ } else { /* ISOC RX */
++ /*
++ isoc_dbg("Processing RX for epid:%d (URB:0x%x) ISOC pipe\n",
++ epid, (unsigned int)urb);
++ */
++
++ struct usb_iso_packet_descriptor *packet;
++
++ if (urb_priv->urb_state == UNLINK) {
++ isoc_warn("Ignoring Isoc Rx data for urb being unlinked.\n");
++ goto skip_out;
++ } else if (urb_priv->urb_state == NOT_STARTED) {
++ isoc_err("What? Got Rx data for Isoc urb that isn't started?\n");
++ goto skip_out;
++ }
++
++ packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
++ ASSERT(packet);
++ 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);
++ if(packet->actual_length > 0)
++ isoc_dbg("Copied %d bytes, packet %d for URB:0x%x[%d]\n",
++ packet->actual_length, urb_priv->isoc_packet_counter,
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++
++ /* 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) {
++ /* Complete the urb with status OK. */
++ tc_finish_urb(hcd, urb, 0);
++ }
++ }
++
++ skip_out:
++ myNextRxDesc->status = 0;
++ myNextRxDesc->command |= IO_MASK(USB_IN_command, eol);
++ myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
++ myLastRxDesc = myNextRxDesc;
++ myNextRxDesc = phys_to_virt(myNextRxDesc->next);
++ flush_etrax_cache();
++ *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, restart);
++ }
++
++ local_irq_restore(flags);
++
++ return IRQ_HANDLED;
++}
++
++static void tc_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. */
++
++ if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
++ int epid;
++
++ timer_dbg("bulk_start_timer: Bulk DMA channel not running.\n");
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ timer_warn("Found enabled EP for epid %d, starting bulk channel.\n",
++ epid);
++ restart_dma8_sub0();
++
++ /* 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 {
++ timer_dbg("bulk_start_timer: Bulk DMA channel running.\n");
++ }
++}
++
++static void tc_bulk_eot_timer_func(unsigned long dummy) {
++ struct usb_hcd *hcd = (struct usb_hcd*)dummy;
++ ASSERT(hcd);
++ /* 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. */
++ timer_dbg("bulk_eot_timer timed out.\n");
++ check_finished_bulk_tx_epids(hcd, 1);
++}
++
++
++/*************************************************************/
++/*************************************************************/
++/* Device driver block */
++/*************************************************************/
++/*************************************************************/
++
++/* Forward declarations for device driver functions */
++static int devdrv_hcd_probe(struct device *);
++static int devdrv_hcd_remove(struct device *);
++#ifdef CONFIG_PM
++static int devdrv_hcd_suspend(struct device *, u32, u32);
++static int devdrv_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++
++/* the device */
++static struct platform_device *devdrv_hc_platform_device;
++
++/* device driver interface */
++static struct device_driver devdrv_hc_device_driver = {
++ .name = (char *) hc_name,
++ .bus = &platform_bus_type,
++
++ .probe = devdrv_hcd_probe,
++ .remove = devdrv_hcd_remove,
++
++#ifdef CONFIG_PM
++ .suspend = devdrv_hcd_suspend,
++ .resume = devdrv_hcd_resume,
++#endif /* CONFIG_PM */
++};
+
+- 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)
++/* initialize the host controller and driver */
++static int __init_or_module devdrv_hcd_probe(struct device *dev)
+ {
+- 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));
++ struct usb_hcd *hcd;
++ struct crisv10_hcd *crisv10_hcd;
++ int retval;
++
++ /* Check DMA burst length */
++ if(IO_EXTRACT(R_BUS_CONFIG, dma_burst, *R_BUS_CONFIG) !=
++ IO_STATE(R_BUS_CONFIG, dma_burst, burst32)) {
++ devdrv_err("Invalid DMA burst length in Etrax 100LX,"
++ " needs to be 32\n");
++ return -EPERM;
++ }
++
++ hcd = usb_create_hcd(&crisv10_hc_driver, dev, dev->bus_id);
++ if (!hcd)
++ return -ENOMEM;
++
++ crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ spin_lock_init(&crisv10_hcd->lock);
++ crisv10_hcd->num_ports = num_ports();
++ crisv10_hcd->running = 0;
++
++ dev_set_drvdata(dev, crisv10_hcd);
++
++ devdrv_dbg("ETRAX USB IRQs HC:%d RX:%d TX:%d\n", ETRAX_USB_HC_IRQ,
++ ETRAX_USB_RX_IRQ, ETRAX_USB_TX_IRQ);
++
++ /* Print out chip version read from registers */
++ int rev_maj = *R_USB_REVISION & IO_MASK(R_USB_REVISION, major);
++ int rev_min = *R_USB_REVISION & IO_MASK(R_USB_REVISION, minor);
++ if(rev_min == 0) {
++ devdrv_info("Etrax 100LX USB Revision %d v1,2\n", rev_maj);
++ } else {
++ devdrv_info("Etrax 100LX USB Revision %d v%d\n", rev_maj, rev_min);
++ }
++
++ devdrv_info("Bulk timer interval, start:%d eot:%d\n",
++ BULK_START_TIMER_INTERVAL,
++ BULK_EOT_TIMER_INTERVAL);
++
++
++ /* Init root hub data structures */
++ if(rh_init()) {
++ devdrv_err("Failed init data for Root Hub\n");
++ retval = -ENOMEM;
++ }
++
++ if(port_in_use(0)) {
++ if (cris_request_io_interface(if_usb_1, "ETRAX100LX USB-HCD")) {
++ printk(KERN_CRIT "usb-host: request IO interface usb1 failed");
++ retval = -EBUSY;
++ goto out;
++ }
++ devdrv_info("Claimed interface for USB physical port 1\n");
++ }
++ if(port_in_use(1)) {
++ if (cris_request_io_interface(if_usb_2, "ETRAX100LX USB-HCD")) {
++ /* Free first interface if second failed to be claimed */
++ if(port_in_use(0)) {
++ cris_free_io_interface(if_usb_1);
++ }
++ printk(KERN_CRIT "usb-host: request IO interface usb2 failed");
++ retval = -EBUSY;
++ goto out;
++ }
++ devdrv_info("Claimed interface for USB physical port 2\n");
++ }
++
++ /* Init transfer controller structs and locks */
++ if((retval = tc_init(hcd)) != 0) {
++ goto out;
++ }
++
++ /* Attach interrupt functions for DMA and init DMA controller */
++ if((retval = tc_dma_init(hcd)) != 0) {
++ goto out;
++ }
++
++ /* Attach the top IRQ handler for USB controller interrupts */
++ if (request_irq(ETRAX_USB_HC_IRQ, crisv10_hcd_top_irq, 0,
++ "ETRAX 100LX built-in USB (HC)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
++ retval = -EBUSY;
++ goto out;
++ }
++
++ /* iso_eof is only enabled 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);
++
++
++ crisv10_ready_wait();
++ /* 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.
++ 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);
++
++ crisv10_ready_wait();
++ /* 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);
++
++
++ /* Check so controller not busy before enabling ports */
++ crisv10_ready_wait();
++
++ /* Enable selected USB ports */
++ if(port_in_use(0)) {
++ *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++ } else {
++ *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++ }
++ if(port_in_use(1)) {
++ *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
++ } else {
++ *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
++ }
++
++ crisv10_ready_wait();
++ /* 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);
++
++ /* Do not continue probing initialization before USB interface is done */
++ crisv10_ready_wait();
++
++ /* Register our Host Controller to USB Core
++ * Finish the remaining parts of generic HCD initialization: allocate the
++ * buffers of consistent memory, register the bus
++ * and call the driver's reset() and start() routines. */
++ retval = usb_add_hcd(hcd, ETRAX_USB_HC_IRQ, IRQF_DISABLED);
++ if (retval != 0) {
++ devdrv_err("Failed registering HCD driver\n");
++ goto out;
++ }
++
++ return 0;
++
++ out:
++ devdrv_hcd_remove(dev);
++ return retval;
++}
++
++
++/* cleanup after the host controller and driver */
++static int __init_or_module devdrv_hcd_remove(struct device *dev)
++{
++ struct crisv10_hcd *crisv10_hcd = dev_get_drvdata(dev);
++ struct usb_hcd *hcd;
++
++ if (!crisv10_hcd)
++ return 0;
++ hcd = crisv10_hcd_to_hcd(crisv10_hcd);
++
++
++ /* Stop USB Controller in Etrax 100LX */
++ crisv10_hcd_reset(hcd);
++
++ usb_remove_hcd(hcd);
++ devdrv_dbg("Removed HCD from USB Core\n");
++
++ /* Free USB Controller IRQ */
++ free_irq(ETRAX_USB_HC_IRQ, NULL);
++
++ /* Free resources */
++ tc_dma_destroy();
++ tc_destroy();
++
++
++ if(port_in_use(0)) {
++ cris_free_io_interface(if_usb_1);
++ }
++ if(port_in_use(1)) {
++ cris_free_io_interface(if_usb_2);
++ }
++
++ devdrv_dbg("Freed all claimed resources\n");
++
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++static int devdrv_hcd_suspend(struct usb_hcd *hcd, u32 state, u32 level)
++{
++ return 0; /* no-op for now */
++}
++
++static int devdrv_hcd_resume(struct usb_hcd *hcd, u32 level)
++{
++ return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_PM */
++
++
++
++/*************************************************************/
++/*************************************************************/
++/* Module block */
++/*************************************************************/
++/*************************************************************/
++
++/* register driver */
++static int __init module_hcd_init(void)
++{
++
++ if (usb_disabled())
++ return -ENODEV;
++
++ /* Here we select enabled ports by following defines created from
++ menuconfig */
++#ifndef CONFIG_ETRAX_USB_HOST_PORT1
++ ports &= ~(1<<0);
++#endif
++#ifndef CONFIG_ETRAX_USB_HOST_PORT2
++ ports &= ~(1<<1);
++#endif
+
+- /* 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);
+- }
++ printk(KERN_INFO "%s version "VERSION" "COPYRIGHT"\n", product_desc);
+
+- curr_ep = phys_to_virt(curr_ep->next);
++ devdrv_hc_platform_device =
++ platform_device_register_simple((char *) hc_name, 0, NULL, 0);
+
+- } while (curr_ep != first_ep);
+- urb->hcpriv = NULL;
++ if (IS_ERR(devdrv_hc_platform_device))
++ return PTR_ERR(devdrv_hc_platform_device);
++ return driver_register(&devdrv_hc_device_driver);
++ /*
++ * Note that we do not set the DMA mask for the device,
++ * i.e. we pretend that we will use PIO, since no specific
++ * allocation routines are needed for DMA buffers. This will
++ * cause the HCD buffer allocation routines to fall back to
++ * kmalloc().
++ */
+ }
+
+-void etrax_usb_do_intr_recover(int epid)
+-{
+- USB_EP_Desc_t *first_ep, *tmp_ep;
++/* unregister driver */
++static void __exit module_hcd_exit(void)
++{
++ driver_unregister(&devdrv_hc_device_driver);
++}
+
+- 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, unsigned 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 irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc)
+-{
+- 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 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 = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+- assert(urb_priv != NULL);
+- /* This sets rx_offset to 0. */
+- 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 = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+- assert(urb_priv != NULL);
+- /* This sets rx_offset to 0. */
+- 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 = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+- assert(urb_priv != NULL);
+- 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 = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+- assert(urb_priv != NULL);
+-
+- 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)
+-{
+- 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,
+- unsigned 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;
+-
+- /* Initialize 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);
+- kobject_uevent(&fake_device.kobj, KOBJ_ADD);
+- 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->ep0.desc.wMaxPacketSize = __const_cpu_to_le16(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);
++/* Module hooks */
++module_init(module_hcd_init);
++module_exit(module_hcd_exit);
+--- linux-2.6.19.2.orig/drivers/usb/host/hc-crisv10.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/usb/host/hc-crisv10.c 2007-02-26 20:58:29.000000000 +0100
+@@ -0,0 +1,4684 @@
++/*
++ *
++ * ETRAX 100LX USB Host Controller Driver
++ *
++ * Copyright (C) 2005, 2006 Axis Communications AB
++ *
++ * Author: Konrad Eriksson <konrad.eriksson@axis.se>
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/spinlock.h>
++#include <linux/usb.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/arch/dma.h>
++#include <asm/arch/io_interface_mux.h>
++
++#include "../core/hcd.h"
++#include "../core/hub.h"
++#include "hc-crisv10.h"
++#include "hc-cris-dbg.h"
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Host Controller settings */
++/***************************************************************************/
++/***************************************************************************/
++
++#define VERSION "1.00"
++#define COPYRIGHT "(c) 2005, 2006 Axis Communications AB"
++#define DESCRIPTION "ETRAX 100LX USB Host Controller"
++
++#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
++
++/* Number of physical ports in Etrax 100LX */
++#define USB_ROOT_HUB_PORTS 2
++
++const char hc_name[] = "hc-crisv10";
++const char product_desc[] = DESCRIPTION;
++
++/* 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
++
++/* Module settings */
++
++MODULE_DESCRIPTION(DESCRIPTION);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Konrad Eriksson <konrad.eriksson@axis.se>");
++
++
++/* Module parameters */
++
++/* 0 = No ports enabled
++ 1 = Only port 1 enabled (on board ethernet on devboard)
++ 2 = Only port 2 enabled (external connector on devboard)
++ 3 = Both ports enabled
++*/
++static unsigned int ports = 3;
++module_param(ports, uint, S_IRUGO);
++MODULE_PARM_DESC(ports, "Bitmask indicating USB ports to use");
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Shared global variables for this module */
++/***************************************************************************/
++/***************************************************************************/
++
++/* EP descriptor lists for non period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++static volatile struct USB_EP_Desc TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++/* EP descriptor lists for period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIntrSB_zout __attribute__ ((aligned (4)));
++
++static volatile struct USB_EP_Desc TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIsocSB_zout __attribute__ ((aligned (4)));
++
++static volatile struct USB_SB_Desc TxIsocSBList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++/* After each enabled bulk EP IN 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 struct USB_EP_Desc TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
++
++/* List of URB pointers, where each points to the active URB for a epid.
++ For Bulk, Ctrl and Intr this means which URB that currently is added to
++ DMA lists (Isoc URBs are all directly added to DMA lists). As soon as
++ URB has completed is the queue examined and the first URB in queue is
++ removed and moved to the activeUrbList while its state change to STARTED and
++ its transfer(s) gets added to DMA list (exception Isoc where URBs enter
++ state STARTED directly and added transfers added to DMA lists). */
++static struct urb *activeUrbList[NBR_OF_EPIDS];
++
++/* Additional software state info for each epid */
++static struct etrax_epid epid_state[NBR_OF_EPIDS];
++
++/* Timer handles for bulk traffic timer used to avoid DMA bug where DMA stops
++ even if there is new data waiting to be processed */
++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/50) /* 20 ms */
++#define BULK_EOT_TIMER_INTERVAL (HZ/16) /* 60 ms */
++
++/* Delay before a URB completion happen when it's scheduled to be delayed */
++#define LATER_TIMER_DELAY (HZ/50) /* 20 ms */
++
++/* Simplifying macros for checking software state info of a epid */
++/* ----------------------------------------------------------------------- */
++#define epid_inuse(epid) epid_state[epid].inuse
++#define epid_out_traffic(epid) epid_state[epid].out_traffic
++#define epid_isoc(epid) (epid_state[epid].type == PIPE_ISOCHRONOUS ? 1 : 0)
++#define epid_intr(epid) (epid_state[epid].type == PIPE_INTERRUPT ? 1 : 0)
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* DEBUG FUNCTIONS */
++/***************************************************************************/
++/***************************************************************************/
++/* 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)
++{
++ struct crisv10_urb_priv *urb_priv = purb->hcpriv;
++ int urb_num = -1;
++ if(urb_priv) {
++ urb_num = urb_priv->urb_num;
++ }
++ printk("\nURB:0x%x[%d]\n", (unsigned int)purb, urb_num);
++ 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 struct USB_IN_Desc *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 struct USB_SB_Desc *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(" USB_SB_Desc at 0x%08lx ", (unsigned long)sb);
++ printk(" command:0x%04x (", sb->command);
++ printk("rem:%d ", (sb->command & 0x3f00) >> 8);
++ printk("full:%d ", (sb->command & 0x40) >> 6);
++ printk("tt:%d(%s) ", tt, tt_string);
++ printk("intr:%d ", (sb->command & 0x8) >> 3);
++ printk("eot:%d ", (sb->command & 0x2) >> 1);
++ printk("eol:%d)", sb->command & 0x1);
++ printk(" sw_len:0x%04x(%d)", sb->sw_len, sb->sw_len);
++ printk(" next:0x%08lx", sb->next);
++ printk(" buf:0x%08lx\n", sb->buf);
++}
++
++
++static void __dump_ep_desc(volatile struct USB_EP_Desc *ep)
++{
++ printk("USB_EP_Desc at 0x%08lx ", (unsigned long)ep);
++ printk(" command:0x%04x (", ep->command);
++ printk("ep_id:%d ", (ep->command & 0x1f00) >> 8);
++ printk("enable:%d ", (ep->command & 0x10) >> 4);
++ printk("intr:%d ", (ep->command & 0x8) >> 3);
++ printk("eof:%d ", (ep->command & 0x2) >> 1);
++ printk("eol:%d)", ep->command & 0x1);
++ printk(" hw_len:0x%04x(%d)", ep->hw_len, ep->hw_len);
++ printk(" next:0x%08lx", ep->next);
++ printk(" sub:0x%08lx\n", ep->sub);
++}
++
++static inline void __dump_ep_list(int pipe_type)
++{
++ volatile struct USB_EP_Desc *ep;
++ volatile struct USB_EP_Desc *first_ep;
++ volatile struct USB_SB_Desc *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 struct USB_EP_Desc *)(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;
++ }
++
++ local_irq_save(flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ r_usb_ept_data = *R_USB_EPT_DATA;
++ local_irq_restore(flags);
++
++ printk(" R_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_iso(int epid)
++{
++ unsigned long flags;
++ __u32 ept_data;
++
++ if (epid < 0 || epid > 31) {
++ printk("Cannot dump ept data for invalid epid %d\n", epid);
++ return;
++ }
++
++ local_irq_save(flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ ept_data = *R_USB_EPT_DATA_ISO;
++ local_irq_restore(flags);
++
++ printk(" R_USB_EPT_DATA = 0x%x for epid %d :\n", ept_data, epid);
++ if (ept_data == 0) {
++ /* No need for more detailed printing. */
++ return;
++ }
++ printk(" valid : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, valid,
++ ept_data));
++ printk(" port : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, port,
++ ept_data));
++ printk(" error_code : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code,
++ ept_data));
++ printk(" max_len : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len,
++ ept_data));
++ printk(" ep : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, ep,
++ ept_data));
++ printk(" dev : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, dev,
++ ept_data));
++}
++
++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);
++ }
++}
++
++static void debug_epid(int epid) {
++ int i;
++
++ if(epid_isoc(epid)) {
++ __dump_ept_data_iso(epid);
++ } else {
++ __dump_ept_data(epid);
++ }
++
++ printk("Bulk:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxBulkEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxBulkEPList[i]));
++ }
++ }
++
++ printk("Ctrl:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxCtrlEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxCtrlEPList[i]));
++ }
++ }
++
++ printk("Intr:\n");
++ for(i = 0; i < MAX_INTR_INTERVAL; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxIntrEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxIntrEPList[i]));
++ }
++ }
++
++ printk("Isoc:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxIsocEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxIsocEPList[i]));
++ }
++ }
++
++ __dump_ept_data_list();
++ __dump_ep_list(PIPE_INTERRUPT);
++ printk("\n\n");
++}
++
++
++
++char* hcd_status_to_str(__u8 bUsbStatus) {
++ static char hcd_status_str[128];
++ hcd_status_str[0] = '\0';
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, ourun, yes)) {
++ strcat(hcd_status_str, "ourun ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, perror, yes)) {
++ strcat(hcd_status_str, "perror ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, device_mode, yes)) {
++ strcat(hcd_status_str, "device_mode ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, host_mode, yes)) {
++ strcat(hcd_status_str, "host_mode ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, started, yes)) {
++ strcat(hcd_status_str, "started ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, running, yes)) {
++ strcat(hcd_status_str, "running ");
++ }
++ return hcd_status_str;
++}
++
++
++char* sblist_to_str(struct USB_SB_Desc* sb_desc) {
++ static char sblist_to_str_buff[128];
++ char tmp[32], tmp2[32];
++ sblist_to_str_buff[0] = '\0';
++ while(sb_desc != NULL) {
++ switch(IO_EXTRACT(USB_SB_command, tt, sb_desc->command)) {
++ case 0: sprintf(tmp, "zout"); break;
++ case 1: sprintf(tmp, "in"); break;
++ case 2: sprintf(tmp, "out"); break;
++ case 3: sprintf(tmp, "setup"); break;
++ }
++ sprintf(tmp2, "(%s %d)", tmp, sb_desc->sw_len);
++ strcat(sblist_to_str_buff, tmp2);
++ if(sb_desc->next != 0) {
++ sb_desc = phys_to_virt(sb_desc->next);
++ } else {
++ sb_desc = NULL;
++ }
++ }
++ return sblist_to_str_buff;
++}
++
++char* port_status_to_str(__u16 wPortStatus) {
++ static char port_status_str[128];
++ port_status_str[0] = '\0';
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) {
++ strcat(port_status_str, "connected ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) {
++ strcat(port_status_str, "enabled ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, suspended, yes)) {
++ strcat(port_status_str, "suspended ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes)) {
++ strcat(port_status_str, "reset ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, speed, full)) {
++ strcat(port_status_str, "full-speed ");
++ } else {
++ strcat(port_status_str, "low-speed ");
++ }
++ return port_status_str;
++}
++
++
++char* endpoint_to_str(struct usb_endpoint_descriptor *ed) {
++ static char endpoint_to_str_buff[128];
++ char tmp[32];
++ int epnum = ed->bEndpointAddress & 0x0F;
++ int dir = ed->bEndpointAddress & 0x80;
++ int type = ed->bmAttributes & 0x03;
++ endpoint_to_str_buff[0] = '\0';
++ sprintf(endpoint_to_str_buff, "ep:%d ", epnum);
++ switch(type) {
++ case 0:
++ sprintf(tmp, " ctrl");
++ break;
++ case 1:
++ sprintf(tmp, " isoc");
++ break;
++ case 2:
++ sprintf(tmp, " bulk");
++ break;
++ case 3:
++ sprintf(tmp, " intr");
++ break;
++ }
++ strcat(endpoint_to_str_buff, tmp);
++ if(dir) {
++ sprintf(tmp, " in");
++ } else {
++ sprintf(tmp, " out");
++ }
++ strcat(endpoint_to_str_buff, tmp);
++
++ return endpoint_to_str_buff;
++}
++
++/* Debug helper functions for Transfer Controller */
++char* pipe_to_str(unsigned int pipe) {
++ static char pipe_to_str_buff[128];
++ char tmp[64];
++ sprintf(pipe_to_str_buff, "dir:%s", str_dir(pipe));
++ sprintf(tmp, " type:%s", str_type(pipe));
++ strcat(pipe_to_str_buff, tmp);
++
++ sprintf(tmp, " dev:%d", usb_pipedevice(pipe));
++ strcat(pipe_to_str_buff, tmp);
++ sprintf(tmp, " ep:%d", usb_pipeendpoint(pipe));
++ strcat(pipe_to_str_buff, tmp);
++ return pipe_to_str_buff;
++}
++
++
++#define USB_DEBUG_DESC 1
++
++#ifdef USB_DEBUG_DESC
++#define dump_in_desc(x) __dump_in_desc(x)
++#define dump_sb_desc(...) __dump_sb_desc(...)
++#define dump_ep_desc(x) __dump_ep_desc(x)
++#define dump_ept_data(x) __dump_ept_data(x)
++#else
++#define dump_in_desc(...) do {} while (0)
++#define dump_sb_desc(...) do {} while (0)
++#define dump_ep_desc(...) do {} while (0)
++#endif
++
++
++/* Uncomment this to enable massive function call trace
++ #define USB_DEBUG_TRACE */
++
++#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 CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
++{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
++
++/* Most helpful debugging aid */
++#define ASSERT(expr) ((void) ((expr) ? 0 : (err("assert failed at: %s %d",__FUNCTION__, __LINE__))))
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Forward declarations */
++/***************************************************************************/
++/***************************************************************************/
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg);
++
++void rh_port_status_change(__u16[]);
++int rh_clear_port_feature(__u8, __u16);
++int rh_set_port_feature(__u8, __u16);
++static void rh_disable_port(unsigned int port);
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++ int timer);
++
++static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++ int mem_flags);
++static void tc_free_epid(struct usb_host_endpoint *ep);
++static int tc_allocate_epid(void);
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status);
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++ int status);
++
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++ int mem_flags);
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb);
++
++static inline struct urb *urb_list_first(int epid);
++static inline void urb_list_add(struct urb *urb, int epid,
++ int mem_flags);
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid);
++static inline void urb_list_del(struct urb *urb, int epid);
++static inline void urb_list_move_last(struct urb *urb, int epid);
++static inline struct urb *urb_list_next(struct urb *urb, int epid);
++
++int create_sb_for_urb(struct urb *urb, int mem_flags);
++int init_intr_urb(struct urb *urb, int mem_flags);
++
++static inline void etrax_epid_set(__u8 index, __u32 data);
++static inline void etrax_epid_clear_error(__u8 index);
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++ __u8 toggle);
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout);
++static inline __u32 etrax_epid_get(__u8 index);
++
++/* We're accessing the same register position in Etrax so
++ when we do full access the internal difference doesn't matter */
++#define etrax_epid_iso_set(index, data) etrax_epid_set(index, data)
++#define etrax_epid_iso_get(index) etrax_epid_get(index)
++
++
++static void tc_dma_process_isoc_urb(struct urb *urb);
++static void tc_dma_process_queue(int epid);
++static void tc_dma_unlink_intr_urb(struct urb *urb);
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc);
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc);
++
++static void tc_bulk_start_timer_func(unsigned long dummy);
++static void tc_bulk_eot_timer_func(unsigned long dummy);
++
++
++/*************************************************************/
++/*************************************************************/
++/* Host Controler Driver block */
++/*************************************************************/
++/*************************************************************/
++
++/* HCD operations */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void*);
++static int crisv10_hcd_reset(struct usb_hcd *);
++static int crisv10_hcd_start(struct usb_hcd *);
++static void crisv10_hcd_stop(struct usb_hcd *);
++#ifdef CONFIG_PM
++static int crisv10_hcd_suspend(struct device *, u32, u32);
++static int crisv10_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++static int crisv10_hcd_get_frame(struct usb_hcd *);
++
++static int tc_urb_enqueue(struct usb_hcd *, struct usb_host_endpoint *ep, struct urb *, gfp_t mem_flags);
++static int tc_urb_dequeue(struct usb_hcd *, struct urb *);
++static void tc_endpoint_disable(struct usb_hcd *, struct usb_host_endpoint *ep);
++
++static int rh_status_data_request(struct usb_hcd *, char *);
++static int rh_control_request(struct usb_hcd *, u16, u16, u16, char*, u16);
++
++#ifdef CONFIG_PM
++static int crisv10_hcd_hub_suspend(struct usb_hcd *);
++static int crisv10_hcd_hub_resume(struct usb_hcd *);
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++static int crisv10_hcd_start_port_reset(struct usb_hcd *, unsigned);
++#endif /* CONFIG_USB_OTG */
++
++/* host controller driver interface */
++static const struct hc_driver crisv10_hc_driver =
++ {
++ .description = hc_name,
++ .product_desc = product_desc,
++ .hcd_priv_size = sizeof(struct crisv10_hcd),
++
++ /* Attaching IRQ handler manualy in probe() */
++ /* .irq = crisv10_hcd_irq, */
++
++ .flags = HCD_USB11,
++
++ /* called to init HCD and root hub */
++ .reset = crisv10_hcd_reset,
++ .start = crisv10_hcd_start,
++
++ /* cleanly make HCD stop writing memory and doing I/O */
++ .stop = crisv10_hcd_stop,
++
++ /* return current frame number */
++ .get_frame_number = crisv10_hcd_get_frame,
++
++
++ /* Manage i/o requests via the Transfer Controller */
++ .urb_enqueue = tc_urb_enqueue,
++ .urb_dequeue = tc_urb_dequeue,
++
++ /* hw synch, freeing endpoint resources that urb_dequeue can't */
++ .endpoint_disable = tc_endpoint_disable,
++
++
++ /* Root Hub support */
++ .hub_status_data = rh_status_data_request,
++ .hub_control = rh_control_request,
++#ifdef CONFIG_PM
++ .hub_suspend = rh_suspend_request,
++ .hub_resume = rh_resume_request,
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++ .start_port_reset = crisv10_hcd_start_port_reset,
++#endif /* CONFIG_USB_OTG */
++ };
++
++
++/*
++ * conversion between pointers to a hcd and the corresponding
++ * crisv10_hcd
++ */
++
++static inline struct crisv10_hcd *hcd_to_crisv10_hcd(struct usb_hcd *hcd)
++{
++ return (struct crisv10_hcd *) hcd->hcd_priv;
++}
++
++static inline struct usb_hcd *crisv10_hcd_to_hcd(struct crisv10_hcd *hcd)
++{
++ return container_of((void *) hcd, struct usb_hcd, hcd_priv);
++}
++
++/* check if specified port is in use */
++static inline int port_in_use(unsigned int port)
++{
++ return ports & (1 << port);
++}
++
++/* number of ports in use */
++static inline unsigned int num_ports(void)
++{
++ unsigned int i, num = 0;
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++ if (port_in_use(i))
++ num++;
++ return num;
++}
++
++/* map hub port number to the port number used internally by the HC */
++static inline unsigned int map_port(unsigned int port)
++{
++ unsigned int i, num = 0;
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++ if (port_in_use(i))
++ if (++num == port)
++ return i;
++ return -1;
++}
++
++/* size of descriptors in slab cache */
++#ifndef MAX
++#define MAX(x, y) ((x) > (y) ? (x) : (y))
++#endif
++
++
++/******************************************************************/
++/* Hardware Interrupt functions */
++/******************************************************************/
++
++/* Fast interrupt handler for HC */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void *vcd)
++{
++ struct usb_hcd *hcd = vcd;
++ struct crisv10_irq_reg reg;
++ __u32 irq_mask;
++ unsigned long flags;
++
++ DBFENTER;
++
++ ASSERT(hcd != NULL);
++ reg.hcd = hcd;
++
++ /* Turn of other interrupts while handling these sensitive cases */
++ local_irq_save(flags);
++
++ /* Read out which interrupts that are flaged */
++ irq_mask = *R_USB_IRQ_MASK_READ;
++ reg.r_usb_irq_mask_read = irq_mask;
++
++ /* 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. */
++ reg.r_usb_status = *R_USB_STATUS;
++
++ /* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn
++ interrupts. */
++ reg.r_usb_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. */
++ reg.r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1;
++ reg.r_usb_rh_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. */
++ reg.r_usb_fm_number = *R_USB_FM_NUMBER;
++
++ /* Interrupts are handled in order of priority. */
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
++ crisv10_hcd_port_status_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
++ crisv10_hcd_epid_attn_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
++ crisv10_hcd_ctl_status_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
++ crisv10_hcd_isoc_eof_irq(&reg);
++ }
++ 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);
++
++ /* Check for finished bulk transfers on epids */
++ check_finished_bulk_tx_epids(hcd, 0);
++ }
++ local_irq_restore(flags);
++
++ DBFEXIT;
++ return IRQ_HANDLED;
++}
++
++
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg) {
++ struct usb_hcd *hcd = reg->hcd;
++ struct crisv10_urb_priv *urb_priv;
++ int epid;
++ DBFENTER;
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
++ struct urb *urb;
++ __u32 ept_data;
++ int error_code;
++
++ if (epid == DUMMY_EPID || epid == INVALID_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 INVALID_EPID or DUMMY_EPID (%d).", epid);
++ continue;
++ }
++
++ if(!epid_inuse(epid)) {
++ irq_err("Epid attention on epid:%d that isn't in use\n", epid);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ debug_epid(epid);
++ continue;
++ }
++
++ /* 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. */
++ ept_data = etrax_epid_get(epid);
++ error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, ept_data);
++
++ /* Get the active URB for this epid. We blatantly assume
++ that only this URB could have caused the epid attention. */
++ urb = activeUrbList[epid];
++ if (urb == NULL) {
++ irq_err("Attention on epid:%d error:%d with no active URB.\n",
++ epid, error_code);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ debug_epid(epid);
++ continue;
++ }
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* 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, ept_data) == 3 ||
++ IO_EXTRACT(R_USB_EPT_DATA, error_count_out, ept_data) == 3)) {
++ /* Check if URB allready is marked for late-finish, we can get
++ several 3rd error for Intr traffic when a device is unplugged */
++ if(urb_priv->later_data == NULL) {
++ /* 3rd error. */
++ irq_warn("3rd error for epid:%d (%s %s) URB:0x%x[%d]\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe),
++ (unsigned int)urb, urb_priv->urb_num);
++
++ tc_finish_urb_later(hcd, urb, -EPROTO);
++ }
++
++ } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
++ irq_warn("Perror for epid:%d\n", epid);
++ printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
++
++ if (!(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. */
++ 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 */
++ printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
++
++ panic("Buffer overrun/underrun for epid:%d. DMA too busy?", epid);
++ } else {
++ irq_warn("Attention on epid:%d (%s %s) with no error code\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(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");
++ }
++
++ tc_dbg("Stall for epid:%d (%s %s) URB:0x%x\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe), (unsigned int)urb);
++ tc_finish_urb(hcd, 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\n",
++ epid);
++
++ } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++ buffer_error)) {
++ /* DMA overrun or underrun. */
++ irq_warn("Buffer overrun/underrun for epid:%d (%s %s)\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++
++ /* 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. */
++ tc_finish_urb(hcd, urb, -EPROTO);
++ } else {
++ irq_warn("Unknown attention on epid:%d (%s %s)\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++ dump_ept_data(epid);
++ }
++ }
++ }
++ DBFEXIT;
++}
++
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg)
++{
++ __u16 port_reg[USB_ROOT_HUB_PORTS];
++ DBFENTER;
++ port_reg[0] = reg->r_usb_rh_port_status_1;
++ port_reg[1] = reg->r_usb_rh_port_status_2;
++ rh_port_status_change(port_reg);
++ DBFEXIT;
++}
++
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg)
++{
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv *urb_priv;
++
++ DBFENTER;
++
++ for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++
++ /* Only check epids that are in use, is valid and has SB list */
++ if (!epid_inuse(epid) || epid == INVALID_EPID ||
++ TxIsocEPList[epid].sub == 0 || epid == DUMMY_EPID) {
++ /* Nothing here to see. */
++ continue;
++ }
++ ASSERT(epid_isoc(epid));
++
++ /* Get the active URB for this epid (if any). */
++ urb = activeUrbList[epid];
++ if (urb == 0) {
++ isoc_warn("Ignoring NULL urb for epid:%d\n", epid);
++ continue;
++ }
++ if(!epid_out_traffic(epid)) {
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++
++ urb_priv = (struct crisv10_urb_priv *)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))) {
++ /* EP should not be enabled if we're waiting for start_frame */
++ ASSERT((TxIsocEPList[epid].command &
++ IO_STATE(USB_EP_command, enable, yes)) == 0);
++
++ isoc_warn("Enabling isoc IN EP descr for epid %d\n", epid);
++ TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ /* This urb is now active. */
++ urb_priv->urb_state = STARTED;
++ continue;
++ }
++ }
++ }
++ }
++
++ DBFEXIT;
++}
++
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg)
++{
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(reg->hcd);
++
++ DBFENTER;
++ ASSERT(crisv10_hcd);
++
++ irq_dbg("ctr_status_irq, controller status: %s\n",
++ hcd_status_to_str(reg->r_usb_status));
++
++ /* 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.");
++ }
++
++ /* Keep track of USB Controller, if it's running or not */
++ if(reg->r_usb_status & IO_STATE(R_USB_STATUS, running, yes)) {
++ crisv10_hcd->running = 1;
++ } else {
++ crisv10_hcd->running = 0;
++ }
++
++ 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.");
++ }
++
++ /* Set the flag to avoid getting "Unlink after no-IRQ? Controller is probably
++ using the wrong IRQ" from hcd_unlink_urb() in drivers/usb/core/hcd.c */
++ set_bit(HCD_FLAG_SAW_IRQ, &reg->hcd->flags);
++
++ DBFEXIT;
++}
++
++
++/******************************************************************/
++/* Host Controller interface functions */
++/******************************************************************/
++
++static inline void crisv10_ready_wait(void) {
++ volatile int timeout = 10000;
++ /* Check the busy bit of USB controller in Etrax */
++ while((*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for USB controller to be idle\n");
++ }
++}
++
++/* reset host controller */
++static int crisv10_hcd_reset(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "reset\n");
++
++
++ /* 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);
++ nop();
++ */
++ DBFEXIT;
++ return 0;
++}
++
++/* start host controller */
++static int crisv10_hcd_start(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "start\n");
++
++ crisv10_ready_wait();
++
++ /* 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);
++
++ nop();
++
++ hcd->state = HC_STATE_RUNNING;
++
++ DBFEXIT;
++ return 0;
++}
++
++/* stop host controller */
++static void crisv10_hcd_stop(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "stop\n");
++ crisv10_hcd_reset(hcd);
++ DBFEXIT;
++}
++
++/* return the current frame number */
++static int crisv10_hcd_get_frame(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ DBFEXIT;
++ return (*R_USB_FM_NUMBER & 0x7ff);
++}
++
++#ifdef CONFIG_USB_OTG
++
++static int crisv10_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
++{
++ return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_USB_OTG */
++
++
++/******************************************************************/
++/* Root Hub functions */
++/******************************************************************/
++
++/* root hub status */
++static const struct usb_hub_status rh_hub_status =
++ {
++ .wHubStatus = 0,
++ .wHubChange = 0,
++ };
++
++/* root hub descriptor */
++static const u8 rh_hub_descr[] =
++ {
++ 0x09, /* bDescLength */
++ 0x29, /* bDescriptorType */
++ USB_ROOT_HUB_PORTS, /* bNbrPorts */
++ 0x00, /* wHubCharacteristics */
++ 0x00,
++ 0x01, /* bPwrOn2pwrGood */
++ 0x00, /* bHubContrCurrent */
++ 0x00, /* DeviceRemovable */
++ 0xff /* PortPwrCtrlMask */
++ };
++
++/* Actual holder of root hub status*/
++struct crisv10_rh rh;
++
++/* Initialize root hub data structures (called from dvdrv_hcd_probe()) */
++int rh_init(void) {
++ int i;
++ /* Reset port status flags */
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++ rh.wPortChange[i] = 0;
++ rh.wPortStatusPrev[i] = 0;
++ }
++ return 0;
++}
++
++#define RH_FEAT_MASK ((1<<USB_PORT_FEAT_CONNECTION)|\
++ (1<<USB_PORT_FEAT_ENABLE)|\
++ (1<<USB_PORT_FEAT_SUSPEND)|\
++ (1<<USB_PORT_FEAT_RESET))
++
++/* Handle port status change interrupt (called from bottom part interrupt) */
++void rh_port_status_change(__u16 port_reg[]) {
++ int i;
++ __u16 wChange;
++
++ for(i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++ /* Xor out changes since last read, masked for important flags */
++ wChange = (port_reg[i] & RH_FEAT_MASK) ^ rh.wPortStatusPrev[i];
++ /* Or changes together with (if any) saved changes */
++ rh.wPortChange[i] |= wChange;
++ /* Save new status */
++ rh.wPortStatusPrev[i] = port_reg[i];
++
++ if(wChange) {
++ rh_dbg("Interrupt port_status change port%d: %s Current-status:%s\n", i+1,
++ port_status_to_str(wChange),
++ port_status_to_str(port_reg[i]));
++ }
++ }
++}
++
++/* Construct port status change bitmap for the root hub */
++static int rh_status_data_request(struct usb_hcd *hcd, char *buf)
++{
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ unsigned int i;
++
++ DBFENTER;
++ /*
++ * corresponds to hub status change EP (USB 2.0 spec section 11.13.4)
++ * return bitmap indicating ports with status change
++ */
++ *buf = 0;
++ spin_lock(&crisv10_hcd->lock);
++ for (i = 1; i <= crisv10_hcd->num_ports; i++) {
++ if (rh.wPortChange[map_port(i)]) {
++ *buf |= (1 << i);
++ rh_dbg("rh_status_data_request, change on port %d: %s Current Status: %s\n", i,
++ port_status_to_str(rh.wPortChange[map_port(i)]),
++ port_status_to_str(rh.wPortStatusPrev[map_port(i)]));
++ }
++ }
++ spin_unlock(&crisv10_hcd->lock);
++ DBFEXIT;
++ return *buf == 0 ? 0 : 1;
++}
++
++/* Handle a control request for the root hub (called from hcd_driver) */
++static int rh_control_request(struct usb_hcd *hcd,
++ u16 typeReq,
++ u16 wValue,
++ u16 wIndex,
++ char *buf,
++ u16 wLength) {
++
++ struct crisv10_hcd *crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ int retval = 0;
++ int len;
++ DBFENTER;
++
++ switch (typeReq) {
++ case GetHubDescriptor:
++ rh_dbg("GetHubDescriptor\n");
++ len = min_t(unsigned int, sizeof rh_hub_descr, wLength);
++ memcpy(buf, rh_hub_descr, len);
++ buf[2] = crisv10_hcd->num_ports;
++ break;
++ case GetHubStatus:
++ rh_dbg("GetHubStatus\n");
++ len = min_t(unsigned int, sizeof rh_hub_status, wLength);
++ memcpy(buf, &rh_hub_status, len);
++ break;
++ case GetPortStatus:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ rh_dbg("GetportStatus, port:%d change:%s status:%s\n", wIndex,
++ port_status_to_str(rh.wPortChange[map_port(wIndex)]),
++ port_status_to_str(rh.wPortStatusPrev[map_port(wIndex)]));
++ *(u16 *) buf = cpu_to_le16(rh.wPortStatusPrev[map_port(wIndex)]);
++ *(u16 *) (buf + 2) = cpu_to_le16(rh.wPortChange[map_port(wIndex)]);
++ break;
++ case SetHubFeature:
++ rh_dbg("SetHubFeature\n");
++ case ClearHubFeature:
++ rh_dbg("ClearHubFeature\n");
++ switch (wValue) {
++ case C_HUB_OVER_CURRENT:
++ case C_HUB_LOCAL_POWER:
++ rh_warn("Not implemented hub request:%d \n", typeReq);
++ /* not implemented */
++ break;
++ default:
++ goto error;
++ }
++ break;
++ case SetPortFeature:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ if(rh_set_port_feature(map_port(wIndex), wValue))
++ goto error;
++ break;
++ case ClearPortFeature:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ if(rh_clear_port_feature(map_port(wIndex), wValue))
++ goto error;
++ break;
++ default:
++ rh_warn("Unknown hub request: %d\n", typeReq);
++ error:
++ retval = -EPIPE;
++ }
++ DBFEXIT;
++ return retval;
++}
++
++int rh_set_port_feature(__u8 bPort, __u16 wFeature) {
++ __u8 bUsbCommand = 0;
++ switch(wFeature) {
++ case USB_PORT_FEAT_RESET:
++ rh_dbg("SetPortFeature: reset\n");
++ bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, reset);
++ goto set;
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ rh_dbg("SetPortFeature: suspend\n");
++ bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, suspend);
++ goto set;
++ break;
++ case USB_PORT_FEAT_POWER:
++ rh_dbg("SetPortFeature: power\n");
++ break;
++ case USB_PORT_FEAT_C_CONNECTION:
++ rh_dbg("SetPortFeature: c_connection\n");
++ break;
++ case USB_PORT_FEAT_C_RESET:
++ rh_dbg("SetPortFeature: c_reset\n");
++ break;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ rh_dbg("SetPortFeature: c_over_current\n");
++ break;
++
++ set:
++ /* Select which port via the port_sel field */
++ bUsbCommand |= IO_FIELD(R_USB_COMMAND, port_sel, bPort+1);
++
++ /* Make sure the controller isn't busy. */
++ crisv10_ready_wait();
++ /* Send out the actual command to the USB controller */
++ *R_USB_COMMAND = bUsbCommand;
++
++ /* If port reset then also bring USB controller into running state */
++ if(wFeature == USB_PORT_FEAT_RESET) {
++ /* Wait a while for controller to first become started after port reset */
++ udelay(12000); /* 12ms blocking wait */
++
++ /* Make sure the controller isn't busy. */
++ crisv10_ready_wait();
++
++ /* 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);
++ }
++
++ break;
++ default:
++ rh_dbg("SetPortFeature: unknown feature\n");
++ return -1;
++ }
++ return 0;
++}
++
++int rh_clear_port_feature(__u8 bPort, __u16 wFeature) {
++ switch(wFeature) {
++ case USB_PORT_FEAT_ENABLE:
++ rh_dbg("ClearPortFeature: enable\n");
++ rh_disable_port(bPort);
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ rh_dbg("ClearPortFeature: suspend\n");
++ break;
++ case USB_PORT_FEAT_POWER:
++ rh_dbg("ClearPortFeature: power\n");
++ break;
++
++ case USB_PORT_FEAT_C_ENABLE:
++ rh_dbg("ClearPortFeature: c_enable\n");
++ goto clear;
++ case USB_PORT_FEAT_C_SUSPEND:
++ rh_dbg("ClearPortFeature: c_suspend\n");
++ goto clear;
++ case USB_PORT_FEAT_C_CONNECTION:
++ rh_dbg("ClearPortFeature: c_connection\n");
++ goto clear;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ rh_dbg("ClearPortFeature: c_over_current\n");
++ goto clear;
++ case USB_PORT_FEAT_C_RESET:
++ rh_dbg("ClearPortFeature: c_reset\n");
++ goto clear;
++ clear:
++ rh.wPortChange[bPort] &= ~(1 << (wFeature - 16));
++ break;
++ default:
++ rh_dbg("ClearPortFeature: unknown feature\n");
++ return -1;
++ }
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++/* Handle a suspend request for the root hub (called from hcd_driver) */
++static int rh_suspend_request(struct usb_hcd *hcd)
++{
++ return 0; /* no-op for now */
++}
++
++/* Handle a resume request for the root hub (called from hcd_driver) */
++static int rh_resume_request(struct usb_hcd *hcd)
++{
++ return 0; /* no-op for now */
++}
++#endif /* CONFIG_PM */
++
++
++
++/* Wrapper function for workaround port disable registers in USB controller */
++static void rh_disable_port(unsigned int port) {
++ volatile int timeout = 10000;
++ volatile char* usb_portx_disable;
++ switch(port) {
++ case 0:
++ usb_portx_disable = R_USB_PORT1_DISABLE;
++ break;
++ case 1:
++ usb_portx_disable = R_USB_PORT2_DISABLE;
++ break;
++ default:
++ /* Invalid port index */
++ return;
++ }
++ /* Set disable flag in special register */
++ *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++ /* Wait until not enabled anymore */
++ while((rh.wPortStatusPrev[port] &
++ IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for port %d to become disabled\n", port);
++ }
++ /* clear disable flag in special register */
++ *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++ rh_info("Physical port %d disabled\n", port+1);
++}
++
++
++/******************************************************************/
++/* Transfer Controller (TC) functions */
++/******************************************************************/
++
++/* 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)
++
++
++/* Local variables for Transfer Controller */
++/* --------------------------------------- */
++
++/* 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 (which includes spin_locks) */
++static struct list_head urb_list[NBR_OF_EPIDS];
++
++/* Read about the need and usage of this lock in submit_ctrl_urb. */
++/* Lock for URB lists for each EPID */
++static spinlock_t urb_list_lock;
++
++/* Lock for EPID array register (R_USB_EPT_x) in Etrax */
++static spinlock_t etrax_epid_lock;
++
++/* Lock for dma8 sub0 handling */
++static spinlock_t etrax_dma8_sub0_lock;
++
++/* 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 struct USB_IN_Desc RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
++
++/* Pointers into RxDescList. */
++static volatile struct USB_IN_Desc *myNextRxDesc;
++static volatile struct USB_IN_Desc *myLastRxDesc;
++
++/* 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 data allocated in the isoc descr top half. */
++static kmem_cache_t *isoc_compl_cache;
++
++/* Cache for the data allocated when delayed finishing of URBs */
++static kmem_cache_t *later_data_cache;
++
++
++/* Counter to keep track of how many Isoc EP we have sat up. Used to enable
++ and disable iso_eof interrupt. We only need these interrupts when we have
++ Isoc data endpoints (consumes CPU cycles).
++ FIXME: This could be more fine granular, so this interrupt is only enabled
++ when we have a In Isoc URB not URB_ISO_ASAP flaged queued. */
++static int isoc_epid_counter;
++
++/* Protecting wrapper functions for R_USB_EPT_x */
++/* -------------------------------------------- */
++static inline void etrax_epid_set(__u8 index, __u32 data) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ *R_USB_EPT_DATA = data;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_clear_error(__u8 index) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ *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, error_code));
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++ __u8 toggle) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ if(dirout) {
++ *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 {
++ *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);
++ }
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout) {
++ unsigned long flags;
++ __u8 toggle;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ if (dirout) {
++ toggle = IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
++ } else {
++ toggle = IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
++ }
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++ return toggle;
++}
++
++
++static inline __u32 etrax_epid_get(__u8 index) {
++ unsigned long flags;
++ __u32 data;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ data = *R_USB_EPT_DATA;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++ return data;
++}
++
++
++
++
++/* Main functions for Transfer Controller */
++/* -------------------------------------- */
++
++/* Init structs, memories and lists used by Transfer Controller */
++int tc_init(struct usb_hcd *hcd) {
++ int i;
++ /* Clear software state info for all epids */
++ memset(epid_state, 0, sizeof(struct etrax_epid) * NBR_OF_EPIDS);
++
++ /* Set Invalid and Dummy as being in use and disabled */
++ epid_state[INVALID_EPID].inuse = 1;
++ epid_state[DUMMY_EPID].inuse = 1;
++ epid_state[INVALID_EPID].disabled = 1;
++ epid_state[DUMMY_EPID].disabled = 1;
++
++ /* Clear counter for how many Isoc epids we have sat up */
++ isoc_epid_counter = 0;
++
++ /* Initialize the urb list by initiating a head for each list.
++ Also reset list hodling active URB for each epid */
++ for (i = 0; i < NBR_OF_EPIDS; i++) {
++ INIT_LIST_HEAD(&urb_list[i]);
++ activeUrbList[i] = NULL;
++ }
++
++ /* Init lock for URB lists */
++ spin_lock_init(&urb_list_lock);
++ /* Init lock for Etrax R_USB_EPT register */
++ spin_lock_init(&etrax_epid_lock);
++ /* Init lock for Etrax dma8 sub0 handling */
++ spin_lock_init(&etrax_dma8_sub0_lock);
++
++ /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
++
++ /* Note that we specify sizeof(struct USB_EP_Desc) as the size, but also
++ allocate SB descriptors from this cache. This is ok since
++ sizeof(struct USB_EP_Desc) == sizeof(struct USB_SB_Desc). */
++ usb_desc_cache = kmem_cache_create("usb_desc_cache",
++ sizeof(struct USB_EP_Desc), 0,
++ SLAB_HWCACHE_ALIGN, 0, 0);
++ if(usb_desc_cache == NULL) {
++ return -ENOMEM;
++ }
++
++ /* Create slab cache for speedy allocation of memory for isoc bottom-half
++ interrupt handling */
++ isoc_compl_cache =
++ kmem_cache_create("isoc_compl_cache",
++ sizeof(struct crisv10_isoc_complete_data),
++ 0, SLAB_HWCACHE_ALIGN, 0, 0);
++ if(isoc_compl_cache == NULL) {
++ return -ENOMEM;
++ }
++
++ /* Create slab cache for speedy allocation of memory for later URB finish
++ struct */
++ later_data_cache =
++ kmem_cache_create("later_data_cache",
++ sizeof(struct urb_later_data),
++ 0, SLAB_HWCACHE_ALIGN, 0, 0);
++ if(later_data_cache == NULL) {
++ return -ENOMEM;
++ }
++
++
++ /* Initiate the bulk start timer. */
++ init_timer(&bulk_start_timer);
++ bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
++ bulk_start_timer.function = tc_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 = tc_bulk_eot_timer_func;
++ bulk_eot_timer.data = (unsigned long)hcd;
++ add_timer(&bulk_eot_timer);
++
++ return 0;
++}
++
++/* Uninitialize all resources used by Transfer Controller */
++void tc_destroy(void) {
++
++ /* Destroy all slab cache */
++ kmem_cache_destroy(usb_desc_cache);
++ kmem_cache_destroy(isoc_compl_cache);
++ kmem_cache_destroy(later_data_cache);
++
++ /* Remove timers */
++ del_timer(&bulk_start_timer);
++ del_timer(&bulk_eot_timer);
++}
++
++static void restart_dma8_sub0(void) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_dma8_sub0_lock, flags);
++ /* Verify that the dma is not running */
++ if ((*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd)) == 0) {
++ struct USB_EP_Desc *ep = (struct USB_EP_Desc *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
++ while (DUMMY_EPID == IO_EXTRACT(USB_EP_command, epid, ep->command)) {
++ ep = (struct USB_EP_Desc *)phys_to_virt(ep->next);
++ }
++ /* Advance the DMA to the next EP descriptor that is not a DUMMY_EPID.
++ * ep->next is already a physical address; no need for a virt_to_phys. */
++ *R_DMA_CH8_SUB0_EP = ep->next;
++ /* Restart the DMA */
++ *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
++ }
++ spin_unlock_irqrestore(&etrax_dma8_sub0_lock, flags);
++}
++
++/* queue an URB with the transfer controller (called from hcd_driver) */
++static int tc_urb_enqueue(struct usb_hcd *hcd,
++ struct usb_host_endpoint *ep,
++ struct urb *urb,
++ gfp_t mem_flags) {
++ int epid;
++ int retval;
++ int bustime = 0;
++ int maxpacket;
++ unsigned long flags;
++ struct crisv10_urb_priv *urb_priv;
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ DBFENTER;
++
++ if(!(crisv10_hcd->running)) {
++ /* The USB Controller is not running, probably because no device is
++ attached. No idea to enqueue URBs then */
++ tc_warn("Rejected enqueueing of URB:0x%x because no dev attached\n",
++ (unsigned int)urb);
++ return -ENOENT;
++ }
++
++ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++ /* Special case check for In Isoc transfers. Specification states that each
++ In Isoc transfer consists of one packet and therefore it should fit into
++ the transfer-buffer of an URB.
++ We do the check here to be sure (an invalid scenario can be produced with
++ parameters to the usbtest suite) */
++ if(usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe) &&
++ (urb->transfer_buffer_length < maxpacket)) {
++ tc_err("Submit In Isoc URB with buffer length:%d to pipe with maxpacketlen: %d\n", urb->transfer_buffer_length, maxpacket);
++ return -EMSGSIZE;
++ }
++
++ /* Check if there is enough bandwidth for periodic transfer */
++ if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe)) {
++ /* only check (and later claim) if not already claimed */
++ if (urb->bandwidth == 0) {
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0) {
++ tc_err("Not enough periodic bandwidth\n");
++ return -ENOSPC;
++ }
++ }
++ }
++
++ /* Check if there is a epid for URBs destination, if not this function
++ set up one. */
++ epid = tc_setup_epid(ep, urb, mem_flags);
++ if (epid < 0) {
++ tc_err("Failed setup epid:%d for URB:0x%x\n", epid, (unsigned int)urb);
++ DBFEXIT;
++ return -ENOMEM;
++ }
++
++ if(urb == activeUrbList[epid]) {
++ tc_err("Resubmition of allready active URB:0x%x\n", (unsigned int)urb);
++ return -ENXIO;
++ }
++
++ if(urb_list_entry(urb, epid)) {
++ tc_err("Resubmition of allready queued URB:0x%x\n", (unsigned int)urb);
++ return -ENXIO;
++ }
++
++ /* If we actively have flaged endpoint as disabled then refuse submition */
++ if(epid_state[epid].disabled) {
++ return -ENOENT;
++ }
++
++ /* Allocate and init HC-private data for URB */
++ if(urb_priv_create(hcd, urb, epid, mem_flags) != 0) {
++ DBFEXIT;
++ return -ENOMEM;
++ }
++ urb_priv = urb->hcpriv;
++
++ tc_dbg("Enqueue URB:0x%x[%d] epid:%d (%s) bufflen:%d\n",
++ (unsigned int)urb, urb_priv->urb_num, epid,
++ pipe_to_str(urb->pipe), urb->transfer_buffer_length);
++
++ /* Create and link SBs required for this URB */
++ retval = create_sb_for_urb(urb, mem_flags);
++ if(retval != 0) {
++ tc_err("Failed to create SBs for URB:0x%x[%d]\n", (unsigned int)urb,
++ urb_priv->urb_num);
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++
++ /* Init intr EP pool if this URB is a INTR transfer. This pool is later
++ used when inserting EPs in the TxIntrEPList. We do the alloc here
++ so we can't run out of memory later */
++ if(usb_pipeint(urb->pipe)) {
++ retval = init_intr_urb(urb, mem_flags);
++ if(retval != 0) {
++ tc_warn("Failed to init Intr URB\n");
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++ }
++
++ /* Disable other access when inserting USB */
++ local_irq_save(flags);
++
++ /* Claim bandwidth, if needed */
++ if(bustime) {
++ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
++ }
++
++ /* Add URB to EP queue */
++ urb_list_add(urb, epid, mem_flags);
++
++ if(usb_pipeisoc(urb->pipe)) {
++ /* Special processing of Isoc URBs. */
++ tc_dma_process_isoc_urb(urb);
++ } else {
++ /* Process EP queue for rest of the URB types (Bulk, Ctrl, Intr) */
++ tc_dma_process_queue(epid);
++ }
++
++ local_irq_restore(flags);
++
++ DBFEXIT;
++ return 0;
++}
++
++/* remove an URB from the transfer controller queues (called from hcd_driver)*/
++static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv;
++ unsigned long flags;
++ int epid;
++
++ DBFENTER;
++ /* Disable interrupts here since a descriptor interrupt for the isoc epid
++ will modify the sb list. This could possibly be done more granular, but
++ urb_dequeue should not be used frequently anyway.
++ */
++ local_irq_save(flags);
++
++ urb_priv = urb->hcpriv;
++
++ if (!urb_priv) {
++ /* This happens if a device driver calls unlink on an urb that
++ was never submitted (lazy driver) or if the urb was completed
++ while dequeue was being called. */
++ tc_warn("Dequeing of not enqueued URB:0x%x\n", (unsigned int)urb);
++ local_irq_restore(flags);
++ return 0;
++ }
++ epid = urb_priv->epid;
++
++ tc_warn("Dequeing %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ /* For Bulk, Ctrl and Intr are only one URB active at a time. So any URB
++ that isn't active can be dequeued by just removing it from the queue */
++ if(usb_pipebulk(urb->pipe) || usb_pipecontrol(urb->pipe) ||
++ usb_pipeint(urb->pipe)) {
++
++ /* Check if URB haven't gone further than the queue */
++ if(urb != activeUrbList[epid]) {
++ ASSERT(urb_priv->later_data == NULL);
++ tc_warn("Dequeing URB:0x%x[%d] (%s %s epid:%d) from queue"
++ " (not active)\n", (unsigned int)urb, urb_priv->urb_num,
++ str_dir(urb->pipe), str_type(urb->pipe), epid);
++
++ /* Finish the URB with error status from USB core */
++ tc_finish_urb(hcd, urb, urb->status);
++ local_irq_restore(flags);
++ return 0;
++ }
++ }
++
++ /* Set URB status to Unlink for handling when interrupt comes. */
++ urb_priv->urb_state = UNLINK;
++
++ /* Differentiate dequeing of Bulk and Ctrl from Isoc and Intr */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Check if EP still is enabled */
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ /* Kicking dummy list out of the party. */
++ TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
++ break;
++ case PIPE_CONTROL:
++ /* Check if EP still is enabled */
++ if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ break;
++ case PIPE_ISOCHRONOUS:
++ /* Disabling, busy-wait and unlinking of Isoc SBs will be done in
++ finish_isoc_urb(). Because there might the case when URB is dequeued
++ but there are other valid URBs waiting */
++
++ /* Check if In Isoc EP still is enabled */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ break;
++ case PIPE_INTERRUPT:
++ /* Special care is taken for interrupt URBs. EPs are unlinked in
++ tc_finish_urb */
++ break;
++ default:
++ break;
++ }
++
++ /* Asynchronous unlink, finish the URB later from scheduled or other
++ event (data finished, error) */
++ tc_finish_urb_later(hcd, urb, urb->status);
++
++ local_irq_restore(flags);
++ DBFEXIT;
++ return 0;
++}
++
++
++static void tc_sync_finish_epid(struct usb_hcd *hcd, int epid) {
++ volatile int timeout = 10000;
++ struct urb* urb;
++ struct crisv10_urb_priv* urb_priv;
++ unsigned long flags;
++
++ volatile struct USB_EP_Desc *first_ep; /* First EP in the list. */
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++
++ int type = epid_state[epid].type;
++
++ /* Setting this flag will cause enqueue() to return -ENOENT for new
++ submitions on this endpoint and finish_urb() wont process queue further */
++ epid_state[epid].disabled = 1;
++
++ switch(type) {
++ case PIPE_BULK:
++ /* Check if EP still is enabled */
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++ /* Do busy-wait until DMA not using this EP descriptor anymore */
++ while((*R_DMA_CH8_SUB0_EP ==
++ virt_to_phys(&TxBulkEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Bulk to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++
++ case PIPE_CONTROL:
++ /* Check if EP still is enabled */
++ if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++ /* Do busy-wait until DMA not using this EP descriptor anymore */
++ while((*R_DMA_CH8_SUB1_EP ==
++ virt_to_phys(&TxCtrlEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Ctrl to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++
++ case PIPE_INTERRUPT:
++ local_irq_save(flags);
++ /* Disable all Intr EPs belonging to epid */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* Disable EP */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++ local_irq_restore(flags);
++ break;
++
++ case PIPE_ISOCHRONOUS:
++ /* Check if EP still is enabled */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ tc_warn("sync_finish: Disabling Isoc EP for epid:%d\n", epid);
++ /* The EP was enabled, disable it. */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++
++ while((*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Isoc to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++ }
++
++ local_irq_save(flags);
++
++ /* Finish if there is active URB for this endpoint */
++ if(activeUrbList[epid] != NULL) {
++ urb = activeUrbList[epid];
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv);
++ tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ tc_finish_urb(hcd, activeUrbList[epid], -ENOENT);
++ ASSERT(activeUrbList[epid] == NULL);
++ }
++
++ /* Finish any queued URBs for this endpoint. There won't be any resubmitions
++ because epid_disabled causes enqueue() to fail for this endpoint */
++ while((urb = urb_list_first(epid)) != NULL) {
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv);
++
++ tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ tc_finish_urb(hcd, urb, -ENOENT);
++ }
++ epid_state[epid].disabled = 0;
++ local_irq_restore(flags);
++}
++
++/* free resources associated with an endpoint (called from hcd_driver) */
++static void tc_endpoint_disable(struct usb_hcd *hcd,
++ struct usb_host_endpoint *ep) {
++ DBFENTER;
++ /* Only free epid if it has been allocated. We get two endpoint_disable
++ requests for ctrl endpoints so ignore the second one */
++ if(ep->hcpriv != NULL) {
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ int epid = ep_priv->epid;
++ tc_warn("endpoint_disable ep:0x%x ep-priv:0x%x (%s) (epid:%d freed)\n",
++ (unsigned int)ep, (unsigned int)ep->hcpriv,
++ endpoint_to_str(&(ep->desc)), epid);
++
++ tc_sync_finish_epid(hcd, epid);
++
++ ASSERT(activeUrbList[epid] == NULL);
++ ASSERT(list_empty(&urb_list[epid]));
++
++ tc_free_epid(ep);
++ } else {
++ tc_dbg("endpoint_disable ep:0x%x ep-priv:0x%x (%s)\n", (unsigned int)ep,
++ (unsigned int)ep->hcpriv, endpoint_to_str(&(ep->desc)));
++ }
++ DBFEXIT;
++}
++
++static void tc_finish_urb_later_proc(void *data) {
++ unsigned long flags;
++ struct urb_later_data* uld = (struct urb_later_data*)data;
++ local_irq_save(flags);
++ if(uld->urb == NULL) {
++ late_dbg("Later finish of URB = NULL (allready finished)\n");
++ } else {
++ struct crisv10_urb_priv* urb_priv = uld->urb->hcpriv;
++ ASSERT(urb_priv);
++ if(urb_priv->urb_num == uld->urb_num) {
++ late_dbg("Later finish of URB:0x%x[%d]\n", (unsigned int)(uld->urb),
++ urb_priv->urb_num);
++ if(uld->status != uld->urb->status) {
++ errno_dbg("Later-finish URB with status:%d, later-status:%d\n",
++ uld->urb->status, uld->status);
++ }
++ if(uld != urb_priv->later_data) {
++ panic("Scheduled uld not same as URBs uld\n");
++ }
++ tc_finish_urb(uld->hcd, uld->urb, uld->status);
++ } else {
++ late_warn("Ignoring later finish of URB:0x%x[%d]"
++ ", urb_num doesn't match current URB:0x%x[%d]",
++ (unsigned int)(uld->urb), uld->urb_num,
++ (unsigned int)(uld->urb), urb_priv->urb_num);
++ }
++ }
++ local_irq_restore(flags);
++ kmem_cache_free(later_data_cache, uld);
++}
++
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++ int status) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ struct urb_later_data* uld;
++
++ ASSERT(urb_priv);
++
++ if(urb_priv->later_data != NULL) {
++ /* Later-finish allready scheduled for this URB, just update status to
++ return when finishing later */
++ errno_dbg("Later-finish schedule change URB status:%d with new"
++ " status:%d\n", urb_priv->later_data->status, status);
++
++ urb_priv->later_data->status = status;
++ return;
++ }
++
++ uld = kmem_cache_alloc(later_data_cache, SLAB_ATOMIC);
++ ASSERT(uld);
++
++ uld->hcd = hcd;
++ uld->urb = urb;
++ uld->urb_num = urb_priv->urb_num;
++ uld->status = status;
++
++ INIT_WORK(&uld->ws, tc_finish_urb_later_proc, uld);
++ urb_priv->later_data = uld;
++
++ /* Schedule the finishing of the URB to happen later */
++ schedule_delayed_work(&uld->ws, LATER_TIMER_DELAY);
++}
++
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++ int status);
++
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status) {
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid;
++ char toggle;
++ int urb_num;
++
++ DBFENTER;
++ ASSERT(urb_priv != NULL);
++ epid = urb_priv->epid;
++ urb_num = urb_priv->urb_num;
++
++ if(urb != activeUrbList[epid]) {
++ if(urb_list_entry(urb, epid)) {
++ /* Remove this URB from the list. Only happens when URB are finished
++ before having been processed (dequeing) */
++ urb_list_del(urb, epid);
++ } else {
++ tc_warn("Finishing of URB:0x%x[%d] neither active or in queue for"
++ " epid:%d\n", (unsigned int)urb, urb_num, epid);
++ }
++ }
++
++ /* Cancel any pending later-finish of this URB */
++ if(urb_priv->later_data) {
++ urb_priv->later_data->urb = NULL;
++ }
++
++ /* 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. */
++ if (status == 0 && urb->status == -EINPROGRESS) {
++ urb->actual_length = urb->transfer_buffer_length;
++ } else {
++ /* We wouldn't know of any partial writes if there was an error. */
++ urb->actual_length = 0;
++ }
++ }
++
++
++ /* URB status mangling */
++ if(urb->status == -EINPROGRESS) {
++ /* The USB core hasn't changed the status, let's set our finish status */
++ urb->status = status;
++
++ if ((status == 0) && (urb->transfer_flags & URB_SHORT_NOT_OK) &&
++ usb_pipein(urb->pipe) &&
++ (urb->actual_length != urb->transfer_buffer_length)) {
++ /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's
++ max length) is to be treated as an error. */
++ errno_dbg("Finishing URB:0x%x[%d] with SHORT_NOT_OK flag and short"
++ " data:%d\n", (unsigned int)urb, urb_num,
++ urb->actual_length);
++ urb->status = -EREMOTEIO;
++ }
++
++ if(urb_priv->urb_state == UNLINK) {
++ /* URB has been requested to be unlinked asynchronously */
++ urb->status = -ECONNRESET;
++ errno_dbg("Fixing unlink status of URB:0x%x[%d] to:%d\n",
++ (unsigned int)urb, urb_num, urb->status);
++ }
++ } else {
++ /* The USB Core wants to signal some error via the URB, pass it through */
++ }
++
++ /* use completely different finish function for Isoc URBs */
++ if(usb_pipeisoc(urb->pipe)) {
++ tc_finish_isoc_urb(hcd, urb, status);
++ return;
++ }
++
++ /* Do special unlinking of EPs for Intr traffic */
++ if(usb_pipeint(urb->pipe)) {
++ tc_dma_unlink_intr_urb(urb);
++ }
++
++ /* Release allocated bandwidth for periodic transfers */
++ if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe))
++ usb_release_bandwidth(urb->dev, urb, 0);
++
++ /* This URB is active on EP */
++ if(urb == activeUrbList[epid]) {
++ /* We need to fiddle with the toggle bits because the hardware doesn't do
++ it for us. */
++ toggle = etrax_epid_get_toggle(epid, usb_pipeout(urb->pipe));
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), toggle);
++
++ /* Checks for Ctrl and Bulk EPs */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Check so Bulk EP realy is disabled before finishing active URB */
++ ASSERT((TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++ IO_STATE(USB_EP_command, enable, no));
++ /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++ process Bulk EP. */
++ TxBulkEPList[epid].sub = 0;
++ /* 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]);
++ break;
++ case PIPE_CONTROL:
++ /* Check so Ctrl EP realy is disabled before finishing active URB */
++ ASSERT((TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++ IO_STATE(USB_EP_command, enable, no));
++ /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++ process Ctrl EP. */
++ TxCtrlEPList[epid].sub = 0;
++ break;
++ }
++ }
++
++ /* Free HC-private URB data*/
++ urb_priv_free(hcd, urb);
++
++ if(urb->status) {
++ errno_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++ (unsigned int)urb, urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb->actual_length, urb->status);
++ } else {
++ tc_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++ (unsigned int)urb, urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb->actual_length, urb->status);
++ }
++
++ /* If we just finished an active URB, clear active pointer. */
++ if (urb == activeUrbList[epid]) {
++ /* Make URB not active on EP anymore */
++ activeUrbList[epid] = NULL;
++
++ if(urb->status == 0) {
++ /* URB finished sucessfully, process queue to see if there are any more
++ URBs waiting before we call completion function.*/
++ if(crisv10_hcd->running) {
++ /* Only process queue if USB controller is running */
++ tc_dma_process_queue(epid);
++ } else {
++ tc_warn("No processing of queue for epid:%d, USB Controller not"
++ " running\n", epid);
++ }
++ }
++ }
++
++ /* Hand the URB from HCD to its USB device driver, using its completion
++ functions */
++ usb_hcd_giveback_urb (hcd, urb);
++
++ /* Check the queue once more if the URB returned with error, because we
++ didn't do it before the completion function because the specification
++ states that the queue should not restart until all it's unlinked
++ URBs have been fully retired, with the completion functions run */
++ if(crisv10_hcd->running) {
++ /* Only process queue if USB controller is running */
++ tc_dma_process_queue(epid);
++ } else {
++ tc_warn("No processing of queue for epid:%d, USB Controller not running\n",
++ epid);
++ }
++
++ DBFEXIT;
++}
++
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++ int status) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid, i;
++ volatile int timeout = 10000;
++
++ ASSERT(urb_priv);
++ epid = urb_priv->epid;
++
++ ASSERT(usb_pipeisoc(urb->pipe));
++
++ /* Set 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;
++ }
++
++ /* Check if the URB is currently active (done or error) */
++ if(urb == activeUrbList[epid]) {
++ /* Check if there are another In Isoc URB queued for this epid */
++ if (!list_empty(&urb_list[epid])&& !epid_state[epid].disabled) {
++ /* Move it from queue to active and mark it started so Isoc transfers
++ won't be interrupted.
++ All Isoc URBs data transfers are already added to DMA lists so we
++ don't have to insert anything in DMA lists here. */
++ activeUrbList[epid] = urb_list_first(epid);
++ ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_state =
++ STARTED;
++ urb_list_del(activeUrbList[epid], epid);
++
++ if(urb->status) {
++ errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++ " status:%d, new waiting URB:0x%x[%d]\n",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb_priv->isoc_packet_counter,
++ urb->number_of_packets, urb->status,
++ (unsigned int)activeUrbList[epid],
++ ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_num);
++ }
++
++ } else { /* No other URB queued for this epid */
++ if(urb->status) {
++ errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++ " status:%d, no new URB waiting\n",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb_priv->isoc_packet_counter,
++ urb->number_of_packets, urb->status);
++ }
++
++ /* Check if EP is still enabled, then shut it down. */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ isoc_dbg("Isoc EP enabled for epid:%d, disabling it\n", epid);
++
++ /* Should only occur for In Isoc EPs where SB isn't consumed. */
++ ASSERT(usb_pipein(urb->pipe));
++
++ /* Disable it and wait for it to stop */
++ 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])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Isoc to leave EP for epid:%d\n", epid);
++ }
++ }
++
++ /* Unlink SB to say that epid is finished. */
++ TxIsocEPList[epid].sub = 0;
++ TxIsocEPList[epid].hw_len = 0;
++
++ /* No URB active for EP anymore */
++ activeUrbList[epid] = NULL;
++ }
++ } else { /* Finishing of not active URB (queued up with SBs thought) */
++ isoc_warn("finish_isoc_urb (URB:0x%x %s) (%d of %d packets) status:%d,"
++ " SB queued but not active\n",
++ (unsigned int)urb, str_dir(urb->pipe),
++ urb_priv->isoc_packet_counter, urb->number_of_packets,
++ urb->status);
++ if(usb_pipeout(urb->pipe)) {
++ /* Finishing of not yet active Out Isoc URB needs unlinking of SBs. */
++ struct USB_SB_Desc *iter_sb, *prev_sb, *next_sb;
++
++ iter_sb = TxIsocEPList[epid].sub ?
++ phys_to_virt(TxIsocEPList[epid].sub) : 0;
++ prev_sb = 0;
++
++ /* SB that is linked before this URBs first SB */
++ 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. */
++ isoc_dbg("Isoc urb not found, already sent?\n");
++ 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;
++ }
++ }
++ }
++
++ /* Free HC-private URB data*/
++ urb_priv_free(hcd, urb);
++
++ usb_release_bandwidth(urb->dev, urb, 0);
++
++ /* Hand the URB from HCD to its USB device driver, using its completion
++ functions */
++ usb_hcd_giveback_urb (hcd, urb);
++}
++
++static __u32 urb_num = 0;
++
++/* allocate and initialize URB private data */
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++ int mem_flags) {
++ struct crisv10_urb_priv *urb_priv;
++
++ urb_priv = kmalloc(sizeof *urb_priv, mem_flags);
++ if (!urb_priv)
++ return -ENOMEM;
++ memset(urb_priv, 0, sizeof *urb_priv);
++
++ urb_priv->epid = epid;
++ urb_priv->urb_state = NOT_STARTED;
++
++ urb->hcpriv = urb_priv;
++ /* Assign URB a sequence number, and increment counter */
++ urb_priv->urb_num = urb_num;
++ urb_num++;
++ return 0;
++}
++
++/* free URB private data */
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb) {
++ int i;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ ASSERT(urb_priv != 0);
++
++ /* Check it has any SBs linked that needs to be freed*/
++ if(urb_priv->first_sb != NULL) {
++ struct USB_SB_Desc *next_sb, *first_sb, *last_sb;
++ int i = 0;
++ first_sb = urb_priv->first_sb;
++ last_sb = urb_priv->last_sb;
++ ASSERT(last_sb);
++ while(first_sb != last_sb) {
++ next_sb = (struct USB_SB_Desc *)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++;
++ }
++
++ /* Check if it has any EPs in its Intr pool that also needs to be freed */
++ if(urb_priv->intr_ep_pool_length > 0) {
++ for(i = 0; i < urb_priv->intr_ep_pool_length; i++) {
++ kfree(urb_priv->intr_ep_pool[i]);
++ }
++ /*
++ tc_dbg("Freed %d EPs from URB:0x%x EP pool\n",
++ urb_priv->intr_ep_pool_length, (unsigned int)urb);
++ */
++ }
++
++ kfree(urb_priv);
++ urb->hcpriv = NULL;
++}
++
++static int ep_priv_create(struct usb_host_endpoint *ep, int mem_flags) {
++ struct crisv10_ep_priv *ep_priv;
++
++ ep_priv = kmalloc(sizeof *ep_priv, mem_flags);
++ if (!ep_priv)
++ return -ENOMEM;
++ memset(ep_priv, 0, sizeof *ep_priv);
++
++ ep->hcpriv = ep_priv;
++ return 0;
++}
++
++static void ep_priv_free(struct usb_host_endpoint *ep) {
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ ASSERT(ep_priv);
++ kfree(ep_priv);
++ ep->hcpriv = NULL;
++}
++
++/* EPID handling functions, managing EP-list in Etrax through wrappers */
++/* ------------------------------------------------------------------- */
++
++/* Sets up a new EPID for an endpoint or returns existing if found */
++static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++ int mem_flags) {
++ int epid;
++ char devnum, endpoint, out_traffic, slow;
++ int maxlen;
++ __u32 epid_data;
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++
++ DBFENTER;
++
++ /* Check if a valid epid already is setup for this endpoint */
++ if(ep_priv != NULL) {
++ return ep_priv->epid;
++ }
++
++ /* We must find and initiate a new epid for this urb. */
++ epid = tc_allocate_epid();
++
++ if (epid == -1) {
++ /* Failed to allocate a new epid. */
++ DBFEXIT;
++ return epid;
++ }
++
++ /* We now have a new epid to use. Claim it. */
++ epid_state[epid].inuse = 1;
++
++ /* Init private data for new endpoint */
++ if(ep_priv_create(ep, mem_flags) != 0) {
++ return -ENOMEM;
++ }
++ ep_priv = ep->hcpriv;
++ ep_priv->epid = epid;
++
++ devnum = usb_pipedevice(urb->pipe);
++ endpoint = usb_pipeendpoint(urb->pipe);
++ slow = (urb->dev->speed == USB_SPEED_LOW);
++ 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);
++ }
++
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ epid_data = 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);
++ etrax_epid_iso_set(epid, epid_data);
++ } else {
++ epid_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);
++ etrax_epid_set(epid, epid_data);
++ }
++
++ epid_state[epid].out_traffic = out_traffic;
++ epid_state[epid].type = usb_pipetype(urb->pipe);
++
++ tc_warn("Setting up ep:0x%x epid:%d (addr:%d endp:%d max_len:%d %s %s %s)\n",
++ (unsigned int)ep, epid, devnum, endpoint, maxlen,
++ str_type(urb->pipe), out_traffic ? "out" : "in",
++ slow ? "low" : "full");
++
++ /* Enable Isoc eof interrupt if we set up the first Isoc epid */
++ if(usb_pipeisoc(urb->pipe)) {
++ isoc_epid_counter++;
++ if(isoc_epid_counter == 1) {
++ isoc_warn("Enabled Isoc eof interrupt\n");
++ *R_USB_IRQ_MASK_SET |= IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++ }
++ }
++
++ DBFEXIT;
++ return epid;
++}
++
++static void tc_free_epid(struct usb_host_endpoint *ep) {
++ unsigned long flags;
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ int epid;
++ volatile int timeout = 10000;
++
++ DBFENTER;
++
++ if (ep_priv == NULL) {
++ tc_warn("Trying to free unused epid on ep:0x%x\n", (unsigned int)ep);
++ DBFEXIT;
++ return;
++ }
++
++ epid = ep_priv->epid;
++
++ /* Disable Isoc eof interrupt if we free the last Isoc epid */
++ if(epid_isoc(epid)) {
++ ASSERT(isoc_epid_counter > 0);
++ isoc_epid_counter--;
++ if(isoc_epid_counter == 0) {
++ *R_USB_IRQ_MASK_SET &= ~IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++ isoc_warn("Disabled Isoc eof interrupt\n");
++ }
++ }
++
++ /* Take lock manualy instead of in epid_x_x wrappers,
++ because we need to be polling here */
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++
++ *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)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for epid:%d to drop hold\n", epid);
++ }
++ /* This will, among other things, set the valid field to 0. */
++ *R_USB_EPT_DATA = 0;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++
++ /* Free resource in software state info list */
++ epid_state[epid].inuse = 0;
++
++ /* Free private endpoint data */
++ ep_priv_free(ep);
++
++ DBFEXIT;
++}
++
++static int tc_allocate_epid(void) {
++ int i;
++ DBFENTER;
++ for (i = 0; i < NBR_OF_EPIDS; i++) {
++ if (!epid_inuse(i)) {
++ DBFEXIT;
++ return i;
++ }
++ }
++
++ tc_warn("Found no free epids\n");
++ DBFEXIT;
++ return -1;
++}
++
++
++/* Wrappers around the list functions (include/linux/list.h). */
++/* ---------------------------------------------------------- */
++static inline int __urb_list_empty(int epid) {
++ int retval;
++ retval = list_empty(&urb_list[epid]);
++ return retval;
++}
++
++/* Returns first urb for this epid, or NULL if list is empty. */
++static inline struct urb *urb_list_first(int epid) {
++ unsigned long flags;
++ struct urb *first_urb = 0;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ 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;
++ }
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ 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, int mem_flags) {
++ unsigned long flags;
++ urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), mem_flags);
++ ASSERT(urb_entry);
++
++ urb_entry->urb = urb;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ list_add_tail(&urb_entry->list, &urb_list[epid]);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++}
++
++/* 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.)
++ Should be protected by spin_locks in calling function */
++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;
++}
++
++/* Same function as above but for global use. Protects list by spinlock */
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return (urb_entry);
++}
++
++/* Delete an urb from the list. */
++static inline void urb_list_del(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ /* Delete entry and free. */
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ list_del(&urb_entry->list);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ kfree(urb_entry);
++}
++
++/* Move an urb to the end of the list. */
++static inline void urb_list_move_last(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ list_del(&urb_entry->list);
++ list_add_tail(&urb_entry->list, &urb_list[epid]);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++}
++
++/* Get the next urb in the list. */
++static inline struct urb *urb_list_next(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ spin_lock_irqsave(&urb_list_lock, flags);
++ 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);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return urb_entry->urb;
++ } else {
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return NULL;
++ }
++}
++
++struct USB_EP_Desc* create_ep(int epid, struct USB_SB_Desc* sb_desc,
++ int mem_flags) {
++ struct USB_EP_Desc *ep_desc;
++ ep_desc = (struct USB_EP_Desc *) kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(ep_desc == NULL)
++ return NULL;
++ memset(ep_desc, 0, sizeof(struct USB_EP_Desc));
++
++ ep_desc->hw_len = 0;
++ ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
++ IO_STATE(USB_EP_command, enable, yes));
++ if(sb_desc == NULL) {
++ ep_desc->sub = 0;
++ } else {
++ ep_desc->sub = virt_to_phys(sb_desc);
++ }
++ return ep_desc;
++}
++
++#define TT_ZOUT 0
++#define TT_IN 1
++#define TT_OUT 2
++#define TT_SETUP 3
++
++#define CMD_EOL IO_STATE(USB_SB_command, eol, yes)
++#define CMD_INTR IO_STATE(USB_SB_command, intr, yes)
++#define CMD_FULL IO_STATE(USB_SB_command, full, yes)
++
++/* Allocation and setup of a generic SB. Used to create SETUP, OUT and ZOUT
++ SBs. Also used by create_sb_in() to avoid same allocation procedure at two
++ places */
++struct USB_SB_Desc* create_sb(struct USB_SB_Desc* sb_prev, int tt, void* data,
++ int datalen, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++ memset(sb_desc, 0, sizeof(struct USB_SB_Desc));
++
++ sb_desc->command = IO_FIELD(USB_SB_command, tt, tt) |
++ IO_STATE(USB_SB_command, eot, yes);
++
++ sb_desc->sw_len = datalen;
++ if(data != NULL) {
++ sb_desc->buf = virt_to_phys(data);
++ } else {
++ sb_desc->buf = 0;
++ }
++ if(sb_prev != NULL) {
++ sb_prev->next = virt_to_phys(sb_desc);
++ }
++ return sb_desc;
++}
++
++/* Creates a copy of an existing SB by allocation space for it and copy
++ settings */
++struct USB_SB_Desc* create_sb_copy(struct USB_SB_Desc* sb_orig, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++
++ memcpy(sb_desc, sb_orig, sizeof(struct USB_SB_Desc));
++ return sb_desc;
++}
++
++/* A specific create_sb function for creation of in SBs. This is due to
++ that datalen in In SBs shows how many packets we are expecting. It also
++ sets up the rem field to show if how many bytes we expect in last packet
++ if it's not a full one */
++struct USB_SB_Desc* create_sb_in(struct USB_SB_Desc* sb_prev, int datalen,
++ int maxlen, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = create_sb(sb_prev, TT_IN, NULL,
++ datalen ? (datalen - 1) / maxlen + 1 : 0, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++ sb_desc->command |= IO_FIELD(USB_SB_command, rem, datalen % maxlen);
++ return sb_desc;
++}
++
++void set_sb_cmds(struct USB_SB_Desc *sb_desc, __u16 flags) {
++ sb_desc->command |= flags;
++}
++
++int create_sb_for_urb(struct urb *urb, int mem_flags) {
++ int is_out = !usb_pipein(urb->pipe);
++ int type = usb_pipetype(urb->pipe);
++ int maxlen = usb_maxpacket(urb->dev, urb->pipe, is_out);
++ int buf_len = urb->transfer_buffer_length;
++ void *buf = buf_len > 0 ? urb->transfer_buffer : NULL;
++ struct USB_SB_Desc *sb_desc = NULL;
++
++ struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv != NULL);
++
++ switch(type) {
++ case PIPE_CONTROL:
++ /* Setup stage */
++ sb_desc = create_sb(NULL, TT_SETUP, urb->setup_packet, 8, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++
++ /* Attach first SB to URB */
++ urb_priv->first_sb = sb_desc;
++
++ if (is_out) { /* Out Control URB */
++ /* If this Control OUT transfer has an optional data stage we add
++ an OUT token before the mandatory IN (status) token */
++ if ((buf_len > 0) && buf) {
++ sb_desc = create_sb(sb_desc, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++
++ /* Status stage */
++ /* The data length has to be exactly 1. This is due to a requirement
++ of the USB specification that a host must be prepared to receive
++ data in the status phase */
++ sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ } else { /* In control URB */
++ /* Data stage */
++ sb_desc = create_sb_in(sb_desc, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* Status stage */
++ /* Read comment at zout_buffer declaration for an explanation to this. */
++ sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* Set descriptor interrupt flag for in URBs so we can finish URB after
++ zout-packet has been sent */
++ set_sb_cmds(sb_desc, CMD_INTR | CMD_FULL);
++ }
++ /* Set end-of-list flag in last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++ /* Attach last SB to URB */
++ urb_priv->last_sb = sb_desc;
++ break;
++
++ case PIPE_BULK:
++ if (is_out) { /* Out Bulk URB */
++ sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* 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)) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ } else { /* In Bulk URB */
++ sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ }
++ /* Set end-of-list flag for last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++ break;
++
++ case PIPE_INTERRUPT:
++ if(is_out) { /* Out Intr URB */
++ sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* 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)) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ /* Only generate TX interrupt if it's a Out URB*/
++ set_sb_cmds(sb_desc, CMD_INTR);
++
++ } else { /* In Intr URB */
++ sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ }
++ /* Set end-of-list flag for last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++
++ break;
++ case PIPE_ISOCHRONOUS:
++ if(is_out) { /* Out Isoc URB */
++ int i;
++ if(urb->number_of_packets == 0) {
++ tc_err("Can't create SBs for Isoc URB with zero packets\n");
++ return -EPIPE;
++ }
++ /* 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 > 0) {
++
++ sb_desc = create_sb(sb_desc, TT_OUT, urb->transfer_buffer +
++ urb->iso_frame_desc[i].offset,
++ urb->iso_frame_desc[i].length, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* Check if it's a full length packet */
++ if (urb->iso_frame_desc[i].length ==
++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++
++ } else { /* zero length packet */
++ sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ /* Attach first SB descriptor to URB */
++ if (i == 0) {
++ urb_priv->first_sb = sb_desc;
++ }
++ }
++ /* Set interrupt and end-of-list flags in last SB */
++ set_sb_cmds(sb_desc, CMD_INTR | CMD_EOL);
++ /* Attach last SB descriptor to URB */
++ urb_priv->last_sb = sb_desc;
++ tc_dbg("Created %d out SBs for Isoc URB:0x%x\n",
++ urb->number_of_packets, (unsigned int)urb);
++ } else { /* In Isoc URB */
++ /* Actual number of packets is not relevant for periodic in traffic as
++ long as it is more than zero. Set to 1 always. */
++ sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* Set end-of-list flags for SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++ }
++ break;
++ default:
++ tc_err("Unknown pipe-type\n");
++ return -EPIPE;
++ break;
++ }
++ return 0;
++}
++
++int init_intr_urb(struct urb *urb, int mem_flags) {
++ struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ struct USB_EP_Desc* ep_desc;
++ int interval;
++ int i;
++ int ep_count;
++
++ ASSERT(urb_priv != NULL);
++ ASSERT(usb_pipeint(urb->pipe));
++ /* We can't support interval longer than amount of eof descriptors in
++ TxIntrEPList */
++ if(urb->interval > MAX_INTR_INTERVAL) {
++ tc_err("Interrupt interval %dms too big (max: %dms)\n", urb->interval,
++ MAX_INTR_INTERVAL);
++ return -EINVAL;
++ }
++
++ /* We assume that the SB descriptors already have been setup */
++ ASSERT(urb_priv->first_sb != NULL);
++
++ /* 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. */
++ interval = urb->interval;
++ for (i = 0; interval; i++) {
++ interval = interval >> 1;
++ }
++ urb_priv->interval = 1 << (i - 1);
++
++ /* We can only have max interval for Out Interrupt due to that we can only
++ handle one linked in EP for a certain epid in the Intr descr array at the
++ time. The USB Controller in the Etrax 100LX continues to process Intr EPs
++ so we have no way of knowing which one that caused the actual transfer if
++ we have several linked in. */
++ if(usb_pipeout(urb->pipe)) {
++ urb_priv->interval = MAX_INTR_INTERVAL;
++ }
++
++ /* Calculate amount of EPs needed */
++ ep_count = MAX_INTR_INTERVAL / urb_priv->interval;
++
++ for(i = 0; i < ep_count; i++) {
++ ep_desc = create_ep(urb_priv->epid, urb_priv->first_sb, mem_flags);
++ if(ep_desc == NULL) {
++ /* Free any descriptors that we may have allocated before failure */
++ while(i > 0) {
++ i--;
++ kfree(urb_priv->intr_ep_pool[i]);
++ }
++ return -ENOMEM;
++ }
++ urb_priv->intr_ep_pool[i] = ep_desc;
++ }
++ urb_priv->intr_ep_pool_length = ep_count;
++ return 0;
++}
++
++/* DMA RX/TX functions */
++/* ----------------------- */
++
++static void tc_dma_init_rx_list(void) {
++ int i;
++
++ /* Setup descriptor list except last one */
++ 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]);
++
++ }
++ /* Special handling of last descriptor */
++ 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;
++
++ /* Setup list pointers that show progress in list */
++ myNextRxDesc = &RxDescList[0];
++ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
++
++ flush_etrax_cache();
++ /* Point DMA to first descriptor in list and start it */
++ *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
++ *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
++}
++
++
++static void tc_dma_init_tx_bulk_list(void) {
++ int i;
++ volatile struct USB_EP_Desc *epDescr;
++
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ epDescr = &(TxBulkEPList[i]);
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->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]);
++ }
++
++ /* Special handling of last descr in list, make list circular */
++ epDescr = &TxBulkEPList[i];
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxBulkEPList[0]);
++
++ /* Init DMA sub-channel pointers to last item in each list */
++ *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); */
++}
++
++static void tc_dma_init_tx_ctrl_list(void) {
++ int i;
++ volatile struct USB_EP_Desc *epDescr;
++
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ epDescr = &(TxCtrlEPList[i]);
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxCtrlEPList[i + 1]);
++ }
++ /* Special handling of last descr in list, make list circular */
++ epDescr = &TxCtrlEPList[i];
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxCtrlEPList[0]);
++
++ /* Init DMA sub-channel pointers to last item in each list */
++ *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[i]);
++ /* No point in starting the ctrl channel yet.
++ *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
++}
++
++
++static void tc_dma_init_tx_intr_list(void) {
++ int i;
++
++ 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]);
++ }
++
++ /* Special handling of last descr in list, make list circular */
++ 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]);
++
++ intr_dbg("Initiated Intr EP descriptor list\n");
++
++
++ /* Connect DMA 8 sub-channel 2 to first in list */
++ *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
++}
++
++static void tc_dma_init_tx_isoc_list(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);
++}
++
++static int tc_dma_init(struct usb_hcd *hcd) {
++ tc_dma_init_rx_list();
++ tc_dma_init_tx_bulk_list();
++ tc_dma_init_tx_ctrl_list();
++ tc_dma_init_tx_intr_list();
++ tc_dma_init_tx_isoc_list();
++
++ if (cris_request_dma(USB_TX_DMA_NBR,
++ "ETRAX 100LX built-in USB (Tx)",
++ DMA_VERBOSE_ON_ERROR,
++ dma_usb)) {
++ err("Could not allocate DMA ch 8 for USB");
++ return -EBUSY;
++ }
++
++ if (cris_request_dma(USB_RX_DMA_NBR,
++ "ETRAX 100LX built-in USB (Rx)",
++ DMA_VERBOSE_ON_ERROR,
++ dma_usb)) {
++ err("Could not allocate DMA ch 9 for USB");
++ return -EBUSY;
++ }
++
++ *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);
++
++ if (request_irq(ETRAX_USB_RX_IRQ, tc_dma_rx_interrupt, 0,
++ "ETRAX 100LX built-in USB (Rx)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
++ return -EBUSY;
++ }
++
++ if (request_irq(ETRAX_USB_TX_IRQ, tc_dma_tx_interrupt, 0,
++ "ETRAX 100LX built-in USB (Tx)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++static void tc_dma_destroy(void) {
++ free_irq(ETRAX_USB_RX_IRQ, NULL);
++ free_irq(ETRAX_USB_TX_IRQ, NULL);
++
++ cris_free_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)");
++ cris_free_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)");
++
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb);
++
++/* Handle processing of Bulk, Ctrl and Intr queues */
++static void tc_dma_process_queue(int epid) {
++ struct urb *urb;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ unsigned long flags;
++ char toggle;
++
++ if(epid_state[epid].disabled) {
++ /* Don't process any URBs on a disabled endpoint */
++ return;
++ }
++
++ /* Do not disturb us while fiddling with EPs and epids */
++ local_irq_save(flags);
++
++ /* For bulk, Ctrl and Intr can we only have one URB active at a time for
++ a specific EP. */
++ if(activeUrbList[epid] != NULL) {
++ /* An URB is already active on EP, skip checking queue */
++ local_irq_restore(flags);
++ return;
++ }
++
++ urb = urb_list_first(epid);
++ if(urb == NULL) {
++ /* No URB waiting in EP queue. Nothing do to */
++ local_irq_restore(flags);
++ return;
++ }
++
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv != NULL);
++ ASSERT(urb_priv->urb_state == NOT_STARTED);
++ ASSERT(!usb_pipeisoc(urb->pipe));
++
++ /* Remove this URB from the queue and move it to active */
++ activeUrbList[epid] = urb;
++ urb_list_del(urb, epid);
++
++ urb_priv->urb_state = STARTED;
++
++ /* Reset error counters (regardless of which direction this traffic is). */
++ etrax_epid_clear_error(epid);
++
++ /* Special handling of Intr EP lists */
++ if(usb_pipeint(urb->pipe)) {
++ tc_dma_link_intr_urb(urb);
++ local_irq_restore(flags);
++ return;
++ }
++
++ /* Software must preset the toggle bits for Bulk and Ctrl */
++ if(usb_pipecontrol(urb->pipe)) {
++ /* Toggle bits are initialized only during setup transaction in a
++ CTRL transfer */
++ etrax_epid_set_toggle(epid, 0, 0);
++ etrax_epid_set_toggle(epid, 1, 0);
++ } else {
++ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe));
++ etrax_epid_set_toggle(epid, usb_pipeout(urb->pipe), toggle);
++ }
++
++ tc_dbg("Added SBs from (URB:0x%x %s %s) to epid %d: %s\n",
++ (unsigned int)urb, str_dir(urb->pipe), str_type(urb->pipe), epid,
++ sblist_to_str(urb_priv->first_sb));
++
++ /* 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. */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Assert that the EP descriptor is disabled. */
++ ASSERT(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
++
++ /* Set up and enable the EP descriptor. */
++ TxBulkEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ TxBulkEPList[epid].hw_len = 0;
++ TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ /* Check if the dummy list is already with us (if several urbs were queued). */
++ if (usb_pipein(urb->pipe) && (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0]))) {
++ tc_dbg("Inviting dummy list to the party for urb 0x%lx, epid %d",
++ (unsigned long)urb, epid);
++
++ /* 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]);
++ }
++
++ restart_dma8_sub0();
++
++ /* 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);
++ break;
++ case PIPE_CONTROL:
++ /* 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(urb_priv->first_sb);
++ TxCtrlEPList[epid].hw_len = 0;
++ TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
++ break;
++ }
++ local_irq_restore(flags);
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ volatile struct USB_EP_Desc *tmp_ep;
++ struct USB_EP_Desc *ep_desc;
++ int i = 0, epid;
++ int pool_idx = 0;
++
++ ASSERT(urb_priv != NULL);
++ epid = urb_priv->epid;
++ ASSERT(urb_priv->interval > 0);
++ ASSERT(urb_priv->intr_ep_pool_length > 0);
++
++ tmp_ep = &TxIntrEPList[0];
++
++ /* Only insert one EP descriptor in list for Out Intr URBs.
++ We can only handle Out Intr with interval of 128ms because
++ it's not possible to insert several Out Intr EPs because they
++ are not consumed by the DMA. */
++ if(usb_pipeout(urb->pipe)) {
++ ep_desc = urb_priv->intr_ep_pool[0];
++ ASSERT(ep_desc);
++ ep_desc->next = tmp_ep->next;
++ tmp_ep->next = virt_to_phys(ep_desc);
++ i++;
++ } else {
++ /* Loop through Intr EP descriptor list and insert EP for URB at
++ specified interval */
++ do {
++ /* Each EP descriptor with eof flag sat signals a new frame */
++ if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
++ /* Insert a EP from URBs EP pool at correct interval */
++ if ((i % urb_priv->interval) == 0) {
++ ep_desc = urb_priv->intr_ep_pool[pool_idx];
++ ASSERT(ep_desc);
++ ep_desc->next = tmp_ep->next;
++ tmp_ep->next = virt_to_phys(ep_desc);
++ pool_idx++;
++ ASSERT(pool_idx <= urb_priv->intr_ep_pool_length);
++ }
++ i++;
++ }
++ tmp_ep = (struct USB_EP_Desc *)phys_to_virt(tmp_ep->next);
++ } while(tmp_ep != &TxIntrEPList[0]);
++ }
++
++ intr_dbg("Added SBs to intr epid %d: %s interval:%d (%d EP)\n", epid,
++ sblist_to_str(urb_priv->first_sb), urb_priv->interval, pool_idx);
++
++ /* 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);
++}
++
++static void tc_dma_process_isoc_urb(struct urb *urb) {
++ unsigned long flags;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid;
++
++ /* Do not disturb us while fiddling with EPs and epids */
++ local_irq_save(flags);
++
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->first_sb);
++ epid = urb_priv->epid;
++
++ if(activeUrbList[epid] == NULL) {
++ /* EP is idle, so make this URB active */
++ activeUrbList[epid] = urb;
++ urb_list_del(urb, epid);
++ ASSERT(TxIsocEPList[epid].sub == 0);
++ ASSERT(!(TxIsocEPList[epid].command &
++ IO_STATE(USB_EP_command, enable, yes)));
++
++ /* Differentiate between In and Out Isoc. Because In SBs are not consumed*/
++ if(usb_pipein(urb->pipe)) {
++ /* Each EP for In Isoc will have only one SB descriptor, setup when
++ submitting the first active urb. We do it here by copying from URBs
++ pre-allocated SB. */
++ memcpy((void *)&(TxIsocSBList[epid]), urb_priv->first_sb,
++ sizeof(TxIsocSBList[epid]));
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(&(TxIsocSBList[epid]));
++ } else {
++ /* For Out Isoc we attach the pre-allocated list of SBs for the URB */
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++
++ isoc_dbg("Attached first URB:0x%x[%d] to epid:%d first_sb:0x%x"
++ " last_sb::0x%x\n",
++ (unsigned int)urb, urb_priv->urb_num, epid,
++ (unsigned int)(urb_priv->first_sb),
++ (unsigned int)(urb_priv->last_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;
++ isoc_dbg("URB_ISO_ASAP set, urb->start_frame set to %d\n",
++ urb->start_frame);
++ } else {
++ /* Not started yet. */
++ urb_priv->urb_state = NOT_STARTED;
++ isoc_warn("urb_priv->urb_state set to NOT_STARTED for URB:0x%x\n",
++ (unsigned int)urb);
++ }
++
++ } else {
++ /* An URB is already active on the EP. Leave URB in queue and let
++ finish_isoc_urb process it after current active URB */
++ ASSERT(TxIsocEPList[epid].sub != 0);
++
++ if(usb_pipein(urb->pipe)) {
++ /* Because there already is a active In URB on this epid we do nothing
++ and the finish_isoc_urb() function will handle switching to next URB*/
++
++ } else { /* For Out Isoc, insert new URBs traffic last in SB-list. */
++ struct USB_SB_Desc *temp_sb_desc;
++
++ /* Set state STARTED to all Out Isoc URBs added to SB list because we
++ don't know how many of them that are finished before descr interrupt*/
++ urb_priv->urb_state = STARTED;
++
++ /* Find end of current SB list by looking for SB with eol flag sat */
++ 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);
++ }
++
++ isoc_dbg("Appended URB:0x%x[%d] (first:0x%x last:0x%x) to epid:%d"
++ " sub:0x%x eol:0x%x\n",
++ (unsigned int)urb, urb_priv->urb_num,
++ (unsigned int)(urb_priv->first_sb),
++ (unsigned int)(urb_priv->last_sb), epid,
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)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))) {
++ __u32 epid_data;
++ /* 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. */
++ epid_data = etrax_epid_iso_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) !=
++ IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++ isoc_err("Disabled Isoc EP with error:%d on epid:%d when appending"
++ " URB:0x%x[%d]\n",
++ IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data), epid,
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++
++ /* 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. */
++
++ if(virt_to_phys(temp_sb_desc) == TxIsocEPList[epid].sub) {
++ isoc_dbg("EP for epid:%d stoped at SB:0x%x before newly inserted"
++ ", restarting from this URBs SB:0x%x\n",
++ epid, (unsigned int)temp_sb_desc,
++ (unsigned int)(urb_priv->first_sb));
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
++ /* Enable the EP again so data gets processed this time */
++ TxIsocEPList[epid].command |=
++ IO_STATE(USB_EP_command, enable, yes);
++
++ } else {
++ /* The EP has been disabled but not at end this URB (god knows
++ where). This should generate an epid_attn so we should not be
++ here */
++ isoc_warn("EP was disabled on sb:0x%x before SB list for"
++ " URB:0x%x[%d] got processed\n",
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++ } else {
++ /* This might happend if we are slow on this function and isn't
++ an error. */
++ isoc_dbg("EP was disabled and finished with SBs from appended"
++ " URB:0x%x[%d]\n", (unsigned int)urb, urb_priv->urb_num);
++ }
++ }
++ }
++ }
++
++ /* Start the DMA sub channel */
++ *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
++
++ local_irq_restore(flags);
++}
++
++static void tc_dma_unlink_intr_urb(struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ volatile struct USB_EP_Desc *first_ep; /* First EP in the list. */
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++ volatile struct USB_EP_Desc *unlink_ep; /* The one we should remove from
++ the list. */
++ int count = 0;
++ volatile int timeout = 10000;
++ int epid;
++
++ /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the
++ List". */
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->intr_ep_pool_length > 0);
++ epid = urb_priv->epid;
++
++ /* First disable all Intr EPs belonging to epid for this URB */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* Disable EP */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++
++ /* Now unlink all EPs belonging to this epid from Descr list */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == 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)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Intr to leave unlink EP\n");
++ }
++
++ count++;
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++ if(count != urb_priv->intr_ep_pool_length) {
++ intr_warn("Unlinked %d of %d Intr EPs for URB:0x%x[%d]\n", count,
++ urb_priv->intr_ep_pool_length, (unsigned int)urb,
++ urb_priv->urb_num);
++ } else {
++ intr_dbg("Unlinked %d of %d interrupt EPs for URB:0x%x\n", count,
++ urb_priv->intr_ep_pool_length, (unsigned int)urb);
++ }
++}
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++ int timer) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ __u32 epid_data;
++
++ /* Protect TxEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ /* A finished EP descriptor is disabled and has a valid sub pointer */
++ if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++ (TxBulkEPList[epid].sub != 0)) {
++
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++ /* Sanity checks */
++ ASSERT(urb);
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Only handle finished out Bulk EPs here,
++ and let RX interrupt take care of the rest */
++ if(!epid_out_traffic(epid)) {
++ continue;
++ }
++
++ if(timer) {
++ tc_warn("Found finished %s Bulk epid:%d URB:0x%x[%d] from timeout\n",
++ epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++ urb_priv->urb_num);
++ } else {
++ tc_dbg("Found finished %s Bulk epid:%d URB:0x%x[%d] from interrupt\n",
++ epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++ urb_priv->urb_num);
++ }
++
++ if(urb_priv->urb_state == UNLINK) {
++ /* This Bulk URB is requested to be unlinked, that means that the EP
++ has been disabled and we might not have sent all data */
++ tc_finish_urb(hcd, urb, urb->status);
++ continue;
++ }
++
++ ASSERT(urb_priv->urb_state == STARTED);
++ if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
++ tc_err("Endpoint got disabled before reaching last sb\n");
++ }
++
++ epid_data = etrax_epid_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_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. */
++ tc_finish_urb(hcd, urb, 0);
++ } else {
++ /* Shouldn't happen. We expect errors to be caught by epid
++ attention. */
++ tc_err("Found disabled bulk EP desc (epid:%d error:%d)\n",
++ epid, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++ }
++ } else {
++ tc_dbg("Ignoring In Bulk epid:%d, let RX interrupt handle it\n", epid);
++ }
++ }
++
++ local_irq_restore(flags);
++}
++
++static void check_finished_ctrl_tx_epids(struct usb_hcd *hcd) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ __u32 epid_data;
++
++ /* Protect TxEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if(epid == DUMMY_EPID)
++ continue;
++
++ /* A finished EP descriptor is disabled and has a valid sub pointer */
++ if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++ (TxCtrlEPList[epid].sub != 0)) {
++
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++
++ if(urb == NULL) {
++ tc_warn("Found finished Ctrl epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ /* Sanity checks */
++ ASSERT(usb_pipein(urb->pipe));
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ if (phys_to_virt(TxCtrlEPList[epid].sub) != urb_priv->last_sb) {
++ tc_err("Endpoint got disabled before reaching last sb\n");
++ }
++
++ epid_data = etrax_epid_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_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. */
++
++ /* Check if RX-interrupt for In Ctrl has been processed before
++ finishing the URB */
++ if(urb_priv->ctrl_rx_done) {
++ tc_dbg("Finishing In Ctrl URB:0x%x[%d] in tx_interrupt\n",
++ (unsigned int)urb, urb_priv->urb_num);
++ tc_finish_urb(hcd, urb, 0);
++ } else {
++ /* If we get zout descriptor interrupt before RX was done for a
++ In Ctrl transfer, then we flag that and it will be finished
++ in the RX-Interrupt */
++ urb_priv->ctrl_zout_done = 1;
++ tc_dbg("Got zout descr interrupt before RX interrupt\n");
++ }
++ } else {
++ /* Shouldn't happen. We expect errors to be caught by epid
++ attention. */
++ tc_err("Found disabled Ctrl EP desc (epid:%d URB:0x%x[%d]) error_code:%d\n", epid, (unsigned int)urb, urb_priv->urb_num, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++ __dump_ep_desc(&(TxCtrlEPList[epid]));
++ __dump_ept_data(epid);
++ }
++ }
++ }
++ local_irq_restore(flags);
++}
++
++/* This function goes through all epids that are setup for Out Isoc transfers
++ and marks (isoc_out_done) all queued URBs that the DMA has finished
++ transfer for.
++ No URB completetion is done here to make interrupt routine return quickly.
++ URBs are completed later with help of complete_isoc_bottom_half() that
++ becomes schedules when this functions is finished. */
++static void check_finished_isoc_tx_epids(void) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ struct USB_SB_Desc* sb_desc;
++ int epid_done;
++
++ /* Protect TxIsocEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (TxIsocEPList[epid].sub == 0 || epid == INVALID_EPID ||
++ !epid_out_traffic(epid)) {
++ /* Nothing here to see. */
++ continue;
++ }
++ ASSERT(epid_inuse(epid));
++ ASSERT(epid_isoc(epid));
++
++ 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);
++
++ isoc_dbg("Descr IRQ checking epid:%d sub:0x%x intr:0x%x\n",
++ epid, (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)sb_desc);
++
++ urb = activeUrbList[epid];
++ if(urb == NULL) {
++ isoc_err("Isoc Descr irq on epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ epid_done = 0;
++ while(urb && !epid_done) {
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->urb_state == STARTED ||
++ urb_priv->urb_state == UNLINK);
++
++ if (sb_desc != urb_priv->last_sb) {
++ /* This urb has been sent. */
++ urb_priv->isoc_out_done = 1;
++
++ } else { /* Found URB that has last_sb as the interrupt reason */
++
++ /* Check if EP has been disabled, meaning that all transfers are done*/
++ if(!(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);
++ urb_priv->isoc_out_done = 1;
++ } else {
++ isoc_dbg("Skipping URB:0x%x[%d] because EP not disabled yet\n",
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++ /* Stop looking any further in queue */
++ epid_done = 1;
++ }
++
++ if (!epid_done) {
++ if(urb == activeUrbList[epid]) {
++ urb = urb_list_first(epid);
++ } else {
++ urb = urb_list_next(urb, epid);
++ }
++ }
++ } /* END: while(urb && !epid_done) */
++ }
++
++ local_irq_restore(flags);
++}
++
++
++/* This is where the Out Isoc URBs are realy completed. This function is
++ scheduled from tc_dma_tx_interrupt() when one or more Out Isoc transfers
++ are done. This functions completes all URBs earlier marked with
++ isoc_out_done by fast interrupt routine check_finished_isoc_tx_epids() */
++
++static void complete_isoc_bottom_half(void *data) {
++ struct crisv10_isoc_complete_data *comp_data;
++ struct usb_iso_packet_descriptor *packet;
++ struct crisv10_urb_priv * urb_priv;
++ unsigned long flags;
++ struct urb* urb;
++ int epid_done;
++ int epid;
++ int i;
++
++ comp_data = (struct crisv10_isoc_complete_data*)data;
++
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++ if(!epid_inuse(epid) || !epid_isoc(epid) || !epid_out_traffic(epid) || epid == DUMMY_EPID) {
++ /* Only check valid Out Isoc epids */
++ continue;
++ }
++
++ isoc_dbg("Isoc bottom-half checking epid:%d, sub:0x%x\n", epid,
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub));
++
++ /* The descriptor interrupt handler has marked all transmitted Out Isoc
++ URBs with isoc_out_done. Now we traverse all epids and for all that
++ have out Isoc traffic we traverse its URB list and complete the
++ transmitted URBs. */
++ epid_done = 0;
++ while (!epid_done) {
++
++ /* Get the active urb (if any) */
++ urb = activeUrbList[epid];
++ if (urb == 0) {
++ isoc_dbg("No active URB on epid:%d anymore\n", epid);
++ epid_done = 1;
++ continue;
++ }
++
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ if (!(urb_priv->isoc_out_done)) {
++ /* We have reached URB that isn't flaged done yet, stop traversing. */
++ isoc_dbg("Stoped traversing Out Isoc URBs on epid:%d"
++ " before not yet flaged URB:0x%x[%d]\n",
++ epid, (unsigned int)urb, urb_priv->urb_num);
++ epid_done = 1;
++ continue;
++ }
++
++ /* This urb has been sent. */
++ isoc_dbg("Found URB:0x%x[%d] that is flaged isoc_out_done\n",
++ (unsigned int)urb, urb_priv->urb_num);
++
++ /* Set ok on transfered packets for this URB and finish it */
++ for (i = 0; i < urb->number_of_packets; i++) {
++ packet = &urb->iso_frame_desc[i];
++ packet->status = 0;
++ packet->actual_length = packet->length;
++ }
++ urb_priv->isoc_packet_counter = urb->number_of_packets;
++ tc_finish_urb(comp_data->hcd, urb, 0);
++
++ } /* END: while(!epid_done) */
++ } /* END: for(epid...) */
++
++ local_irq_restore(flags);
++ kmem_cache_free(isoc_compl_cache, comp_data);
++}
++
++
++static void check_finished_intr_tx_epids(struct usb_hcd *hcd) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++
++ /* Protect TxintrEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if(!epid_inuse(epid) || !epid_intr(epid) || !epid_out_traffic(epid)) {
++ /* Nothing to see on this epid. Only check valid Out Intr epids */
++ continue;
++ }
++
++ urb = activeUrbList[epid];
++ if(urb == 0) {
++ intr_warn("Found Out Intr epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_INTERRUPT);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Go through EPs between first and second sof-EP. It's here Out Intr EPs
++ are inserted.*/
++ curr_ep = &TxIntrEPList[0];
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if(next_ep == urb_priv->intr_ep_pool[0]) {
++ /* We found the Out Intr EP for this epid */
++
++ /* Disable it so it doesn't get processed again */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++
++ /* Finish the active Out Intr URB with status OK */
++ tc_finish_urb(hcd, urb, 0);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != &TxIntrEPList[1]);
++
++ }
++ local_irq_restore(flags);
++}
++
++/* Interrupt handler for DMA8/IRQ24 with subchannels (called from hardware intr) */
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc) {
++ struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++ ASSERT(hcd);
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
++ restart_dma8_sub0();
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
++ check_finished_ctrl_tx_epids(hcd);
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
++ check_finished_intr_tx_epids(hcd);
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
++ struct crisv10_isoc_complete_data* comp_data;
++
++ /* Flag done Out Isoc for later completion */
++ check_finished_isoc_tx_epids();
++
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
++ /* Schedule bottom half of Out Isoc completion function. This function
++ finishes the URBs marked with isoc_out_done */
++ comp_data = (struct crisv10_isoc_complete_data*)
++ kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
++ ASSERT(comp_data != NULL);
++ comp_data ->hcd = hcd;
++
++ INIT_WORK(&comp_data->usb_bh, complete_isoc_bottom_half, comp_data);
++ schedule_work(&comp_data->usb_bh);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/* Interrupt handler for DMA9/IRQ25 (called from hardware intr) */
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc) {
++ unsigned long flags;
++ struct urb *urb;
++ struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++ struct crisv10_urb_priv *urb_priv;
++ int epid = 0;
++ int real_error;
++
++ ASSERT(hcd);
++
++ /* Clear this interrupt. */
++ *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
++
++ /* Custom clear interrupt for this interrupt */
++ /* The reason we cli here is that we call the driver's callback functions. */
++ local_irq_save(flags);
++
++ /* Note that this while loop assumes that all packets span only
++ one rx descriptor. */
++ while(myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
++ epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++
++ ASSERT(epid_inuse(epid));
++ if (!urb) {
++ dma_err("No urb for epid %d in rx interrupt\n", epid);
++ goto skip_out;
++ }
++
++ /* Check if any errors on epid */
++ real_error = 0;
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
++ __u32 r_usb_ept_data;
++
++ if (usb_pipeisoc(urb->pipe)) {
++ r_usb_ept_data = etrax_epid_iso_get(epid);
++ 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. Continue processing.
++ */
++ } else real_error = 1;
++ } else real_error = 1;
++ }
++
++ if(real_error) {
++ dma_err("Error in RX descr on epid:%d for URB 0x%x",
++ epid, (unsigned int)urb);
++ dump_ept_data(epid);
++ dump_in_desc(myNextRxDesc);
++ goto skip_out;
++ }
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->urb_state == STARTED ||
++ urb_priv->urb_state == UNLINK);
++
++ if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
++ (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
++ (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
++
++ /* 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. */
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
++ /* No data to copy */
++ } else {
++ /*
++ dma_dbg("Processing RX for URB:0x%x epid:%d (data:%d ofs:%d)\n",
++ (unsigned int)urb, epid, myNextRxDesc->hw_len,
++ urb_priv->rx_offset);
++ */
++ /* Only copy data if URB isn't flaged to be unlinked*/
++ if(urb_priv->urb_state != UNLINK) {
++ /* Make sure the data fits in the buffer. */
++ if(urb_priv->rx_offset + myNextRxDesc->hw_len
++ <= urb->transfer_buffer_length) {
++
++ /* Copy the data to URBs buffer */
++ memcpy(urb->transfer_buffer + urb_priv->rx_offset,
++ phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
++ urb_priv->rx_offset += myNextRxDesc->hw_len;
++ } else {
++ /* Signal overflow when returning URB */
++ urb->status = -EOVERFLOW;
++ tc_finish_urb_later(hcd, urb, urb->status);
++ }
++ }
++ }
++
++ /* Check if it was the last packet in the transfer */
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
++ /* Special handling for In Ctrl URBs. */
++ if(usb_pipecontrol(urb->pipe) && usb_pipein(urb->pipe) &&
++ !(urb_priv->ctrl_zout_done)) {
++ /* Flag that RX part of Ctrl transfer is done. Because zout descr
++ interrupt hasn't happend yet will the URB be finished in the
++ TX-Interrupt. */
++ urb_priv->ctrl_rx_done = 1;
++ tc_dbg("Not finishing In Ctrl URB:0x%x from rx_interrupt, waiting"
++ " for zout\n", (unsigned int)urb);
++ } else {
++ tc_finish_urb(hcd, urb, 0);
++ }
++ }
++ } else { /* ISOC RX */
++ /*
++ isoc_dbg("Processing RX for epid:%d (URB:0x%x) ISOC pipe\n",
++ epid, (unsigned int)urb);
++ */
++
++ struct usb_iso_packet_descriptor *packet;
++
++ if (urb_priv->urb_state == UNLINK) {
++ isoc_warn("Ignoring Isoc Rx data for urb being unlinked.\n");
++ goto skip_out;
++ } else if (urb_priv->urb_state == NOT_STARTED) {
++ isoc_err("What? Got Rx data for Isoc urb that isn't started?\n");
++ goto skip_out;
++ }
++
++ packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
++ ASSERT(packet);
++ 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);
++ if(packet->actual_length > 0)
++ isoc_dbg("Copied %d bytes, packet %d for URB:0x%x[%d]\n",
++ packet->actual_length, urb_priv->isoc_packet_counter,
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++
++ /* 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) {
++ /* Complete the urb with status OK. */
++ tc_finish_urb(hcd, urb, 0);
++ }
++ }
++
++ skip_out:
++ myNextRxDesc->status = 0;
++ myNextRxDesc->command |= IO_MASK(USB_IN_command, eol);
++ myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
++ myLastRxDesc = myNextRxDesc;
++ myNextRxDesc = phys_to_virt(myNextRxDesc->next);
++ flush_etrax_cache();
++ *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, restart);
++ }
++
++ local_irq_restore(flags);
++
++ return IRQ_HANDLED;
++}
++
++static void tc_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. */
++
++ if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
++ int epid;
++
++ timer_dbg("bulk_start_timer: Bulk DMA channel not running.\n");
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ timer_warn("Found enabled EP for epid %d, starting bulk channel.\n",
++ epid);
++ restart_dma8_sub0();
++
++ /* 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 {
++ timer_dbg("bulk_start_timer: Bulk DMA channel running.\n");
++ }
++}
++
++static void tc_bulk_eot_timer_func(unsigned long dummy) {
++ struct usb_hcd *hcd = (struct usb_hcd*)dummy;
++ ASSERT(hcd);
++ /* 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. */
++ timer_dbg("bulk_eot_timer timed out.\n");
++ check_finished_bulk_tx_epids(hcd, 1);
++}
++
++
++/*************************************************************/
++/*************************************************************/
++/* Device driver block */
++/*************************************************************/
++/*************************************************************/
++
++/* Forward declarations for device driver functions */
++static int devdrv_hcd_probe(struct device *);
++static int devdrv_hcd_remove(struct device *);
++#ifdef CONFIG_PM
++static int devdrv_hcd_suspend(struct device *, u32, u32);
++static int devdrv_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++
++/* the device */
++static struct platform_device *devdrv_hc_platform_device;
++
++/* device driver interface */
++static struct device_driver devdrv_hc_device_driver = {
++ .name = (char *) hc_name,
++ .bus = &platform_bus_type,
++
++ .probe = devdrv_hcd_probe,
++ .remove = devdrv_hcd_remove,
++
++#ifdef CONFIG_PM
++ .suspend = devdrv_hcd_suspend,
++ .resume = devdrv_hcd_resume,
++#endif /* CONFIG_PM */
++};
++
++/* initialize the host controller and driver */
++static int __init_or_module devdrv_hcd_probe(struct device *dev)
++{
++ struct usb_hcd *hcd;
++ struct crisv10_hcd *crisv10_hcd;
++ int retval;
++
++ /* Check DMA burst length */
++ if(IO_EXTRACT(R_BUS_CONFIG, dma_burst, *R_BUS_CONFIG) !=
++ IO_STATE(R_BUS_CONFIG, dma_burst, burst32)) {
++ devdrv_err("Invalid DMA burst length in Etrax 100LX,"
++ " needs to be 32\n");
++ return -EPERM;
++ }
++
++ hcd = usb_create_hcd(&crisv10_hc_driver, dev, dev->bus_id);
++ if (!hcd)
++ return -ENOMEM;
++
++ crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ spin_lock_init(&crisv10_hcd->lock);
++ crisv10_hcd->num_ports = num_ports();
++ crisv10_hcd->running = 0;
++
++ dev_set_drvdata(dev, crisv10_hcd);
++
++ devdrv_dbg("ETRAX USB IRQs HC:%d RX:%d TX:%d\n", ETRAX_USB_HC_IRQ,
++ ETRAX_USB_RX_IRQ, ETRAX_USB_TX_IRQ);
++
++ /* Print out chip version read from registers */
++ int rev_maj = *R_USB_REVISION & IO_MASK(R_USB_REVISION, major);
++ int rev_min = *R_USB_REVISION & IO_MASK(R_USB_REVISION, minor);
++ if(rev_min == 0) {
++ devdrv_info("Etrax 100LX USB Revision %d v1,2\n", rev_maj);
++ } else {
++ devdrv_info("Etrax 100LX USB Revision %d v%d\n", rev_maj, rev_min);
++ }
++
++ devdrv_info("Bulk timer interval, start:%d eot:%d\n",
++ BULK_START_TIMER_INTERVAL,
++ BULK_EOT_TIMER_INTERVAL);
++
++
++ /* Init root hub data structures */
++ if(rh_init()) {
++ devdrv_err("Failed init data for Root Hub\n");
++ retval = -ENOMEM;
++ }
++
++ if(port_in_use(0)) {
++ if (cris_request_io_interface(if_usb_1, "ETRAX100LX USB-HCD")) {
++ printk(KERN_CRIT "usb-host: request IO interface usb1 failed");
++ retval = -EBUSY;
++ goto out;
++ }
++ devdrv_info("Claimed interface for USB physical port 1\n");
++ }
++ if(port_in_use(1)) {
++ if (cris_request_io_interface(if_usb_2, "ETRAX100LX USB-HCD")) {
++ /* Free first interface if second failed to be claimed */
++ if(port_in_use(0)) {
++ cris_free_io_interface(if_usb_1);
++ }
++ printk(KERN_CRIT "usb-host: request IO interface usb2 failed");
++ retval = -EBUSY;
++ goto out;
++ }
++ devdrv_info("Claimed interface for USB physical port 2\n");
++ }
++
++ /* Init transfer controller structs and locks */
++ if((retval = tc_init(hcd)) != 0) {
++ goto out;
++ }
++
++ /* Attach interrupt functions for DMA and init DMA controller */
++ if((retval = tc_dma_init(hcd)) != 0) {
++ goto out;
++ }
++
++ /* Attach the top IRQ handler for USB controller interrupts */
++ if (request_irq(ETRAX_USB_HC_IRQ, crisv10_hcd_top_irq, 0,
++ "ETRAX 100LX built-in USB (HC)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
++ retval = -EBUSY;
++ goto out;
++ }
++
++ /* iso_eof is only enabled 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);
++
++
++ crisv10_ready_wait();
++ /* 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.
++ 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);
++
++ crisv10_ready_wait();
++ /* 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);
++
++
++ /* Check so controller not busy before enabling ports */
++ crisv10_ready_wait();
++
++ /* Enable selected USB ports */
++ if(port_in_use(0)) {
++ *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++ } else {
++ *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++ }
++ if(port_in_use(1)) {
++ *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
++ } else {
++ *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
++ }
++
++ crisv10_ready_wait();
++ /* 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);
++
++ /* Do not continue probing initialization before USB interface is done */
++ crisv10_ready_wait();
++
++ /* Register our Host Controller to USB Core
++ * Finish the remaining parts of generic HCD initialization: allocate the
++ * buffers of consistent memory, register the bus
++ * and call the driver's reset() and start() routines. */
++ retval = usb_add_hcd(hcd, ETRAX_USB_HC_IRQ, IRQF_DISABLED);
++ if (retval != 0) {
++ devdrv_err("Failed registering HCD driver\n");
++ goto out;
++ }
++
++ return 0;
++
++ out:
++ devdrv_hcd_remove(dev);
++ return retval;
++}
++
++
++/* cleanup after the host controller and driver */
++static int __init_or_module devdrv_hcd_remove(struct device *dev)
++{
++ struct crisv10_hcd *crisv10_hcd = dev_get_drvdata(dev);
++ struct usb_hcd *hcd;
++
++ if (!crisv10_hcd)
++ return 0;
++ hcd = crisv10_hcd_to_hcd(crisv10_hcd);
++
++
++ /* Stop USB Controller in Etrax 100LX */
++ crisv10_hcd_reset(hcd);
++
++ usb_remove_hcd(hcd);
++ devdrv_dbg("Removed HCD from USB Core\n");
++
++ /* Free USB Controller IRQ */
++ free_irq(ETRAX_USB_HC_IRQ, NULL);
++
++ /* Free resources */
++ tc_dma_destroy();
++ tc_destroy();
++
++
++ if(port_in_use(0)) {
++ cris_free_io_interface(if_usb_1);
++ }
++ if(port_in_use(1)) {
++ cris_free_io_interface(if_usb_2);
++ }
++
++ devdrv_dbg("Freed all claimed resources\n");
++
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++static int devdrv_hcd_suspend(struct usb_hcd *hcd, u32 state, u32 level)
++{
++ return 0; /* no-op for now */
++}
++
++static int devdrv_hcd_resume(struct usb_hcd *hcd, u32 level)
++{
++ return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_PM */
++
++
++
++/*************************************************************/
++/*************************************************************/
++/* Module block */
++/*************************************************************/
++/*************************************************************/
++
++/* register driver */
++static int __init module_hcd_init(void)
++{
++
++ if (usb_disabled())
++ return -ENODEV;
++
++ /* Here we select enabled ports by following defines created from
++ menuconfig */
++#ifndef CONFIG_ETRAX_USB_HOST_PORT1
++ ports &= ~(1<<0);
++#endif
++#ifndef CONFIG_ETRAX_USB_HOST_PORT2
++ ports &= ~(1<<1);
++#endif
++
++ printk(KERN_INFO "%s version "VERSION" "COPYRIGHT"\n", product_desc);
++
++ devdrv_hc_platform_device =
++ platform_device_register_simple((char *) hc_name, 0, NULL, 0);
++
++ if (IS_ERR(devdrv_hc_platform_device))
++ return PTR_ERR(devdrv_hc_platform_device);
++ return driver_register(&devdrv_hc_device_driver);
++ /*
++ * Note that we do not set the DMA mask for the device,
++ * i.e. we pretend that we will use PIO, since no specific
++ * allocation routines are needed for DMA buffers. This will
++ * cause the HCD buffer allocation routines to fall back to
++ * kmalloc().
++ */
++}
++
++/* unregister driver */
++static void __exit module_hcd_exit(void)
++{
++ driver_unregister(&devdrv_hc_device_driver);
++}
++
++
++/* Module hooks */
++module_init(module_hcd_init);
++module_exit(module_hcd_exit);
+--- linux-2.6.19.2.orig/drivers/usb/host/hc_crisv10.h 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/usb/host/hc_crisv10.h 1970-01-01 01:00:00.000000000 +0100
+@@ -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
+--- linux-2.6.19.2.orig/drivers/usb/host/hc-crisv10.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/usb/host/hc-crisv10.h 2006-01-27 13:59:58.000000000 +0100
+@@ -0,0 +1,330 @@
++#ifndef __LINUX_ETRAX_USB_H
++#define __LINUX_ETRAX_USB_H
++
++#include <linux/types.h>
++#include <linux/list.h>
++
++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;
++};
++
++struct USB_SB_Desc {
++ volatile __u16 sw_len;
++ volatile __u16 command;
++ volatile unsigned long next;
++ volatile unsigned long buf;
++};
++
++struct USB_EP_Desc {
++ volatile __u16 hw_len;
++ volatile __u16 command;
++ volatile unsigned long sub;
++ volatile unsigned long next;
++};
++
++
++/* Root Hub port status struct */
++struct crisv10_rh {
++ volatile __u16 wPortChange[2];
++ volatile __u16 wPortStatusPrev[2];
++};
++
++/* HCD description */
++struct crisv10_hcd {
++ spinlock_t lock;
++ __u8 num_ports;
++ __u8 running;
++};
++
++
++/* Endpoint HC private data description */
++struct crisv10_ep_priv {
++ int epid;
++};
++
++/* Additional software state info for a USB Controller epid */
++struct etrax_epid {
++ __u8 inuse; /* !0 = setup in Etrax and used for a endpoint */
++ __u8 disabled; /* !0 = Temporarly disabled to avoid resubmission */
++ __u8 type; /* Setup as: PIPE_BULK, PIPE_CONTROL ... */
++ __u8 out_traffic; /* !0 = This epid is for out traffic */
++};
++
++/* Struct to hold information of scheduled later URB completion */
++struct urb_later_data {
++ struct work_struct ws;
++ struct usb_hcd *hcd;
++ struct urb *urb;
++ int urb_num;
++ int status;
++};
++
++
++typedef enum {
++ STARTED,
++ NOT_STARTED,
++ UNLINK,
++} crisv10_urb_state_t;
++
++
++struct crisv10_urb_priv {
++ /* Sequence number for this URB. Every new submited URB gets this from
++ a incrementing counter. Used when a URB is scheduled for later finish to
++ be sure that the intended URB hasn't already been completed (device
++ drivers has a tendency to reuse URBs once they are completed, causing us
++ to not be able to single old ones out only based on the URB pointer.) */
++ __u32 urb_num;
++
++ /* 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. */
++ struct USB_SB_Desc *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. */
++ struct USB_SB_Desc *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;
++
++ /* Flag that marks if this Isoc Out URB has finished it's transfer. Used
++ because several URBs can be finished before list is processed */
++ __u8 isoc_out_done;
++
++ /* This field is used to pass information about the urb's current state
++ between the various interrupt handlers (thus marked volatile). */
++ volatile crisv10_urb_state_t urb_state;
++
++ /* In Ctrl transfers consist of (at least) 3 packets: SETUP, IN and ZOUT.
++ When DMA8 sub-channel 2 has processed the SB list for this sequence we
++ get a interrupt. We also get a interrupt for In transfers and which
++ one of these interrupts that comes first depends of data size and device.
++ To be sure that we have got both interrupts before we complete the URB
++ we have these to flags that shows which part that has completed.
++ We can then check when we get one of the interrupts that if the other has
++ occured it's safe for us to complete the URB, otherwise we set appropriate
++ flag and do the completion when we get the other interrupt. */
++ volatile unsigned char ctrl_zout_done;
++ volatile unsigned char ctrl_rx_done;
++
++ /* 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;
++
++
++ /* The interval time rounded up to closest 2^N */
++ int interval;
++
++ /* Pool of EP descriptors needed if it's a INTR transfer.
++ Amount of EPs in pool correspons to how many INTR that should
++ be inserted in TxIntrEPList (max 128, defined by MAX_INTR_INTERVAL) */
++ struct USB_EP_Desc* intr_ep_pool[128];
++
++ /* The mount of EPs allocated for this INTR URB */
++ int intr_ep_pool_length;
++
++ /* Pointer to info struct if URB is scheduled to be finished later */
++ struct urb_later_data* later_data;
++};
++
++
++/* This struct is for passing data from the top half to the bottom half irq
++ handlers */
++struct crisv10_irq_reg {
++ struct usb_hcd* hcd;
++ __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;
++};
++
++
++/* This struct is for passing data from the isoc top half to the isoc bottom
++ half. */
++struct crisv10_isoc_complete_data {
++ struct usb_hcd *hcd;
++ struct urb *urb;
++ struct work_struct usb_bh;
++};
++
++/* Entry item for URB lists for each endpint */
++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 -urN linux-2.6.19.2.orig/drivers/net/cris/Makefile linux-2.6.19.2.dev/drivers/net/cris/Makefile
+--- linux-2.6.19.2.orig/drivers/net/cris/Makefile 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/net/cris/Makefile 2005-01-04 13:09:12.000000000 +0100
+@@ -1 +1,2 @@
+ obj-$(CONFIG_ETRAX_ARCH_V10) += eth_v10.o
++obj-$(CONFIG_ETRAX_ARCH_V32) += eth_v32.o
+diff -urN linux-2.6.19.2.orig/drivers/net/cris/eth_v10.c linux-2.6.19.2.dev/drivers/net/cris/eth_v10.c
+--- linux-2.6.19.2.orig/drivers/net/cris/eth_v10.c 2007-01-10 20:10:37.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/net/cris/eth_v10.c 2007-01-15 16:35:48.000000000 +0100
+@@ -1,221 +1,10 @@
+-/* $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.
++/*
++ * Driver for the ETRAX 100LX network controller.
+ *
+- * Copyright (c) 1998-2002 Axis Communications AB.
++ * Copyright (c) 1998-2006 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
+- *
+- *
+ */
+
+
+@@ -251,6 +40,7 @@
+ #include <asm/bitops.h>
+ #include <asm/ethernet.h>
+ #include <asm/cache.h>
++#include <asm/arch/io_interface_mux.h>
+
+ //#define ETHDEBUG
+ #define D(x)
+@@ -280,6 +70,9 @@
+ * by this lock as well.
+ */
+ spinlock_t lock;
++
++ spinlock_t led_lock; /* Protect LED state */
++ spinlock_t transceiver_lock; /* Protect transceiver state. */
+ };
+
+ typedef struct etrax_eth_descr
+@@ -296,8 +89,6 @@
+ void (*check_duplex)(struct net_device* dev);
+ };
+
+-struct transceiver_ops* transceiver;
+-
+ /* Duplex settings */
+ enum duplex
+ {
+@@ -308,7 +99,7 @@
+
+ /* Dma descriptors etc. */
+
+-#define MAX_MEDIA_DATA_SIZE 1518
++#define MAX_MEDIA_DATA_SIZE 1522
+
+ #define MIN_PACKET_LEN 46
+ #define ETHER_HEAD_LEN 14
+@@ -332,9 +123,9 @@
+ #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 )
++#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 */
+@@ -345,8 +136,8 @@
+ #define NO_NETWORK_ACTIVITY 0
+ #define NETWORK_ACTIVITY 1
+
+-#define NBR_OF_RX_DESC 64
+-#define NBR_OF_TX_DESC 256
++#define NBR_OF_RX_DESC 32
++#define NBR_OF_TX_DESC 16
+
+ /* Large packets are sent directly to upper layers while small packets are */
+ /* copied (to reduce memory waste). The following constant decides the breakpoint */
+@@ -368,7 +159,6 @@
+ 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)));
+
+@@ -378,7 +168,6 @@
+ 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;
+
+@@ -412,7 +201,7 @@
+ 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 e100_hardware_send_packet(struct net_local* np, 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);
+@@ -435,7 +224,10 @@
+ static void e100_set_network_leds(int active);
+
+ static const struct ethtool_ops e100_ethtool_ops;
+-
++#if defined(CONFIG_ETRAX_NO_PHY)
++static void dummy_check_speed(struct net_device* dev);
++static void dummy_check_duplex(struct net_device* dev);
++#else
+ 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);
+@@ -444,16 +236,29 @@
+ 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);
++#endif
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void e100_netpoll(struct net_device* dev);
++#endif
++
++static int autoneg_normal = 1;
+
+ struct transceiver_ops transceivers[] =
+ {
++#if defined(CONFIG_ETRAX_NO_PHY)
++ {0x0000, dummy_check_speed, dummy_check_duplex} /* Dummy */
++#else
+ {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*/
++ {0x04de, intel_check_speed, intel_check_duplex}, /* Intel LXT972A*/
+ {0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */
++#endif
+ };
+
++struct transceiver_ops* transceiver = &transceivers[0];
++static unsigned int mdio_phy_addr = 0; /* PHY address on MDIO bus */
++
+ #define tx_done(dev) (*R_DMA_CH0_CMD == 0)
+
+ /*
+@@ -468,18 +273,26 @@
+ etrax_ethernet_init(void)
+ {
+ struct net_device *dev;
+- struct net_local* np;
++ struct net_local* np;
+ int i, err;
+
+ printk(KERN_INFO
+- "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
+-
++ "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 1998-2006 Axis Communications AB\n");
++
++ if (cris_request_io_interface(if_eth, cardname)) {
++ printk(KERN_CRIT "etrax_ethernet_init failed to get IO interface\n");
++ return -EBUSY;
++ }
++
+ dev = alloc_etherdev(sizeof(struct net_local));
+- np = dev->priv;
+-
+ if (!dev)
+ return -ENOMEM;
++
++ np = netdev_priv(dev);
+
++ /* we do our own locking */
++ dev->features |= NETIF_F_LLTX;
++
+ dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
+
+ /* now setup our etrax specific stuff */
+@@ -495,18 +308,26 @@
+ dev->get_stats = e100_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->set_mac_address = e100_set_mac_address;
+- dev->ethtool_ops = &e100_ethtool_ops;
++ dev->ethtool_ops = &e100_ethtool_ops;
+ dev->do_ioctl = e100_ioctl;
+- dev->set_config = e100_set_config;
++ dev->set_config = e100_set_config;
+ dev->tx_timeout = e100_tx_timeout;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ dev->poll_controller = e100_netpoll;
++#endif
++
++ spin_lock_init(&np->lock);
++ spin_lock_init(&np->led_lock);
++ spin_lock_init(&np->transceiver_lock);
+
+ /* 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)
++ /* 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);
+ if (!RxDescList[i].skb)
+@@ -517,6 +338,7 @@
+ 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);
+ }
+
+@@ -542,7 +364,6 @@
+
+ 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];
+@@ -563,18 +384,19 @@
+ 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.data = (unsigned long)dev;
+ speed_timer.function = e100_check_speed;
+
+ clear_led_timer.function = e100_clear_network_leds;
++ clear_led_timer.data = (unsigned long)dev;
+
+ full_duplex = 0;
+ current_duplex = autoneg;
+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+- duplex_timer.data = (unsigned long)dev;
++ duplex_timer.data = (unsigned long)dev;
+ duplex_timer.function = e100_check_duplex;
+
+- /* Initialize mii interface */
++ /* 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;
+@@ -586,6 +408,9 @@
+ /* unwanted addresses are matched */
+ *R_NETWORK_GA_0 = 0x00000000;
+ *R_NETWORK_GA_1 = 0x00000000;
++
++ /* Initialize next time the led can flash */
++ led_next_time = jiffies;
+ return 0;
+ }
+
+@@ -596,7 +421,7 @@
+ static int
+ e100_set_mac_address(struct net_device *dev, void *p)
+ {
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
+ struct sockaddr *addr = p;
+ int i;
+
+@@ -680,17 +505,36 @@
+ /* allocate the irq corresponding to the transmitting DMA */
+
+ if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
+- cardname, (void *)dev)) {
++ 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)) {
++ cardname, (void *)dev)) {
+ goto grace_exit2;
+ }
+
++ /*
++ * Always allocate the DMA channels after the IRQ,
++ * and clean up on failure.
++ */
++
++ if (cris_request_dma(NETWORK_TX_DMA_NBR,
++ cardname,
++ DMA_VERBOSE_ON_ERROR,
++ dma_eth)) {
++ goto grace_exit3;
++ }
++
++ if (cris_request_dma(NETWORK_RX_DMA_NBR,
++ cardname,
++ DMA_VERBOSE_ON_ERROR,
++ dma_eth)) {
++ goto grace_exit4;
++ }
++
+ /* give the HW an idea of what MAC address we want */
+
+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+@@ -705,6 +549,7 @@
+
+ *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
+ #else
++ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, max_size, size1522);
+ 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);
+@@ -724,8 +569,7 @@
+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+
+- save_flags(flags);
+- cli();
++ local_irq_save(flags);
+
+ /* enable the irq's for ethernet DMA */
+
+@@ -757,12 +601,13 @@
+
+ *R_DMA_CH0_FIRST = 0;
+ *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
++ netif_start_queue(dev);
+
+- restore_flags(flags);
++ local_irq_restore(flags);
+
+ /* Probe for transceiver */
+ if (e100_probe_transceiver(dev))
+- goto grace_exit3;
++ goto grace_exit5;
+
+ /* Start duplex/speed timers */
+ add_timer(&speed_timer);
+@@ -771,10 +616,14 @@
+ /* We are now ready to accept transmit requeusts from
+ * the queueing layer of the networking.
+ */
+- netif_start_queue(dev);
++ netif_carrier_on(dev);
+
+ return 0;
+
++grace_exit5:
++ cris_free_dma(NETWORK_RX_DMA_NBR, cardname);
++grace_exit4:
++ cris_free_dma(NETWORK_TX_DMA_NBR, cardname);
+ grace_exit3:
+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+ grace_exit2:
+@@ -785,7 +634,13 @@
+ return -EAGAIN;
+ }
+
+-
++#if defined(CONFIG_ETRAX_NO_PHY)
++static void
++dummy_check_speed(struct net_device* dev)
++{
++ current_speed = 100;
++}
++#else
+ static void
+ generic_check_speed(struct net_device* dev)
+ {
+@@ -821,15 +676,18 @@
+ data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+ current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
+ }
+-
++#endif
+ static void
+ e100_check_speed(unsigned long priv)
+ {
+ struct net_device* dev = (struct net_device*)priv;
++ struct net_local *np = netdev_priv(dev);
+ static int led_initiated = 0;
+ unsigned long data;
+ int old_speed = current_speed;
+
++ spin_lock(&np->transceiver_lock);
++
+ data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR);
+ if (!(data & BMSR_LSTATUS)) {
+ current_speed = 0;
+@@ -837,14 +695,22 @@
+ transceiver->check_speed(dev);
+ }
+
++ spin_lock(&np->led_lock);
+ if ((old_speed != current_speed) || !led_initiated) {
+ led_initiated = 1;
+ e100_set_network_leds(NO_NETWORK_ACTIVITY);
++ if (current_speed)
++ netif_carrier_on(dev);
++ else
++ netif_carrier_off(dev);
+ }
++ spin_unlock(&np->led_lock);
+
+ /* Reinitialize the timer. */
+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+ add_timer(&speed_timer);
++
++ spin_unlock(&np->transceiver_lock);
+ }
+
+ static void
+@@ -857,7 +723,7 @@
+ ADVERTISE_10HALF | ADVERTISE_10FULL);
+
+ switch (current_speed_selection) {
+- case 10 :
++ case 10:
+ if (current_duplex == full)
+ data |= ADVERTISE_10FULL;
+ else if (current_duplex == half)
+@@ -866,7 +732,7 @@
+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+ break;
+
+- case 100 :
++ case 100:
+ if (current_duplex == full)
+ data |= ADVERTISE_100FULL;
+ else if (current_duplex == half)
+@@ -875,45 +741,54 @@
+ data |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+ break;
+
+- case 0 : /* Auto */
++ 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;
++ ADVERTISE_100HALF | ADVERTISE_100FULL;
+ break;
+
+- default : /* assume autoneg speed and duplex */
++ default: /* assume autoneg speed and duplex */
+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
+- ADVERTISE_100HALF | ADVERTISE_100FULL;
++ ADVERTISE_100HALF | ADVERTISE_100FULL;
++ break;
+ }
+
+ 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;
+-
++ if (autoneg_normal) {
++ 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)
+ {
++ struct net_local *np = netdev_priv(dev);
++
++ spin_lock(&np->transceiver_lock);
+ if (speed != current_speed_selection) {
+ current_speed_selection = speed;
+ e100_negotiate(dev);
+ }
++ spin_unlock(&np->transceiver_lock);
+ }
+
+ 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;
++ struct net_local *np = netdev_priv(dev);
++ int old_duplex;
++
++ spin_lock(&np->transceiver_lock);
++ old_duplex = full_duplex;
+ transceiver->check_duplex(dev);
+ if (old_duplex != full_duplex) {
+ /* Duplex changed */
+@@ -925,12 +800,20 @@
+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+ add_timer(&duplex_timer);
+ np->mii_if.full_duplex = full_duplex;
++ spin_unlock(&np->transceiver_lock);
+ }
+-
++#if defined(CONFIG_ETRAX_NO_PHY)
++static void
++dummy_check_duplex(struct net_device* dev)
++{
++ full_duplex = 1;
++}
++#else
+ 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))
+@@ -943,6 +826,7 @@
+ 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;
+ }
+@@ -951,6 +835,7 @@
+ 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;
+ }
+@@ -959,26 +844,35 @@
+ 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;
+ }
+-
++#endif
+ static void
+ e100_set_duplex(struct net_device* dev, enum duplex new_duplex)
+ {
++ struct net_local *np = netdev_priv(dev);
++
++ spin_lock(&np->transceiver_lock);
+ if (new_duplex != current_duplex) {
+ current_duplex = new_duplex;
+ e100_negotiate(dev);
+ }
++ spin_unlock(&np->transceiver_lock);
+ }
+
+ static int
+ e100_probe_transceiver(struct net_device* dev)
+ {
++#if !defined(CONFIG_ETRAX_NO_PHY)
+ unsigned int phyid_high;
+ unsigned int phyid_low;
+ unsigned int oui;
+ struct transceiver_ops* ops = NULL;
++ struct net_local *np = netdev_priv(dev);
++
++ spin_lock(&np->transceiver_lock);
+
+ /* Probe MDIO physical address */
+ for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
+@@ -986,7 +880,7 @@
+ break;
+ }
+ if (mdio_phy_addr == 32)
+- return -ENODEV;
++ return -ENODEV;
+
+ /* Get manufacturer */
+ phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);
+@@ -999,6 +893,8 @@
+ }
+ transceiver = ops;
+
++ spin_unlock(&np->transceiver_lock);
++#endif
+ return 0;
+ }
+
+@@ -1006,7 +902,7 @@
+ 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 data; /* Data read from MDIO */
+ int bitCounter;
+
+ /* Start of frame, OP Code, Physical Address, Register Address */
+@@ -1082,6 +978,7 @@
+ e100_receive_mdio_bit()
+ {
+ unsigned char bit;
++
+ *R_NETWORK_MGM_CTRL = 0;
+ bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT);
+ udelay(1);
+@@ -1117,7 +1014,7 @@
+ static void
+ e100_tx_timeout(struct net_device *dev)
+ {
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&np->lock, flags);
+@@ -1139,8 +1036,7 @@
+ e100_reset_transceiver(dev);
+
+ /* and get rid of the packets that never got an interrupt */
+- while (myFirstTxDesc != myNextTxDesc)
+- {
++ while (myFirstTxDesc != myNextTxDesc) {
+ dev_kfree_skb(myFirstTxDesc->skb);
+ myFirstTxDesc->skb = 0;
+ myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+@@ -1166,7 +1062,7 @@
+ static int
+ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
+ {
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
+ unsigned char *buf = skb->data;
+ unsigned long flags;
+
+@@ -1179,7 +1075,7 @@
+
+ dev->trans_start = jiffies;
+
+- e100_hardware_send_packet(buf, skb->len);
++ e100_hardware_send_packet(np, buf, skb->len);
+
+ myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
+
+@@ -1202,13 +1098,15 @@
+ e100rxtx_interrupt(int irq, void *dev_id)
+ {
+ 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;
++ struct net_local *np = netdev_priv(dev);
++ unsigned long irqbits;
+
+- /* 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);
++ /*
++ * Note that both rx and tx interrupts are blocked at this point,
++ * regardless of which got us here.
++ */
++
++ irqbits = *R_IRQ_MASK2_RD;
+
+ /* Handle received packets */
+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
+@@ -1224,7 +1122,7 @@
+ * allocate a new buffer to put a packet in.
+ */
+ e100_rx(dev);
+- ((struct net_local *)dev->priv)->stats.rx_packets++;
++ np->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 */
+@@ -1239,8 +1137,7 @@
+
+ /* Report any packets that have been sent */
+ while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+- myFirstTxDesc != myNextTxDesc)
+- {
++ (netif_queue_stopped(dev) || myFirstTxDesc != myNextTxDesc)) {
+ np->stats.tx_bytes += myFirstTxDesc->skb->len;
+ np->stats.tx_packets++;
+
+@@ -1249,19 +1146,15 @@
+ dev_kfree_skb_irq(myFirstTxDesc->skb);
+ myFirstTxDesc->skb = 0;
+ myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
++ /* Wake up queue. */
++ netif_wake_queue(dev);
+ }
+
+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
+- /* acknowledge the eop interrupt and wake up queue */
++ /* acknowledge the eop interrupt. */
+ *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;
+ }
+
+@@ -1269,7 +1162,7 @@
+ e100nw_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
+ unsigned long irqbits = *R_IRQ_MASK0_RD;
+
+ /* check for underrun irq */
+@@ -1291,7 +1184,6 @@
+ 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"));
+ }
+@@ -1304,12 +1196,13 @@
+ {
+ struct sk_buff *skb;
+ int length = 0;
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
+ unsigned char *skb_data_ptr;
+ #ifdef ETHDEBUG
+ int i;
+ #endif
+-
++ etrax_eth_descr *prevRxDesc; /* The descriptor right before myNextRxDesc */
++ spin_lock(&np->led_lock);
+ if (!led_active && time_after(jiffies, led_next_time)) {
+ /* light the network leds depending on the current speed. */
+ e100_set_network_leds(NETWORK_ACTIVITY);
+@@ -1319,9 +1212,10 @@
+ led_active = 1;
+ mod_timer(&clear_led_timer, jiffies + HZ/10);
+ }
++ spin_unlock(&np->led_lock);
+
+ length = myNextRxDesc->descr.hw_len - 4;
+- ((struct net_local *)dev->priv)->stats.rx_bytes += length;
++ np->stats.rx_bytes += length;
+
+ #ifdef ETHDEBUG
+ printk("Got a packet of length %d:\n", length);
+@@ -1341,7 +1235,7 @@
+ if (!skb) {
+ np->stats.rx_errors++;
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+- return;
++ goto update_nextrxdesc;
+ }
+
+ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */
+@@ -1358,15 +1252,15 @@
+ 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.
++ * 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;
++ goto update_nextrxdesc;
+ }
+ skb = myNextRxDesc->skb;
+ align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;
+@@ -1382,9 +1276,10 @@
+ /* Send the packet to the upper layers */
+ netif_rx(skb);
+
++ update_nextrxdesc:
+ /* Prepare for next packet */
+ myNextRxDesc->descr.status = 0;
+- myPrevRxDesc = myNextRxDesc;
++ prevRxDesc = myNextRxDesc;
+ myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
+
+ rx_queue_len++;
+@@ -1392,9 +1287,9 @@
+ /* Check if descriptors should be returned */
+ if (rx_queue_len == RX_QUEUE_THRESHOLD) {
+ flush_etrax_cache();
+- myPrevRxDesc->descr.ctrl |= d_eol;
++ prevRxDesc->descr.ctrl |= d_eol;
+ myLastRxDesc->descr.ctrl &= ~d_eol;
+- myLastRxDesc = myPrevRxDesc;
++ myLastRxDesc = prevRxDesc;
+ rx_queue_len = 0;
+ }
+ }
+@@ -1403,7 +1298,7 @@
+ static int
+ e100_close(struct net_device *dev)
+ {
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
+
+ printk(KERN_INFO "Closing %s.\n", dev->name);
+
+@@ -1431,6 +1326,9 @@
+ free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+
++ cris_free_dma(NETWORK_TX_DMA_NBR, cardname);
++ cris_free_dma(NETWORK_RX_DMA_NBR, cardname);
++
+ /* Update the statistics here. */
+
+ update_rx_stats(&np->stats);
+@@ -1448,46 +1346,56 @@
+ {
+ struct mii_ioctl_data *data = if_mii(ifr);
+ struct net_local *np = netdev_priv(dev);
++ int ret = 0;
++ int old_autoneg;
+
+ spin_lock(&np->lock); /* Preempt protection */
+ switch (cmd) {
+- case SIOCGMIIPHY: /* Get PHY address */
++ case SIOCGMIIPHY: /* Get PHY address */
+ data->phy_id = mdio_phy_addr;
+ break;
+- case SIOCGMIIREG: /* Read MII register */
++ 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 */
++ 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 */
++ case SET_ETH_SPEED_10: /* 10 Mbps */
+ e100_set_speed(dev, 10);
+ break;
+- case SET_ETH_SPEED_100: /* 100 Mbps */
++ case SET_ETH_SPEED_100: /* 100 Mbps */
+ e100_set_speed(dev, 100);
+ break;
+- case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */
++ case SET_ETH_SPEED_AUTO: /* Auto-negotiate speed */
+ e100_set_speed(dev, 0);
+ break;
+- case SET_ETH_DUPLEX_HALF: /* Half duplex. */
++ case SET_ETH_DUPLEX_HALF: /* Half duplex */
+ e100_set_duplex(dev, half);
+ break;
+- case SET_ETH_DUPLEX_FULL: /* Full duplex. */
++ case SET_ETH_DUPLEX_FULL: /* Full duplex */
+ e100_set_duplex(dev, full);
+ break;
+- case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/
++ case SET_ETH_DUPLEX_AUTO: /* Auto-negotiate duplex */
+ e100_set_duplex(dev, autoneg);
+ break;
++ case SET_ETH_AUTONEG:
++ old_autoneg = autoneg_normal;
++ autoneg_normal = *(int*)data;
++ if (autoneg_normal != old_autoneg)
++ e100_negotiate(dev);
++ break;
+ default:
++ spin_unlock(&np->lock);
+ return -EINVAL;
+ }
+ spin_unlock(&np->lock);
+- return 0;
++ return ret;
+ }
+
+-static int e100_set_settings(struct net_device *dev,
++static int e100_get_settings(struct net_device *dev,
+ struct ethtool_cmd *ecmd)
+ {
+ ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+@@ -1565,7 +1473,8 @@
+ static int
+ e100_set_config(struct net_device *dev, struct ifmap *map)
+ {
+- struct net_local *np = (struct net_local *)dev->priv;
++ struct net_local *np = netdev_priv(dev);
++
+ spin_lock(&np->lock); /* Preempt protection */
+
+ switch(map->port) {
+@@ -1574,21 +1483,25 @@
+ 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);
+@@ -1602,6 +1515,7 @@
+ 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);
+@@ -1613,11 +1527,11 @@
+ 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);
+ }
+
+ /*
+@@ -1627,8 +1541,9 @@
+ static struct net_device_stats *
+ e100_get_stats(struct net_device *dev)
+ {
+- struct net_local *lp = (struct net_local *)dev->priv;
++ struct net_local *lp = netdev_priv(dev);
+ unsigned long flags;
++
+ spin_lock_irqsave(&lp->lock, flags);
+
+ update_rx_stats(&lp->stats);
+@@ -1640,21 +1555,21 @@
+
+ /*
+ * 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.
++ * 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;
++ struct net_local *lp = netdev_priv(dev);
+ 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)
+- {
++ if (dev->flags & IFF_PROMISC) {
+ /* promiscuous mode */
+ lo_bits = 0xfffffffful;
+ hi_bits = 0xfffffffful;
+@@ -1684,9 +1599,10 @@
+ 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++) {
++ for (i = 0; i < num_addr; i++) {
+ /* Calculate the hash index for the GA registers */
+
+ hash_ix = 0;
+@@ -1713,8 +1629,7 @@
+
+ if (hash_ix >= 32) {
+ hi_bits |= (1 << (hash_ix-32));
+- }
+- else {
++ } else {
+ lo_bits |= (1 << hash_ix);
+ }
+ dmi = dmi->next;
+@@ -1729,10 +1644,11 @@
+ }
+
+ void
+-e100_hardware_send_packet(char *buf, int length)
++e100_hardware_send_packet(struct net_local *np, char *buf, int length)
+ {
+ D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
+
++ spin_lock(&np->led_lock);
+ if (!led_active && time_after(jiffies, led_next_time)) {
+ /* light the network leds depending on the current speed. */
+ e100_set_network_leds(NETWORK_ACTIVITY);
+@@ -1742,15 +1658,16 @@
+ led_active = 1;
+ mod_timer(&clear_led_timer, jiffies + HZ/10);
+ }
++ spin_unlock(&np->led_lock);
+
+ /* 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;
++ /* 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);
+@@ -1759,6 +1676,11 @@
+ static void
+ e100_clear_network_leds(unsigned long dummy)
+ {
++ struct net_device *dev = (struct net_device *)dummy;
++ struct net_local *np = netdev_priv(dev);
++
++ spin_lock(&np->led_lock);
++
+ if (led_active && time_after(jiffies, led_next_time)) {
+ e100_set_network_leds(NO_NETWORK_ACTIVITY);
+
+@@ -1766,6 +1688,8 @@
+ led_next_time = jiffies + NET_FLASH_PAUSE;
+ led_active = 0;
+ }
++
++ spin_unlock(&np->led_lock);
+ }
+
+ static void
+@@ -1786,19 +1710,25 @@
+ #else
+ LED_NETWORK_SET(LED_OFF);
+ #endif
+- }
+- else if (light_leds) {
++ } else if (light_leds) {
+ if (current_speed == 10) {
+ LED_NETWORK_SET(LED_ORANGE);
+ } else {
+ LED_NETWORK_SET(LED_GREEN);
+ }
+- }
+- else {
++ } else {
+ LED_NETWORK_SET(LED_OFF);
+ }
+ }
+
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void
++e100_netpoll(struct net_device* netdev)
++{
++ e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
++}
++#endif
++
+ static int
+ etrax_init_module(void)
+ {
+diff -urN linux-2.6.19.2.orig/drivers/net/cris/eth_v32.c linux-2.6.19.2.dev/drivers/net/cris/eth_v32.c
+--- linux-2.6.19.2.orig/drivers/net/cris/eth_v32.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/net/cris/eth_v32.c 2007-02-06 11:10:37.000000000 +0100
+@@ -0,0 +1,2305 @@
++/*
++ * Driver for the ETRAX FS network controller.
++ *
++ * Copyright (c) 2003-2006 Axis Communications AB.
++ */
++
++#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/cpufreq.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++
++#include <asm/io.h> /* LED_* I/O functions */
++#include <asm/irq.h>
++#include <asm/arch/hwregs/reg_map.h>
++#include <asm/arch/hwregs/reg_rdwr.h>
++#include <asm/arch/hwregs/dma.h>
++#include <asm/arch/hwregs/eth_defs.h>
++#include <asm/arch/hwregs/config_defs.h>
++#include <asm/arch/hwregs/intr_vect_defs.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/ethernet.h>
++#include <asm/arch/dma.h>
++#include <asm/arch/intmem.h>
++#include <asm/arch/pinmux.h>
++
++#include "eth_v32.h"
++
++#define DEBUG(x)
++#define GET_BIT(bit,val) (((val) >> (bit)) & 0x01)
++
++/* Toggle network LEDs on/off at runtime */
++static int use_network_leds = 1;
++
++static void update_rx_stats(struct crisv32_ethernet_local *np);
++static void update_tx_stats(struct crisv32_ethernet_local *np);
++static void crisv32_eth_setup_controller(struct net_device *dev);
++static int crisv32_eth_request_irqdma(struct net_device *dev);
++static void crisv32_eth_init_rings(struct net_device *dev);
++static void crisv32_eth_reset_rings(struct net_device *dev);
++static void crisv32_ethernet_bug(struct net_device *dev);
++
++/*
++ * 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 FS built-in ethernet controller";
++
++static int autoneg_normal = 1;
++
++/* Some chipset needs special care. */
++struct transceiver_ops transceivers[] = {
++ {0x1018, broadcom_check_speed, broadcom_check_duplex},
++ /* TDK 2120 and TDK 2120C */
++ {0xC039, tdk_check_speed, tdk_check_duplex},
++ {0x039C, tdk_check_speed, tdk_check_duplex},
++ /* Intel LXT972A*/
++ {0x04de, intel_check_speed, intel_check_duplex},
++ /* National Semiconductor DP83865 */
++ {0x0017, national_check_speed, national_check_duplex},
++ /* Generic, must be last. */
++ {0x0000, generic_check_speed, generic_check_duplex}
++};
++
++static struct net_device *crisv32_dev[2];
++static struct crisv32_eth_leds *crisv32_leds[3];
++
++#ifdef CONFIG_CPU_FREQ
++static int
++crisv32_ethernet_freq_notifier(struct notifier_block *nb, unsigned long val,
++ void *data);
++
++static struct notifier_block crisv32_ethernet_freq_notifier_block = {
++ .notifier_call = crisv32_ethernet_freq_notifier
++};
++#endif
++
++/*
++ * mask in and out tx/rx interrupts.
++ */
++static inline void crisv32_disable_tx_ints(struct crisv32_ethernet_local *np)
++{
++ reg_dma_rw_intr_mask intr_mask_tx = { .data = regk_dma_no };
++ REG_WR(dma, np->dma_out_inst, rw_intr_mask, intr_mask_tx);
++}
++
++static inline void crisv32_enable_tx_ints(struct crisv32_ethernet_local *np)
++{
++ reg_dma_rw_intr_mask intr_mask_tx = { .data = regk_dma_yes };
++ REG_WR(dma, np->dma_out_inst, rw_intr_mask, intr_mask_tx);
++}
++
++static inline void crisv32_disable_rx_ints(struct crisv32_ethernet_local *np)
++{
++ reg_dma_rw_intr_mask intr_mask_rx = { .in_eop = regk_dma_no };
++ REG_WR(dma, np->dma_in_inst, rw_intr_mask, intr_mask_rx);
++}
++
++static inline void crisv32_enable_rx_ints(struct crisv32_ethernet_local *np)
++{
++ reg_dma_rw_intr_mask intr_mask_rx = { .in_eop = regk_dma_yes };
++ REG_WR(dma, np->dma_in_inst, rw_intr_mask, intr_mask_rx);
++}
++
++/* start/stop receiver */
++static inline void crisv32_start_receiver(struct crisv32_ethernet_local *np)
++{
++ reg_eth_rw_rec_ctrl rec_ctrl;
++
++ rec_ctrl = REG_RD(eth, np->eth_inst, rw_rec_ctrl);
++ rec_ctrl.ma0 = regk_eth_yes;
++ rec_ctrl.broadcast = regk_eth_rec;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++}
++
++static inline void crisv32_stop_receiver(struct crisv32_ethernet_local *np)
++{
++ reg_eth_rw_rec_ctrl rec_ctrl;
++
++ rec_ctrl = REG_RD(eth, np->eth_inst, rw_rec_ctrl);
++ rec_ctrl.ma0 = regk_eth_no;
++ rec_ctrl.broadcast = regk_eth_discard;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++}
++
++static int __init
++crisv32_eth_request_irqdma(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ /* Allocate IRQs and DMAs. */
++ if (np->eth_inst == regi_eth0) {
++ if (request_irq(DMA0_INTR_VECT, crisv32tx_eth_interrupt,
++ 0, cardname, dev)) {
++ return -EAGAIN;
++ }
++
++ if (request_irq(DMA1_INTR_VECT, crisv32rx_eth_interrupt,
++ IRQF_SAMPLE_RANDOM, cardname, dev)) {
++ goto err0_1;
++ }
++
++ if (crisv32_request_dma(0, cardname, DMA_VERBOSE_ON_ERROR,
++ 12500000, dma_eth0))
++ goto err0_2;
++
++ if (crisv32_request_dma(1, cardname, DMA_VERBOSE_ON_ERROR,
++ 12500000, dma_eth0))
++ goto err0_3;
++
++ if (request_irq(ETH0_INTR_VECT, crisv32nw_eth_interrupt, 0,
++ cardname, dev)) {
++ crisv32_free_dma(1);
++ err0_3:
++ crisv32_free_dma(0);
++ err0_2:
++ free_irq(DMA1_INTR_VECT, dev);
++ err0_1:
++ free_irq(DMA0_INTR_VECT, dev);
++ return -EAGAIN;
++ }
++ } else {
++ if (request_irq(DMA6_INTR_VECT, crisv32tx_eth_interrupt,
++ 0, cardname, dev))
++ return -EAGAIN;
++
++ if (request_irq(DMA7_INTR_VECT, crisv32rx_eth_interrupt,
++ IRQF_SAMPLE_RANDOM, cardname, dev))
++ goto err1_1;
++
++ if (crisv32_request_dma(6, cardname, DMA_VERBOSE_ON_ERROR,
++ 0, dma_eth1))
++ goto err1_2;
++
++ if (crisv32_request_dma(7, cardname, DMA_VERBOSE_ON_ERROR,
++ 0, dma_eth1))
++ goto err1_3;
++
++ if (request_irq(ETH1_INTR_VECT, crisv32nw_eth_interrupt, 0,
++ cardname, dev)) {
++ crisv32_free_dma(7);
++ err1_3:
++ crisv32_free_dma(6);
++ err1_2:
++ free_irq(DMA7_INTR_VECT, dev);
++ err1_1:
++ free_irq(DMA6_INTR_VECT, dev);
++ return -EAGAIN;
++ }
++ }
++ return 0;
++}
++
++static void __init
++crisv32_eth_setup_controller(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ reg_config_rw_pad_ctrl pad_ctrl;
++
++ reg_eth_rw_tr_ctrl tr_ctrl = {
++ .retry = regk_eth_yes,
++ .pad = regk_eth_yes,
++ .crc = regk_eth_yes
++ };
++
++ reg_eth_rw_rec_ctrl rec_ctrl = {
++ .ma0 = regk_eth_no, /* enable at open() */
++ .broadcast = regk_eth_no,
++ .max_size = regk_eth_size1522
++ };
++
++ reg_eth_rw_ga_lo ga_lo = { 0 };
++ reg_eth_rw_ga_hi ga_hi = { 0 };
++
++ reg_eth_rw_gen_ctrl gen_ctrl = {
++ .phy = regk_eth_mii_clk,
++ .flow_ctrl = regk_eth_yes
++ };
++
++ /*
++ * Initialize group address registers to make sure that no
++ * unwanted addresses are matched.
++ */
++ REG_WR(eth, np->eth_inst, rw_ga_lo, ga_lo);
++ REG_WR(eth, np->eth_inst, rw_ga_hi, ga_hi);
++
++ /* Configure receiver and transmitter */
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++ REG_WR(eth, np->eth_inst, rw_tr_ctrl, tr_ctrl);
++
++ /* Enable ethernet controller with mii clk. */
++ REG_WR(eth, np->eth_inst, rw_gen_ctrl, gen_ctrl);
++ gen_ctrl.en = regk_eth_yes;
++ REG_WR(eth, np->eth_inst, rw_gen_ctrl, gen_ctrl);
++
++ /* keep reset low (RESET_LEN) */
++ udelay(500);
++
++ /* done */
++ pad_ctrl = REG_RD(config, regi_config, rw_pad_ctrl);
++ pad_ctrl.phyrst_n = 1;
++ REG_WR(config, regi_config, rw_pad_ctrl, pad_ctrl);
++
++ /* Let the PHY reset (RESET_WAIT) */
++ udelay(200);
++
++ crisv32_eth_probe_transceiver(dev);
++}
++
++static void __init
++crisv32_eth_init_rings(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ int i;
++
++ /* Initialise receive descriptors for interface. */
++ for (i = 0; i < NBR_RX_DESC; i++) {
++ struct sk_buff *skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
++
++ np->dma_rx_descr_list[i].skb = skb;
++ np->dma_rx_descr_list[i].descr.buf =
++ (char*)virt_to_phys(skb->data);
++ np->dma_rx_descr_list[i].descr.after =
++ (char*)virt_to_phys(skb->data + MAX_MEDIA_DATA_SIZE);
++
++ np->dma_rx_descr_list[i].descr.eol = 0;
++ np->dma_rx_descr_list[i].descr.in_eop = 0;
++ np->dma_rx_descr_list[i].descr.next =
++ (void *) virt_to_phys(&np->dma_rx_descr_list[i + 1].descr);
++ }
++ /* bend the list into a ring */
++ np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.next =
++ (void *) virt_to_phys(&np->dma_rx_descr_list[0].descr);
++
++ /* Initialize transmit descriptors. */
++ for (i = 0; i < NBR_TX_DESC; i++) {
++ np->dma_tx_descr_list[i].descr.wait = 1;
++ np->dma_tx_descr_list[i].descr.eol = 0;
++ np->dma_tx_descr_list[i].descr.out_eop = 0;
++ np->dma_tx_descr_list[i].descr.next =
++ (void*)virt_to_phys(&np->dma_tx_descr_list[i+1].descr);
++ }
++ /* bend the list into a ring */
++ np->dma_tx_descr_list[NBR_TX_DESC - 1].descr.next =
++ (void *) virt_to_phys(&np->dma_tx_descr_list[0].descr);
++
++ crisv32_eth_reset_rings(dev);
++}
++
++static void
++crisv32_eth_reset_rings(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ int i;
++
++ /* free un-handled tx packets */
++ while(np->txpackets
++ || np->catch_tx_desc != np->active_tx_desc) {
++ np->txpackets--;
++ if (np->catch_tx_desc->skb)
++ dev_kfree_skb(np->catch_tx_desc->skb);
++
++ np->catch_tx_desc->skb = 0;
++ np->catch_tx_desc =
++ phys_to_virt((int)np->catch_tx_desc->descr.next);
++ } while (np->catch_tx_desc != np->active_tx_desc);
++ WARN_ON(np->txpackets != 0);
++ np->txpackets = 0;
++
++ /* cleanup the rx-ring */
++ for (i = 0; i < NBR_RX_DESC; i++) {
++ struct sk_buff *skb;
++ skb = np->dma_rx_descr_list[i].skb;
++ if (!skb
++ || (np->dma_rx_descr_list[i].descr.buf !=
++ (void *)virt_to_phys(skb->data)))
++ {
++ printk("%s:%d: damaged rx-ring! "
++ "i=%d skb=%p %lx %lx %p %p\n",
++ __func__, __LINE__, i,
++ skb,
++ virt_to_phys(skb->data),
++ virt_to_phys(skb->data + MAX_MEDIA_DATA_SIZE),
++ np->dma_rx_descr_list[i].descr.buf,
++ np->dma_rx_descr_list[i].descr.after);
++ WARN_ON(1);
++ crisv32_ethernet_bug(dev);
++ if (skb)
++ dev_kfree_skb(skb);
++ skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
++ np->dma_rx_descr_list[i].skb = skb;
++ np->dma_rx_descr_list[i].descr.buf =
++ (char*)virt_to_phys(skb->data);
++ }
++ np->dma_rx_descr_list[i].descr.after =
++ (char*)virt_to_phys(skb->data
++ + MAX_MEDIA_DATA_SIZE);
++ np->dma_rx_descr_list[i].descr.eol = 0;
++ np->dma_rx_descr_list[i].descr.in_eop = 0;
++ /* Workaround cache bug */
++ flush_dma_descr(&np->dma_rx_descr_list[i].descr, 1);
++ }
++
++ /* reset rx-ring */
++ np->active_rx_desc = &np->dma_rx_descr_list[0];
++ np->prev_rx_desc = &np->dma_rx_descr_list[NBR_RX_DESC - 1];
++ np->last_rx_desc = np->prev_rx_desc;
++ np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.eol = 1;
++
++ /* reset tx-ring */
++ np->dma_tx_descr_list[0].descr.buf =
++ np->dma_tx_descr_list[0].descr.after = 0;
++ np->dma_rx_descr_list[i].descr.in_eop = 0;
++ np->dma_tx_descr_list[0].descr.eol = 1;
++
++ np->active_tx_desc = &np->dma_tx_descr_list[0];
++ np->prev_tx_desc = &np->dma_tx_descr_list[NBR_TX_DESC - 1];
++ np->catch_tx_desc = &np->dma_tx_descr_list[0];
++
++ /* Fill context descriptors. */
++ np->ctxt_in.next = 0;
++ np->ctxt_in.saved_data =
++ (void *)virt_to_phys(&np->active_rx_desc->descr);
++ np->ctxt_in.saved_data_buf = np->active_rx_desc->descr.buf;
++
++ np->ctxt_out.next = 0;
++ np->ctxt_out.saved_data =
++ (void *)virt_to_phys(&np->dma_tx_descr_list[0].descr);
++}
++
++static void __init
++crisv32_init_leds(int ledgrp, struct net_device* dev)
++{
++ struct timer_list timer_init = TIMER_INITIALIZER(NULL, 0, 0);
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ /* Use already allocated led grp if initialized */
++ if (crisv32_leds[ledgrp] != NULL) {
++ np->leds = crisv32_leds[ledgrp];
++ return;
++ }
++
++ crisv32_leds[ledgrp] = kmalloc(sizeof(struct crisv32_eth_leds),GFP_KERNEL);
++
++ crisv32_leds[ledgrp]->ledgrp = ledgrp;
++ crisv32_leds[ledgrp]->led_active = 0;
++ /* NOTE: Should this value be set to zero as the jiffies timer can wrap? */
++ crisv32_leds[ledgrp]->led_next_time = jiffies;
++
++ crisv32_leds[ledgrp]->clear_led_timer = timer_init;
++ crisv32_leds[ledgrp]->clear_led_timer.function = crisv32_clear_network_leds;
++ crisv32_leds[ledgrp]->clear_led_timer.data = (unsigned long) dev;
++
++ spin_lock_init(&crisv32_leds[ledgrp]->led_lock);
++
++ np->leds = crisv32_leds[ledgrp];
++}
++
++static int __init
++crisv32_ethernet_init(void)
++{
++ struct crisv32_ethernet_local *np;
++ int ret = 0;
++
++ printk("ETRAX FS 10/100MBit ethernet v0.01 (c)"
++ " 2003 Axis Communications AB\n");
++
++#ifdef CONFIG_ETRAX_ETHERNET_IFACE0
++{
++ int iface0 = 0;
++ /* Default MAC address for interface 0.
++ * The real one will be set later. */
++ static struct sockaddr default_mac_iface0 =
++ {0, {0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00}};
++
++ if (!(crisv32_dev[iface0] = alloc_etherdev(sizeof *np)))
++ return -ENOMEM;
++
++ ret |= crisv32_ethernet_device_init(crisv32_dev[iface0]);
++
++#if defined(CONFIG_ETRAX_ETH0_USE_LEDGRP0)
++ crisv32_init_leds(LED_GRP_0,crisv32_dev[iface0]);
++#elif defined(CONFIG_ETRAX_ETH0_USE_LEDGRP1)
++ crisv32_init_leds(LED_GRP_1,crisv32_dev[iface0]);
++#else
++ crisv32_init_leds(LED_GRP_NONE,crisv32_dev[iface0]);
++#endif
++
++ np = (struct crisv32_ethernet_local *) crisv32_dev[iface0]->priv;
++ np->eth_inst = regi_eth0;
++ np->dma_out_inst = regi_dma0;
++ np->dma_in_inst = regi_dma1;
++
++ register_netdev(crisv32_dev[iface0]);
++
++ /* Set up default MAC address */
++ memcpy(crisv32_dev[iface0]->dev_addr, default_mac_iface0.sa_data, 6);
++ crisv32_eth_set_mac_address(crisv32_dev[iface0], &default_mac_iface0);
++ if (crisv32_eth_request_irqdma(crisv32_dev[iface0]))
++ printk("%s: eth0 unable to allocate IRQ and DMA resources\n",
++ __func__);
++ np->txpackets = 0;
++ crisv32_eth_init_rings(crisv32_dev[iface0]);
++ crisv32_eth_setup_controller(crisv32_dev[iface0]);
++}
++#endif /* CONFIG_ETRAX_ETHERNET_IFACE0 */
++
++#ifdef CONFIG_ETRAX_ETHERNET_IFACE1
++{
++ int iface1 = 0;
++ /* Default MAC address for interface 1.
++ * The real one will be set later. */
++ static struct sockaddr default_mac_iface1 =
++ {0, {0x00, 0x40, 0x8C, 0xCD, 0x00, 0x01}};
++
++ if (crisv32_pinmux_alloc_fixed(pinmux_eth1))
++ panic("Eth pinmux\n");
++
++ /* Increase index to device array if interface 0 is enabled as well.*/
++#ifdef CONFIG_ETRAX_ETHERNET_IFACE0
++ iface1++;
++#endif
++ if (!(crisv32_dev[iface1] = alloc_etherdev(sizeof *np)))
++ return -ENOMEM;
++
++ ret |= crisv32_ethernet_device_init(crisv32_dev[iface1]);
++
++#if defined(CONFIG_ETRAX_ETH1_USE_LEDGRP0)
++ crisv32_init_leds(LED_GRP_0,crisv32_dev[iface1]);
++#elif defined(CONFIG_ETRAX_ETH1_USE_LEDGRP1)
++ crisv32_init_leds(LED_GRP_1,crisv32_dev[iface1]);
++#else
++ crisv32_init_leds(LED_GRP_NONE,crisv32_dev[iface1]);
++#endif
++
++ np = (struct crisv32_ethernet_local *) crisv32_dev[iface1]->priv;
++ np->eth_inst = regi_eth1;
++ np->dma_out_inst = regi_dma6;
++ np->dma_in_inst = regi_dma7;
++
++ register_netdev(crisv32_dev[iface1]);
++
++ /* Set up default MAC address */
++ memcpy(crisv32_dev[iface1]->dev_addr, default_mac_iface1.sa_data, 6);
++ crisv32_eth_set_mac_address(crisv32_dev[iface1], &default_mac_iface1);
++
++ if (crisv32_eth_request_irqdma(crisv32_dev[iface1]))
++ printk("%s: eth1 unable to allocate IRQ and DMA resources\n",
++ __func__);
++ np->txpackets = 0;
++ crisv32_eth_init_rings(crisv32_dev[iface1]);
++ crisv32_eth_setup_controller(crisv32_dev[iface1]);
++}
++#endif /* CONFIG_ETRAX_ETHERNET_IFACE1 */
++
++#ifdef CONFIG_CPU_FREQ
++ cpufreq_register_notifier(&crisv32_ethernet_freq_notifier_block,
++ CPUFREQ_TRANSITION_NOTIFIER);
++#endif
++
++ return ret;
++}
++
++static int __init
++crisv32_ethernet_device_init(struct net_device* dev)
++{
++ struct timer_list timer_init = TIMER_INITIALIZER(NULL, 0, 0);
++ struct crisv32_ethernet_local *np;
++
++ dev->base_addr = 0; /* Just to have something to show. */
++
++ /* we do our own locking */
++ dev->features |= NETIF_F_LLTX;
++
++ /* We use several IRQs and DMAs so just report 0 here. */
++ dev->irq = 0;
++ dev->dma = 0;
++
++ /*
++ * Fill in our handlers so the network layer can talk to us in the
++ * future.
++ */
++ dev->open = crisv32_eth_open;
++ dev->hard_start_xmit = crisv32_eth_send_packet;
++ dev->stop = crisv32_eth_close;
++ dev->get_stats = crisv32_get_stats;
++ dev->set_multicast_list = crisv32_eth_set_multicast_list;
++ dev->set_mac_address = crisv32_eth_set_mac_address;
++ dev->ethtool_ops = &crisv32_ethtool_ops;
++ dev->do_ioctl = crisv32_eth_ioctl;
++ dev->set_config = crisv32_eth_set_config;
++ dev->tx_timeout = crisv32_eth_tx_timeout;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ dev->poll_controller = crisv32_netpoll;
++#endif
++
++ np = netdev_priv(dev);
++
++ spin_lock_init(&np->lock);
++ spin_lock_init(&np->transceiver_lock);
++
++ /* Initialize speed indicator stuff. */
++ np->current_speed = 10;
++ np->current_speed_selection = 0; /* Auto. */
++ np->speed_timer = timer_init;
++ np->speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
++ np->speed_timer.data = (unsigned long) dev;
++ np->speed_timer.function = crisv32_eth_check_speed;
++
++ np->full_duplex = 0;
++ np->current_duplex = autoneg;
++ np->duplex_timer = timer_init;
++ np->duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
++ np->duplex_timer.data = (unsigned long) dev;
++ np->duplex_timer.function = crisv32_eth_check_duplex;
++
++ return 0;
++}
++
++static int
++crisv32_eth_open(struct net_device *dev)
++{
++ struct sockaddr mac_addr;
++ reg_dma_rw_ack_intr ack_intr = { .data = 1,.in_eop = 1 };
++ reg_dma_rw_cfg dma_cfg = { .en = 1 };
++ reg_eth_rw_clr_err clr_err = {.clr = regk_eth_yes};
++ int intr_mask_nw = 0x1cff;
++ int eth_ack_intr = 0xffff;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ spin_lock(&np->lock);
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ np->gigabit_mode = 0;
++#endif
++ crisv32_disable_tx_ints(np);
++ crisv32_disable_rx_ints(np);
++
++ REG_WR(eth, np->eth_inst, rw_clr_err, clr_err);
++ REG_WR_INT(eth, np->eth_inst, rw_ack_intr, eth_ack_intr);
++ REG_WR_INT(eth, np->eth_inst, rw_intr_mask, intr_mask_nw);
++ crisv32_eth_reset_rings(dev);
++
++ /* Give the hardware an idea of what MAC address we want. */
++ memcpy(mac_addr.sa_data, dev->dev_addr, dev->addr_len);
++ crisv32_eth_set_mac_address(dev, &mac_addr);
++
++ /* Enable irq and make sure that the irqs are cleared. */
++ REG_WR(dma, np->dma_out_inst, rw_ack_intr, ack_intr);
++ REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr);
++
++ /* Prepare input DMA. */
++ DMA_RESET(np->dma_in_inst);
++ DMA_ENABLE(np->dma_in_inst);
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ DMA_WR_CMD(np->dma_in_inst, regk_dma_set_w_size2);
++#endif
++ DMA_START_CONTEXT( np->dma_in_inst, virt_to_phys(&np->ctxt_in));
++ DMA_CONTINUE(np->dma_in_inst);
++ crisv32_enable_rx_ints(np);
++ crisv32_start_receiver(np);
++
++ /* Prepare output DMA. */
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ DMA_WR_CMD(np->dma_out_inst, regk_dma_set_w_size4);
++#endif
++ REG_WR(dma, np->dma_out_inst, rw_cfg, dma_cfg);
++ netif_start_queue(dev);
++ crisv32_enable_tx_ints(np);
++
++ /* Start duplex/speed timers */
++ add_timer(&np->speed_timer);
++ add_timer(&np->duplex_timer);
++
++ spin_unlock(&np->lock);
++ /*
++ * We are now ready to accept transmit requeusts from the queueing
++ * layer of the networking.
++ */
++ netif_carrier_on(dev);
++
++ return 0;
++}
++
++static int
++crisv32_eth_close(struct net_device *dev)
++{
++ reg_dma_rw_ack_intr ack_intr = {0};
++
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ unsigned long flags;
++
++ printk(KERN_INFO "Closing %s.\n", dev->name);
++
++ /* stop the receiver before the DMA channels to avoid overruns. */
++ crisv32_stop_receiver(np);
++
++ spin_lock_irqsave(&np->lock, flags);
++ netif_stop_queue(dev);
++
++ /* Reset the TX DMA in case it has hung on something. */
++ DMA_RESET(np->dma_in_inst);
++
++ /* Stop DMA */
++ DMA_STOP(np->dma_in_inst);
++ DMA_STOP(np->dma_out_inst);
++
++ /* Disable irq and make sure that the irqs are cleared. */
++ crisv32_disable_tx_ints(np);
++ ack_intr.data = 1;
++ REG_WR(dma, np->dma_out_inst, rw_ack_intr, ack_intr);
++
++ crisv32_disable_rx_ints(np);
++ ack_intr.in_eop = 1;
++ REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr);
++
++ np->sender_started = 0;
++ spin_unlock_irqrestore(&np->lock, flags);
++
++ /* Update the statistics. */
++ update_rx_stats(np);
++ update_tx_stats(np);
++
++ /* Stop speed/duplex timers */
++ del_timer(&np->speed_timer);
++ del_timer(&np->duplex_timer);
++
++ return 0;
++}
++
++static int
++crisv32_eth_set_mac_address(struct net_device *dev, void *vpntr)
++{
++ int i;
++ unsigned char *addr = ((struct sockaddr*)vpntr)->sa_data;
++
++ reg_eth_rw_ma0_lo ma0_lo =
++ { addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24)};
++
++ reg_eth_rw_ma0_hi ma0_hi = { addr[4] | (addr[5] << 8) };
++
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ /* Remember the address. */
++ memcpy(dev->dev_addr, addr, dev->addr_len);
++
++ /*
++ * Write the address to the hardware.
++ * Note the way the address is wrapped:
++ * ma0_l0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24);
++ * ma0_hi = a0_4 | (a0_5 << 8);
++ */
++ REG_WR(eth, np->eth_inst, rw_ma0_lo, ma0_lo);
++ REG_WR(eth, np->eth_inst, rw_ma0_hi, ma0_hi);
++
++ 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]);
++
++ return 0;
++}
++
++static irqreturn_t
++crisv32rx_eth_interrupt(int irq, void *dev_id)
++{
++ reg_dma_r_masked_intr masked_in;
++ reg_dma_rw_cmd cmd = {0};
++ reg_dma_rw_ack_intr ack_intr = {0};
++ struct net_device *dev = (struct net_device *) dev_id;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ masked_in = REG_RD(dma, np->dma_in_inst, r_masked_intr);
++
++ if (masked_in.in_eop) {
++ DEBUG(printk("EOP_IN interrupt\n"));
++
++ /* Acknowledge input dma interrupt. */
++ ack_intr.in_eop = 1;
++ REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr);
++
++ np->new_rx_package = 1;
++ /* Check if complete packets were indeed received. */
++ while (np->active_rx_desc->descr.in_eop == 1
++ && np->new_rx_package) {
++ /*
++ * Take out the buffer and give it to the OS, then
++ * allocate a new buffer to put a packet in.
++ */
++ crisv32_eth_receive_packet(dev);
++
++ /* Update number of packets received. */
++ np->stats.rx_packets++;
++
++ /* Restarts input dma. */
++ cmd.cont_data = 1;
++ REG_WR(dma, np->dma_in_inst, rw_cmd, cmd);
++
++ /* Acknowledge input dma interrupt. */
++ REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr);
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t
++crisv32tx_eth_interrupt(int irq, void *dev_id)
++{
++ reg_dma_rw_stat stat;
++ dma_descr_data *dma_pos;
++ reg_dma_rw_ack_intr ack_intr = { .data = 1 };
++ reg_dma_r_masked_intr masked_out;
++
++ struct net_device *dev = (struct net_device *) dev_id;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ unsigned long flags;
++
++ masked_out = REG_RD(dma, np->dma_out_inst, r_masked_intr);
++
++ /* Get the current output dma position. */
++ stat = REG_RD(dma, np->dma_out_inst, rw_stat);
++ if (stat.list_state == regk_dma_data_at_eol)
++ dma_pos = &np->active_tx_desc->descr;
++ else
++ dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_out_inst,
++ rw_data));
++
++ /* ack the interrupt */
++ REG_WR(dma, np->dma_out_inst, rw_ack_intr, ack_intr);
++
++ /* protect against ethernet excessive-col interrupts */
++ spin_lock_irqsave(&np->lock, flags);
++
++ /* Take care of transmited dma descriptors and report sent packet. */
++ while (np->txpackets && ((&np->catch_tx_desc->descr != dma_pos)
++ || netif_queue_stopped(dev))) {
++ /* Update sent packet statistics. */
++ np->stats.tx_bytes += np->catch_tx_desc->skb->len;
++ np->stats.tx_packets++;
++
++ dev_kfree_skb_irq(np->catch_tx_desc->skb);
++ np->catch_tx_desc->skb = 0;
++ np->txpackets--;
++ np->catch_tx_desc =
++ phys_to_virt((int)np->catch_tx_desc->descr.next);
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ if (np->gigabit_mode) {
++ np->intmem_tx_buf_catch->free = 1;
++ np->intmem_tx_buf_catch = np->intmem_tx_buf_catch->next;
++ }
++#endif
++ netif_wake_queue(dev);
++ }
++ spin_unlock_irqrestore(&np->lock, flags);
++ return IRQ_HANDLED;
++}
++
++
++/* Update receive errors. */
++static void
++update_rx_stats(struct crisv32_ethernet_local *np)
++{
++ reg_eth_rs_rec_cnt r;
++ reg_eth_rs_phy_cnt rp;
++
++ r = REG_RD(eth, np->eth_inst, rs_rec_cnt);
++ rp = REG_RD(eth, np->eth_inst, rs_phy_cnt);
++
++ np->stats.rx_fifo_errors += r.congestion;
++ np->stats.rx_crc_errors += r.crc_err;
++ np->stats.rx_frame_errors += r.align_err;
++ np->stats.rx_length_errors += r.oversize;
++}
++
++/* Update transmit errors. */
++static void
++update_tx_stats(struct crisv32_ethernet_local *np)
++{
++ reg_eth_rs_tr_cnt r;
++
++ r = REG_RD(eth, np->eth_inst, rs_tr_cnt);
++
++ np->stats.collisions += r.single_col + r.mult_col;
++ np->stats.tx_errors += r.deferred;
++}
++
++/* Get current statistics. */
++static struct net_device_stats *
++crisv32_get_stats(struct net_device *dev)
++{
++ unsigned long flags;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ spin_lock_irqsave(&np->lock, flags);
++
++ update_rx_stats(np);
++ update_tx_stats(np);
++
++ spin_unlock_irqrestore(&np->lock, flags);
++
++ return &np->stats;
++}
++
++/* Check for network errors. This acknowledge the received interrupt. */
++static irqreturn_t
++crisv32nw_eth_interrupt(int irq, void *dev_id)
++{
++ struct net_device *dev = (struct net_device *) dev_id;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ reg_eth_r_masked_intr intr_mask;
++ int ack_intr = 0xffff;
++ reg_eth_rw_clr_err clr_err;
++
++ intr_mask = REG_RD(eth, np->eth_inst, r_masked_intr);
++
++ /*
++ * Check for underrun and/or excessive collisions. Note that the
++ * rw_clr_err register clears both underrun and excessive collision
++ * errors, so there's no need to check them separately.
++ */
++ if (np->sender_started
++ && (intr_mask.urun || intr_mask.exc_col)) {
++ unsigned long flags;
++ dma_descr_data *dma_pos;
++ reg_dma_rw_stat stat;
++
++ /* Get the current output dma position. */
++ stat = REG_RD(dma, np->dma_out_inst, rw_stat);
++ if (stat.list_state == regk_dma_data_at_eol)
++ dma_pos = &np->active_tx_desc->descr;
++ else
++ dma_pos = phys_to_virt(REG_RD_INT(dma,
++ np->dma_out_inst,
++ rw_data));
++
++ /*
++ * Protect against the tx-interrupt messing with
++ * the tx-ring.
++ */
++ spin_lock_irqsave(&np->lock, flags);
++ /*
++ * If we have more than one packet in the tx-ring
++ * drop one and move ahead. Upper layers rely on
++ * packeloss when doing congestion control.
++ */
++ if (intr_mask.exc_col && np->txpackets > 1) {
++ dev_kfree_skb_irq(np->catch_tx_desc->skb);
++ np->catch_tx_desc->skb = 0;
++ np->catch_tx_desc =
++ phys_to_virt((int)
++ np->catch_tx_desc->descr.next);
++ np->txpackets--;
++ netif_wake_queue(dev);
++ }
++ np->ctxt_out.next = 0;
++ if (np->txpackets) {
++ np->ctxt_out.saved_data = (void *)
++ virt_to_phys(&np->catch_tx_desc->descr);
++ np->ctxt_out.saved_data_buf =
++ np->catch_tx_desc->descr.buf;
++
++ /* restart the DMA */
++ DMA_START_CONTEXT(np->dma_out_inst,
++ (int) virt_to_phys(&np->ctxt_out));
++ }
++ else {
++ /* let the next packet restart the DMA */
++ np->ctxt_out.saved_data = (void *)
++ virt_to_phys(&np->active_tx_desc->descr);
++ np->sender_started = 0;
++ }
++
++ spin_unlock_irqrestore(&np->lock, flags);
++ np->stats.tx_errors++;
++ }
++
++ REG_WR_INT(eth, np->eth_inst, rw_ack_intr, ack_intr);
++ clr_err.clr = 1;
++ REG_WR(eth, np->eth_inst, rw_clr_err, clr_err);
++
++ update_rx_stats(np);
++ update_tx_stats(np);
++
++ return IRQ_HANDLED;
++}
++
++/* We have a good packet(s), get it/them out of the buffers. */
++static void
++crisv32_eth_receive_packet(struct net_device *dev)
++{
++ int length;
++ struct sk_buff *skb;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ struct sk_buff *tmp;
++ unsigned long flags;
++
++ DEBUG(printk("crisv32_receive_packet\n"));
++
++ /* Activate LED */
++ spin_lock_irqsave(&np->leds->led_lock, flags);
++ if (!np->leds->led_active && time_after(jiffies, np->leds->led_next_time)) {
++ /* light the network leds depending on the current speed. */
++ crisv32_set_network_leds(LED_ACTIVITY, dev);
++
++ /* Set the earliest time we may clear the LED */
++ np->leds->led_next_time = jiffies + NET_FLASH_TIME;
++ np->leds->led_active = 1;
++ np->leds->clear_led_timer.data = (unsigned long) dev;
++ mod_timer(&np->leds->clear_led_timer, jiffies + HZ/10);
++ }
++ spin_unlock_irqrestore(&np->leds->led_lock, flags);
++
++ /* Discard CRC (4 bytes). */
++ length = (np->active_rx_desc->descr.after) -
++ (np->active_rx_desc->descr.buf) - 4;
++
++ /* Update received packet statistics. */
++ np->stats.rx_bytes += length;
++
++ if (np->active_rx_desc != np->last_rx_desc) {
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ if (np->gigabit_mode) {
++ skb = dev_alloc_skb(length);
++ if(!skb) {
++ np->stats.rx_errors++;
++ printk(KERN_NOTICE "%s: memory squeeze,"
++ " dropping packet.", dev->name);
++ return;
++ }
++ /* Allocate room for the packet body. */
++ skb_put(skb, length - ETHER_HEAD_LEN);
++ /* Allocate room for the header and copy the data to
++ * the SKB */
++ memcpy(skb_push(skb, ETHER_HEAD_LEN),
++ crisv32_intmem_phys_to_virt((unsigned long)np->active_rx_desc->descr.buf), length);
++ skb->dev = dev;
++ skb->protocol = eth_type_trans(skb, dev);
++ skb->ip_summed = CHECKSUM_NONE;
++ /* Send the packet to the upper layer. */
++ netif_rx(skb);
++ np->last_rx_desc =
++ (void *) phys_to_virt(np->last_rx_desc->descr.next);
++ } else {
++#endif
++ tmp = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
++ if (!tmp) {
++ np->stats.rx_errors++;
++ printk(KERN_NOTICE "%s: memory squeeze,"
++ " dropping packet.",
++ dev->name);
++ return;
++ }
++ skb = np->active_rx_desc->skb;
++ np->active_rx_desc->skb = tmp;
++ skb_put(skb, length);
++
++ np->active_rx_desc->descr.buf =
++ (void *) virt_to_phys(np->active_rx_desc->skb->data);
++ np->active_rx_desc->descr.after =
++ np->active_rx_desc->descr.buf + MAX_MEDIA_DATA_SIZE;
++
++ skb->dev = dev;
++ skb->protocol = eth_type_trans(skb, dev);
++ skb->ip_summed = CHECKSUM_NONE;
++
++ /* Send the packet to the upper layer. */
++ netif_rx(skb);
++ np->last_rx_desc =
++ phys_to_virt((int)
++ np->last_rx_desc->descr.next);
++ }
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ }
++#endif
++ /*
++ * When the input DMA reaches eol precaution must be taken, otherwise
++ * the DMA could stop. The problem occurs if the eol flag is re-placed
++ * on the descriptor that the DMA stands on before the DMA proceed to
++ * the next descriptor. This case could, for example, happen if there
++ * is a traffic burst and then the network goes silent. To prevent this
++ * we make sure that we do not set the eol flag on the descriptor that
++ * the DMA stands on.
++ */
++ if(virt_to_phys(&np->active_rx_desc->descr) !=
++ REG_RD_INT(dma, np->dma_in_inst, rw_saved_data)) {
++ np->active_rx_desc->descr.after =
++ np->active_rx_desc->descr.buf + MAX_MEDIA_DATA_SIZE;
++ np->active_rx_desc->descr.eol = 1;
++ np->active_rx_desc->descr.in_eop = 0;
++ np->active_rx_desc =
++ phys_to_virt((int)np->active_rx_desc->descr.next);
++ barrier();
++ np->prev_rx_desc->descr.eol = 0;
++ flush_dma_descr(&np->prev_rx_desc->descr, 0); // Workaround cache bug
++ np->prev_rx_desc =
++ phys_to_virt((int)np->prev_rx_desc->descr.next);
++ flush_dma_descr(&np->prev_rx_desc->descr, 1); // Workaround cache bug
++ } else {
++ np->new_rx_package = 0;
++ }
++}
++
++/*
++ * This function (i.e. hard_start_xmit) is protected from concurent calls by a
++ * spinlock (xmit_lock) in the net_device structure.
++ */
++static int
++crisv32_eth_send_packet(struct sk_buff *skb, struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ unsigned char *buf = skb->data;
++ unsigned long flags;
++
++ dev->trans_start = jiffies;
++
++ spin_lock_irqsave(&np->leds->led_lock, flags);
++ if (!np->leds->led_active && time_after(jiffies, np->leds->led_next_time)) {
++ /* light the network leds depending on the current speed. */
++ crisv32_set_network_leds(LED_ACTIVITY, dev);
++
++ /* Set the earliest time we may clear the LED */
++ np->leds->led_next_time = jiffies + NET_FLASH_TIME;
++ np->leds->led_active = 1;
++ np->leds->clear_led_timer.data = (unsigned long) dev;
++ mod_timer(&np->leds->clear_led_timer, jiffies + HZ/10);
++ }
++ spin_unlock_irqrestore(&np->leds->led_lock, flags);
++
++ /*
++ * Need to disable irq to avoid updating pointer in interrupt while
++ * sending packets.
++ */
++ spin_lock_irqsave(&np->lock, flags);
++
++ np->active_tx_desc->skb = skb;
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ if (np->gigabit_mode) {
++ if(np->intmem_tx_buf_active->free) {
++ memcpy(np->intmem_tx_buf_active->buf,
++ skb->data, skb->len);
++ np->intmem_tx_buf_active->free = 0;
++ crisv32_eth_hw_send_packet(
++ np->intmem_tx_buf_active->buf, skb->len, np);
++ np->intmem_tx_buf_active =
++ np->intmem_tx_buf_active->next;
++ } else {
++ printk("%s: Internal tx memory buffer not free!\n\r",
++ __FILE__);
++ spin_unlock_irqrestore(&np->lock, flags);
++ return 1;
++ }
++ }
++ else
++#endif
++ {
++ crisv32_eth_hw_send_packet(buf, skb->len, np);
++ }
++ /* Stop queue if full. */
++ if (np->active_tx_desc == np->catch_tx_desc)
++ netif_stop_queue(dev);
++
++ np->txpackets++;
++ spin_unlock_irqrestore(&np->lock, flags);
++
++ return 0;
++}
++
++
++static void
++crisv32_eth_hw_send_packet(unsigned char *buf, int length, void *priv)
++{
++ struct crisv32_ethernet_local *np =
++ (struct crisv32_ethernet_local *) priv;
++
++ /* Configure the tx dma descriptor. */
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ if (np->gigabit_mode) {
++ np->active_tx_desc->descr.buf = (unsigned char *) crisv32_intmem_virt_to_phys(buf);
++ } else
++#endif
++ {
++ np->active_tx_desc->descr.buf = (unsigned char *) virt_to_phys(buf);
++ }
++
++ np->active_tx_desc->descr.after = np->active_tx_desc->descr.buf +
++ length;
++ np->active_tx_desc->descr.intr = 1;
++ np->active_tx_desc->descr.out_eop = 1;
++
++ /* Move eol. */
++ np->active_tx_desc->descr.eol = 1;
++ np->prev_tx_desc->descr.eol = 0;
++
++
++ /* Update pointers. */
++ np->prev_tx_desc = np->active_tx_desc;
++ np->active_tx_desc = phys_to_virt((int)np->active_tx_desc->descr.next);
++
++ /* Start DMA. */
++ crisv32_start_dma_out(np);
++}
++
++static void
++crisv32_start_dma_out(struct crisv32_ethernet_local* np)
++{
++ if (!np->sender_started) {
++ /* Start DMA for the first time. */
++ np->ctxt_out.saved_data_buf = np->prev_tx_desc->descr.buf;
++ REG_WR(dma, np->dma_out_inst, rw_group_down,
++ (int) virt_to_phys(&np->ctxt_out));
++ DMA_WR_CMD(np->dma_out_inst, regk_dma_load_c);
++ DMA_WR_CMD(np->dma_out_inst, regk_dma_load_d | regk_dma_burst);
++ np->sender_started = 1;
++ } else {
++ DMA_CONTINUE_DATA(np->dma_out_inst);
++ }
++}
++
++/*
++ * Called by upper layers if they decide it took too long to complete sending
++ * a packet - we need to reset and stuff.
++ */
++static void
++crisv32_eth_tx_timeout(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ reg_dma_rw_cfg cfg = {0};
++ reg_dma_rw_stat stat = {0};
++ unsigned long flags;
++
++ printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
++
++
++ spin_lock_irqsave(&np->lock, flags);
++ crisv32_ethernet_bug(dev);
++
++ np->txpackets = 0;
++ /* Update error stats. */
++ np->stats.tx_errors++;
++
++ /* Reset the TX DMA in case it has hung on something. */
++ cfg.en = 0;
++ REG_WR(dma, np->dma_out_inst, rw_cfg, cfg);
++
++ do {
++ stat = REG_RD(dma, np->dma_out_inst, rw_stat);
++ } while (stat.mode != regk_dma_rst);
++
++ /* Reset the tranceiver. */
++ crisv32_eth_reset_tranceiver(dev);
++
++ /* Get rid of the packets that never got an interrupt. */
++ do {
++ if (np->catch_tx_desc->skb)
++ dev_kfree_skb(np->catch_tx_desc->skb);
++
++ np->catch_tx_desc->skb = 0;
++ np->catch_tx_desc =
++ phys_to_virt((int)np->catch_tx_desc->descr.next);
++ } while (np->catch_tx_desc != np->active_tx_desc);
++
++
++ /* Start output DMA. */
++ REG_WR(dma, np->dma_out_inst, rw_group_down,
++ (int) virt_to_phys(&np->ctxt_out));
++ DMA_WR_CMD(np->dma_out_inst, regk_dma_load_c);
++ DMA_WR_CMD(np->dma_out_inst, regk_dma_load_d | regk_dma_burst);
++ spin_unlock_irqrestore(&np->lock, flags);
++
++ /* Tell the upper layers we're ok again. */
++ netif_wake_queue(dev);
++}
++
++/*
++ * 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
++crisv32_eth_set_multicast_list(struct net_device *dev)
++{
++ int num_addr = dev->mc_count;
++ unsigned long int lo_bits;
++ unsigned long int hi_bits;
++ reg_eth_rw_rec_ctrl rec_ctrl = {0};
++ reg_eth_rw_ga_lo ga_lo = {0};
++ reg_eth_rw_ga_hi ga_hi = {0};
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ if (dev->flags & IFF_PROMISC) {
++ /* Promiscuous mode. */
++ lo_bits = 0xfffffffful;
++ hi_bits = 0xfffffffful;
++
++ /* Enable individual receive. */
++ rec_ctrl = (reg_eth_rw_rec_ctrl) REG_RD(eth, np->eth_inst,
++ rw_rec_ctrl);
++ rec_ctrl.individual = regk_eth_yes;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++ } else if (dev->flags & IFF_ALLMULTI) {
++ /* Enable all multicasts. */
++ lo_bits = 0xfffffffful;
++ hi_bits = 0xfffffffful;
++
++ /* Disable individual receive */
++ rec_ctrl =
++ (reg_eth_rw_rec_ctrl) REG_RD(eth, np->eth_inst, rw_rec_ctrl);
++ rec_ctrl.individual = regk_eth_no;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++ } else if (num_addr == 0) {
++ /* Normal, clear the mc list. */
++ lo_bits = 0x00000000ul;
++ hi_bits = 0x00000000ul;
++
++ /* Disable individual receive */
++ rec_ctrl =
++ (reg_eth_rw_rec_ctrl) REG_RD(eth, np->eth_inst, rw_rec_ctrl);
++ rec_ctrl.individual = regk_eth_no;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++ } 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. */
++ rec_ctrl =
++ (reg_eth_rw_rec_ctrl) REG_RD(eth, np->eth_inst, rw_rec_ctrl);
++ rec_ctrl.individual = regk_eth_no;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++ }
++
++ ga_lo.tbl = (unsigned int) lo_bits;
++ ga_hi.tbl = (unsigned int) hi_bits;
++
++ REG_WR(eth, np->eth_inst, rw_ga_lo, ga_lo);
++ REG_WR(eth, np->eth_inst, rw_ga_hi, ga_hi);
++}
++
++static int
++crisv32_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct mii_ioctl_data *data = if_mii(ifr);
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ int old_autoneg;
++
++ spin_lock(&np->lock); /* Preempt protection */
++ switch (cmd) {
++ case SIOCGMIIPHY: /* Get PHY address */
++ data->phy_id = np->mdio_phy_addr;
++ break;
++ case SIOCGMIIREG: /* Read MII register */
++ data->val_out = crisv32_eth_get_mdio_reg(dev,
++ data->reg_num);
++ break;
++ case SIOCSMIIREG: /* Write MII register */
++ crisv32_eth_set_mdio_reg(dev, data->reg_num,
++ data->val_in);
++ break;
++ case SET_ETH_ENABLE_LEDS:
++ use_network_leds = 1;
++ break;
++ case SET_ETH_DISABLE_LEDS:
++ use_network_leds = 0;
++ break;
++ case SET_ETH_AUTONEG:
++ old_autoneg = autoneg_normal;
++ autoneg_normal = *(int*)data;
++ if (autoneg_normal != old_autoneg)
++ crisv32_eth_negotiate(dev);
++ break;
++ default:
++ spin_unlock(&np->lock); /* Preempt protection */
++ return -EINVAL;
++ }
++ spin_unlock(&np->lock);
++ return 0;
++}
++
++static int crisv32_eth_get_settings(struct net_device *dev,
++ struct ethtool_cmd *ecmd)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ /* What about GMII and 1000xpause? not included in ethtool.h */
++ ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
++ SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
++ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ ecmd->supported |= SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
++#endif
++ ecmd->port = PORT_TP;
++ ecmd->transceiver = XCVR_EXTERNAL;
++ ecmd->phy_address = np->mdio_phy_addr;
++ ecmd->speed = np->current_speed;
++ ecmd->duplex = np->full_duplex;
++ ecmd->advertising = ADVERTISED_TP;
++
++ if (np->current_duplex == autoneg && np->current_speed_selection == 0)
++ ecmd->advertising |= ADVERTISED_Autoneg;
++ else {
++ ecmd->advertising |=
++ ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
++ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ ecmd->advertising |= ADVERTISED_1000baseT_Half |
++ ADVERTISED_1000baseT_Full;
++#endif
++ if (np->current_speed_selection == 10)
++ ecmd->advertising &= ~(ADVERTISED_100baseT_Half |
++ ADVERTISED_100baseT_Full |
++ ADVERTISED_1000baseT_Half |
++ ADVERTISED_1000baseT_Full);
++
++ else if (np->current_speed_selection == 100)
++ ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
++ ADVERTISED_10baseT_Full |
++ ADVERTISED_1000baseT_Half |
++ ADVERTISED_1000baseT_Full);
++
++ else if (np->current_speed_selection == 1000)
++ ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
++ ADVERTISED_10baseT_Full |
++ ADVERTISED_100baseT_Half |
++ ADVERTISED_100baseT_Full);
++
++ if (np->current_duplex == half)
++ ecmd->advertising &= ~(ADVERTISED_10baseT_Full |
++ ADVERTISED_100baseT_Full |
++ ADVERTISED_1000baseT_Full);
++ else if (np->current_duplex == full)
++ ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
++ ADVERTISED_100baseT_Half |
++ ADVERTISED_1000baseT_Half);
++ }
++
++ ecmd->autoneg = AUTONEG_ENABLE;
++ return 0;
++}
++
++static int crisv32_eth_set_settings(struct net_device *dev,
++ struct ethtool_cmd *ecmd)
++{
++ if (ecmd->autoneg == AUTONEG_ENABLE) {
++ crisv32_eth_set_duplex(dev, autoneg);
++ crisv32_eth_set_speed(dev, 0);
++ } else {
++ crisv32_eth_set_duplex(dev, ecmd->duplex);
++ crisv32_eth_set_speed(dev, ecmd->speed);
++ }
++
++ return 0;
++}
++
++static void crisv32_eth_get_drvinfo(struct net_device *dev,
++ struct ethtool_drvinfo *info)
++{
++ strncpy(info->driver, "ETRAX FS", sizeof(info->driver) - 1);
++ strncpy(info->version, "$Revision: 1.96 $", 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);
++}
++
++static int crisv32_eth_nway_reset(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ if (np->current_duplex == autoneg && np->current_speed_selection == 0)
++ crisv32_eth_negotiate(dev);
++ return 0;
++}
++
++static struct ethtool_ops crisv32_ethtool_ops = {
++ .get_settings = crisv32_eth_get_settings,
++ .set_settings = crisv32_eth_set_settings,
++ .get_drvinfo = crisv32_eth_get_drvinfo,
++ .nway_reset = crisv32_eth_nway_reset,
++ .get_link = ethtool_op_get_link,
++};
++
++/* Is this function really needed? Use ethtool instead? */
++static int
++crisv32_eth_set_config(struct net_device *dev, struct ifmap *map)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ spin_lock(&np->lock); /* Preempt protection */
++
++ switch(map->port) {
++ case IF_PORT_UNKNOWN:
++ /* Use autoneg */
++ crisv32_eth_set_speed(dev, 0);
++ crisv32_eth_set_duplex(dev, autoneg);
++ break;
++ case IF_PORT_10BASET:
++ crisv32_eth_set_speed(dev, 10);
++ crisv32_eth_set_duplex(dev, autoneg);
++ break;
++ case IF_PORT_100BASET:
++ case IF_PORT_100BASETX:
++ crisv32_eth_set_speed(dev, 100);
++ crisv32_eth_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;
++}
++
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++/*
++ * Switch the behaviour of the tx and rx buffers using
++ * external or internal memory. Usage of the internal
++ * memory is required for gigabit operation.
++ */
++static void
++crisv32_eth_switch_intmem_usage(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ int i;
++ reg_dma_rw_stat stat;
++ reg_dma_rw_cfg cfg = {0};
++ reg_dma_rw_intr_mask intr_mask_in = { .in_eop = regk_dma_yes };
++ reg_dma_rw_ack_intr ack_intr = { .data = 1,.in_eop = 1 };
++ unsigned char *intmem_tmp;
++
++ /* Notify the kernel that the interface has stopped */
++ netif_stop_queue(dev);
++
++ /* Stop the receiver DMA */
++ cfg.en = regk_dma_no;
++ REG_WR(dma, np->dma_in_inst, rw_cfg, cfg);
++
++ if (!(np->gigabit_mode)) {
++ /* deallocate SKBs in rx_desc */
++ for (i = 0; i < NBR_RX_DESC; i++)
++ dev_kfree_skb(np->dma_rx_descr_list[i].skb);
++
++ /* Init TX*/
++ for(i=0; i < NBR_INTMEM_TX_BUF; i++) {
++ /* Allocate internal memory */
++ intmem_tmp = NULL;
++ intmem_tmp = crisv32_intmem_alloc(MAX_MEDIA_DATA_SIZE,
++ 32);
++ /* Check that we really got the memory */
++ if (intmem_tmp == NULL) {
++ printk(KERN_ERR "%s: Can't allocate intmem for"
++ " RX buffer nbr: %d\n", dev->name, i);
++ return;
++ }
++ /* Setup the list entry */
++ np->tx_intmem_buf_list[i].free = 1;
++ np->tx_intmem_buf_list[i].buf = intmem_tmp;
++ np->tx_intmem_buf_list[i].next = &np->tx_intmem_buf_list[i + 1];
++ }
++ /* Setup the last list entry */
++ np->tx_intmem_buf_list[NBR_INTMEM_TX_BUF - 1].next = &np->tx_intmem_buf_list[0];
++ /* Setup initial pointer */
++ np->intmem_tx_buf_active = np->tx_intmem_buf_list;
++ np->intmem_tx_buf_catch = np->tx_intmem_buf_list;
++
++ /* Init RX */
++ for (i=0; i < NBR_INTMEM_RX_DESC; i++) {
++ /* Allocate internal memory */
++ intmem_tmp = NULL;
++ intmem_tmp = crisv32_intmem_alloc(MAX_MEDIA_DATA_SIZE, 32);
++ /* Check that we really got the memory */
++ if (intmem_tmp == NULL) {
++ printk(KERN_ERR "%s: Can't allocate intmem for"
++ " desc nbr: %d\n", dev->name, i);
++ return;
++ }
++ /* Setup the descriptors*/
++ np->dma_rx_descr_list[i].skb = NULL;
++ np->dma_rx_descr_list[i].descr.buf =
++ (void *) crisv32_intmem_virt_to_phys(intmem_tmp);
++ np->dma_rx_descr_list[i].descr.after =
++ (void *) crisv32_intmem_virt_to_phys(intmem_tmp + MAX_MEDIA_DATA_SIZE);
++ np->dma_rx_descr_list[i].descr.eol = 0;
++ np->dma_rx_descr_list[i].descr.in_eop = 0;
++ np->dma_rx_descr_list[i].descr.next =
++ (void *) virt_to_phys(&np->dma_rx_descr_list[i+1].descr);
++ }
++ /* Setup the last rx descriptor */
++ np->dma_rx_descr_list[NBR_INTMEM_RX_DESC - 1].descr.eol = 1;
++ np->dma_rx_descr_list[NBR_INTMEM_RX_DESC - 1].descr.next =
++ (void*) virt_to_phys(&np->dma_rx_descr_list[0].descr);
++ /* Initialise initial receive pointers. */
++ np->active_rx_desc = &np->dma_rx_descr_list[0];
++ np->prev_rx_desc = &np->dma_rx_descr_list[NBR_INTMEM_RX_DESC - 1];
++ np->last_rx_desc = np->prev_rx_desc;
++
++ np->gigabit_mode = 1;
++ } else {
++ /* dealloc TX intmem */
++ for(i=0; i < NBR_INTMEM_TX_BUF; i++)
++ crisv32_intmem_free(np->tx_intmem_buf_list[i].buf);
++
++ /* dealloc RX intmem */
++ for (i=0; i < NBR_INTMEM_RX_DESC; i++)
++ crisv32_intmem_free(crisv32_intmem_phys_to_virt((unsigned long)np->dma_rx_descr_list[i].descr.buf));
++
++ /* Setup new rx_desc and alloc SKBs */
++ for (i = 0; i < NBR_RX_DESC; i++) {
++ struct sk_buff *skb;
++
++ skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
++ np->dma_rx_descr_list[i].skb = skb;
++ np->dma_rx_descr_list[i].descr.buf =
++ (char*)virt_to_phys(skb->data);
++ np->dma_rx_descr_list[i].descr.after =
++ (char*)virt_to_phys(skb->data + MAX_MEDIA_DATA_SIZE);
++
++ np->dma_rx_descr_list[i].descr.eol = 0;
++ np->dma_rx_descr_list[i].descr.in_eop = 0;
++ np->dma_rx_descr_list[i].descr.next =
++ (void *) virt_to_phys(&np->dma_rx_descr_list[i + 1].descr);
++ }
++
++ np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.eol = 1;
++ np->dma_rx_descr_list[NBR_RX_DESC - 1].descr.next =
++ (void *) virt_to_phys(&np->dma_rx_descr_list[0].descr);
++
++ /* Initialise initial receive pointers. */
++ np->active_rx_desc = &np->dma_rx_descr_list[0];
++ np->prev_rx_desc = &np->dma_rx_descr_list[NBR_RX_DESC - 1];
++ np->last_rx_desc = np->prev_rx_desc;
++
++ np->gigabit_mode = 0;
++ }
++
++ /* Fill context descriptors. */
++ np->ctxt_in.next = 0;
++ np->ctxt_in.saved_data =
++ (dma_descr_data *) virt_to_phys(&np->dma_rx_descr_list[0].descr);
++ np->ctxt_in.saved_data_buf = np->dma_rx_descr_list[0].descr.buf;
++
++ /* Enable irq and make sure that the irqs are cleared. */
++ REG_WR(dma, np->dma_in_inst, rw_intr_mask, intr_mask_in);
++ REG_WR(dma, np->dma_in_inst, rw_ack_intr, ack_intr);
++
++ /* Start input dma */
++ cfg.en = regk_dma_yes;
++ REG_WR(dma, np->dma_in_inst, rw_cfg, cfg);
++ REG_WR(dma, np->dma_in_inst, rw_group_down,
++ (int) virt_to_phys(&np->ctxt_in));
++
++ DMA_WR_CMD(np->dma_in_inst, regk_dma_load_c);
++ DMA_WR_CMD(np->dma_in_inst, regk_dma_load_d | regk_dma_burst);
++
++ netif_wake_queue(dev);
++
++ stat = REG_RD(dma, np->dma_in_inst, rw_stat);
++}
++#endif
++
++static void
++crisv32_eth_negotiate(struct net_device *dev)
++{
++ unsigned short data =
++ crisv32_eth_get_mdio_reg(dev, MII_ADVERTISE);
++ unsigned short ctrl1000 =
++ crisv32_eth_get_mdio_reg(dev, MII_CTRL1000);
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ /* Make all capabilities available */
++ data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
++ ADVERTISE_100HALF | ADVERTISE_100FULL;
++ ctrl1000 |= ADVERTISE_1000HALF | ADVERTISE_1000FULL;
++
++ /* Remove the speed capabilities that we that do not want */
++ switch (np->current_speed_selection) {
++ case 10 :
++ data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
++ ctrl1000 &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
++ break;
++ case 100 :
++ data &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
++ ctrl1000 &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
++ break;
++ case 1000 :
++ data &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
++ ADVERTISE_100HALF | ADVERTISE_100FULL);
++ break;
++ }
++
++ /* Remove the duplex capabilites that we do not want */
++ if (np->current_duplex == full) {
++ data &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
++ ctrl1000 &= ~(ADVERTISE_1000HALF);
++ }
++ else if (np->current_duplex == half) {
++ data &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
++ ctrl1000 &= ~(ADVERTISE_1000FULL);
++ }
++
++ crisv32_eth_set_mdio_reg(dev, MII_ADVERTISE, data);
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ crisv32_eth_set_mdio_reg(dev, MII_CTRL1000, ctrl1000);
++#endif
++
++ /* Renegotiate with link partner */
++ if (autoneg_normal) {
++ data = crisv32_eth_get_mdio_reg(dev, MII_BMCR);
++ data |= BMCR_ANENABLE | BMCR_ANRESTART;
++ }
++ crisv32_eth_set_mdio_reg(dev, MII_BMCR, data);
++}
++static void
++crisv32_eth_check_speed(unsigned long idev)
++{
++ static int led_initiated = 0;
++ struct net_device *dev = (struct net_device *) idev;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ unsigned long data;
++ int old_speed;
++ unsigned long flags;
++
++ BUG_ON(!np);
++ BUG_ON(!np->transceiver);
++
++ spin_lock(&np->transceiver_lock);
++
++ old_speed = np->current_speed;
++ data = crisv32_eth_get_mdio_reg(dev, MII_BMSR);
++
++ if (!(data & BMSR_LSTATUS))
++ np->current_speed = 0;
++ else
++ np->transceiver->check_speed(dev);
++
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ if ((old_speed != np->current_speed)
++ && ((old_speed == 1000) || (np->current_speed == 1000))) {
++ /* Switch between mii and gmii */
++ reg_eth_rw_gen_ctrl gen_ctrl = REG_RD(eth, np->eth_inst,
++ rw_gen_ctrl);
++ reg_eth_rw_tr_ctrl tr_ctrl = REG_RD(eth, np->eth_inst,
++ rw_tr_ctrl);
++ if (old_speed == 1000) {
++ gen_ctrl.phy = regk_eth_mii;
++ gen_ctrl.gtxclk_out = regk_eth_no;
++ tr_ctrl.carrier_ext = regk_eth_no;
++ }
++ else {
++ gen_ctrl.phy = regk_eth_gmii;
++ gen_ctrl.gtxclk_out = regk_eth_yes;
++ tr_ctrl.carrier_ext = regk_eth_yes;
++ }
++ REG_WR(eth, np->eth_inst, rw_tr_ctrl, tr_ctrl);
++ REG_WR(eth, np->eth_inst, rw_gen_ctrl, gen_ctrl);
++
++ crisv32_eth_switch_intmem_usage(dev);
++ }
++#endif
++
++ spin_lock_irqsave(&np->leds->led_lock, flags);
++ if ((old_speed != np->current_speed) || !led_initiated) {
++ led_initiated = 1;
++ np->leds->clear_led_timer.data = (unsigned long) dev;
++ if (np->current_speed) {
++ netif_carrier_on(dev);
++ crisv32_set_network_leds(LED_LINK, dev);
++ } else {
++ netif_carrier_off(dev);
++ crisv32_set_network_leds(LED_NOLINK, dev);
++ }
++ }
++ spin_unlock_irqrestore(&np->leds->led_lock, flags);
++
++ /* Reinitialize the timer. */
++ np->speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
++ add_timer(&np->speed_timer);
++
++ spin_unlock(&np->transceiver_lock);
++}
++
++static void
++crisv32_eth_set_speed(struct net_device *dev, unsigned long speed)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ spin_lock(&np->transceiver_lock);
++ if (np->current_speed_selection != speed) {
++ np->current_speed_selection = speed;
++ crisv32_eth_negotiate(dev);
++ }
++ spin_unlock(&np->transceiver_lock);
++}
++
++static void
++crisv32_eth_check_duplex(unsigned long idev)
++{
++ struct net_device *dev = (struct net_device *) idev;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ reg_eth_rw_rec_ctrl rec_ctrl;
++ int old_duplex = np->full_duplex;
++
++ np->transceiver->check_duplex(dev);
++
++ if (old_duplex != np->full_duplex) {
++ /* Duplex changed. */
++ rec_ctrl = (reg_eth_rw_rec_ctrl) REG_RD(eth, np->eth_inst,
++ rw_rec_ctrl);
++ rec_ctrl.duplex = np->full_duplex;
++ REG_WR(eth, np->eth_inst, rw_rec_ctrl, rec_ctrl);
++ }
++
++ /* Reinitialize the timer. */
++ np->duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
++ add_timer(&np->duplex_timer);
++}
++
++static void
++crisv32_eth_set_duplex(struct net_device *dev, enum duplex new_duplex)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ spin_lock(&np->transceiver_lock);
++ if (np->current_duplex != new_duplex) {
++ np->current_duplex = new_duplex;
++ crisv32_eth_negotiate(dev);
++ }
++ spin_unlock(&np->transceiver_lock);
++}
++
++static int
++crisv32_eth_probe_transceiver(struct net_device *dev)
++{
++ unsigned int phyid_high;
++ unsigned int phyid_low;
++ unsigned int oui;
++ struct transceiver_ops *ops = NULL;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ /* Probe MDIO physical address. */
++ for (np->mdio_phy_addr = 0;
++ np->mdio_phy_addr <= 31; np->mdio_phy_addr++) {
++ if (crisv32_eth_get_mdio_reg(dev, MII_BMSR) != 0xffff)
++ break;
++ }
++
++ if (np->mdio_phy_addr == 32)
++ return -ENODEV;
++
++ /* Get manufacturer. */
++ phyid_high = crisv32_eth_get_mdio_reg(dev, MII_PHYSID1);
++ phyid_low = crisv32_eth_get_mdio_reg(dev, MII_PHYSID2);
++
++ oui = (phyid_high << 6) | (phyid_low >> 10);
++
++ for (ops = &transceivers[0]; ops->oui; ops++) {
++ if (ops->oui == oui)
++ break;
++ }
++
++ np->transceiver = ops;
++ return 0;
++}
++
++static void
++generic_check_speed(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MII_ADVERTISE);
++ if ((data & ADVERTISE_100FULL) ||
++ (data & ADVERTISE_100HALF))
++ np->current_speed = 100;
++ else
++ np->current_speed = 10;
++}
++
++static void
++generic_check_duplex(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MII_ADVERTISE);
++ if ((data & ADVERTISE_10FULL) ||
++ (data & ADVERTISE_100FULL))
++ np->full_duplex = 1;
++ else
++ np->full_duplex = 0;
++}
++
++static void
++broadcom_check_speed(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_AUX_CTRL_STATUS_REG);
++ np->current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
++}
++
++static void
++broadcom_check_duplex(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_AUX_CTRL_STATUS_REG);
++ np->full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
++}
++
++static void
++tdk_check_speed(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_TDK_DIAGNOSTIC_REG);
++ np->current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
++}
++
++static void
++tdk_check_duplex(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_TDK_DIAGNOSTIC_REG);
++ np->full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
++
++}
++
++static void
++intel_check_speed(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_INT_STATUS_REG_2);
++ np->current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
++}
++
++static void
++intel_check_duplex(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_INT_STATUS_REG_2);
++ np->full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;
++}
++
++static void
++national_check_speed(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_NAT_LINK_AN_REG);
++ if (data & MDIO_NAT_1000)
++ np->current_speed = 1000;
++ else if (data & MDIO_NAT_100)
++ np->current_speed = 100;
++ else
++ np->current_speed = 10;
++}
++
++static void
++national_check_duplex(struct net_device *dev)
++{
++ unsigned long data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MDIO_NAT_LINK_AN_REG);
++ if (data & MDIO_NAT_FULL_DUPLEX_IND)
++ np->full_duplex = 1;
++ else
++ np->full_duplex = 0;
++}
++
++static void
++crisv32_eth_reset_tranceiver(struct net_device *dev)
++{
++ int i;
++ unsigned short cmd;
++ unsigned short data;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ data = crisv32_eth_get_mdio_reg(dev, MII_BMCR);
++
++ cmd = (MDIO_START << 14)
++ | (MDIO_WRITE << 12)
++ | (np->mdio_phy_addr << 7)
++ | (MII_BMCR << 2);
++
++ crisv32_eth_send_mdio_cmd(dev, cmd, 1);
++
++ data |= 0x8000;
++
++ /* Magic value is number of bits. */
++ for (i = 15; i >= 0; i--)
++ crisv32_eth_send_mdio_bit(dev, GET_BIT(i, data));
++}
++
++static unsigned short
++crisv32_eth_get_mdio_reg(struct net_device *dev, unsigned char reg_num)
++{
++ int i;
++ unsigned short cmd; /* Data to be sent on MDIO port. */
++ unsigned short data; /* Data read from MDIO. */
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ /* Start of frame, OP Code, Physical Address, Register Address. */
++ cmd = (MDIO_START << 14)
++ | (MDIO_READ << 12)
++ | (np->mdio_phy_addr << 7)
++ | (reg_num << 2);
++
++ crisv32_eth_send_mdio_cmd(dev, cmd, 0);
++
++ data = 0;
++
++ /* Receive data. Magic value is number of bits. */
++ for (i = 15; i >= 0; i--)
++ data |= (crisv32_eth_receive_mdio_bit(dev) << i);
++
++ return data;
++}
++
++static void
++crisv32_eth_set_mdio_reg(struct net_device *dev, unsigned char reg, int value)
++{
++ int bitCounter;
++ unsigned short cmd;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ cmd = (MDIO_START << 14)
++ | (MDIO_WRITE << 12)
++ | (np->mdio_phy_addr << 7)
++ | (reg << 2);
++
++ crisv32_eth_send_mdio_cmd(dev, cmd, 1);
++
++ /* Data... */
++ for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
++ crisv32_eth_send_mdio_bit(dev, GET_BIT(bitCounter, value));
++ }
++}
++
++static void
++crisv32_eth_send_mdio_cmd(struct net_device *dev, unsigned short cmd,
++ int write_cmd)
++{
++ int i;
++ unsigned char data = 0x2;
++
++ /* Preamble. Magic value is number of bits. */
++ for (i = 31; i >= 0; i--)
++ crisv32_eth_send_mdio_bit(dev, GET_BIT(i, MDIO_PREAMBLE));
++
++ for (i = 15; i >= 2; i--)
++ crisv32_eth_send_mdio_bit(dev, GET_BIT(i, cmd));
++
++ /* Turnaround. */
++ for (i = 1; i >= 0; i--)
++ if (write_cmd)
++ crisv32_eth_send_mdio_bit(dev, GET_BIT(i, data));
++ else
++ crisv32_eth_receive_mdio_bit(dev);
++}
++
++static void
++crisv32_eth_send_mdio_bit(struct net_device *dev, unsigned char bit)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ reg_eth_rw_mgm_ctrl mgm_ctrl = {
++ .mdoe = regk_eth_yes,
++ .mdio = bit & 1
++ };
++
++ REG_WR(eth, np->eth_inst, rw_mgm_ctrl, mgm_ctrl);
++
++ udelay(1);
++
++ mgm_ctrl.mdc = 1;
++ REG_WR(eth, np->eth_inst, rw_mgm_ctrl, mgm_ctrl);
++
++ udelay(1);
++}
++
++static unsigned char
++crisv32_eth_receive_mdio_bit(struct net_device *dev)
++{
++ reg_eth_r_stat stat;
++ reg_eth_rw_mgm_ctrl mgm_ctrl = {0};
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++
++ REG_WR(eth, np->eth_inst, rw_mgm_ctrl, mgm_ctrl);
++ stat = REG_RD(eth, np->eth_inst, r_stat);
++
++ udelay(1);
++
++ mgm_ctrl.mdc = 1;
++ REG_WR(eth, np->eth_inst, rw_mgm_ctrl, mgm_ctrl);
++
++ udelay(1);
++ return stat.mdio;
++}
++
++static void
++crisv32_clear_network_leds(unsigned long priv)
++{
++ struct net_device *dev = (struct net_device*)priv;
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&np->leds->led_lock, flags);
++ if (np->leds->led_active && time_after(jiffies, np->leds->led_next_time)) {
++ crisv32_set_network_leds(LED_NOACTIVITY, dev);
++
++ /* Set the earliest time we may set the LED */
++ np->leds->led_next_time = jiffies + NET_FLASH_PAUSE;
++ np->leds->led_active = 0;
++ }
++ spin_unlock_irqrestore(&np->leds->led_lock, flags);
++}
++
++static void
++crisv32_set_network_leds(int active, struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ int light_leds = 0;
++
++ if (np->leds->ledgrp == LED_GRP_NONE)
++ return;
++
++ if (active == LED_NOLINK) {
++ if (dev == crisv32_dev[0])
++ np->leds->ifisup[0] = 0;
++ else
++ np->leds->ifisup[1] = 0;
++ }
++ else if (active == LED_LINK) {
++ if (dev == crisv32_dev[0])
++ np->leds->ifisup[0] = 1;
++ else
++ np->leds->ifisup[1] = 1;
++#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
++ light_leds = 1;
++ } else {
++ light_leds = (active == LED_NOACTIVITY);
++#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
++ light_leds = 0;
++ } else {
++ light_leds = (active == LED_ACTIVITY);
++#else
++#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
++#endif
++ }
++
++ if (!use_network_leds) {
++ NET_LED_SET(np->leds->ledgrp,LED_OFF);
++ return;
++ }
++
++ if (!np->current_speed) {
++ /* Set link down if none of the interfaces that use this led group is up */
++ if ((np->leds->ifisup[0] + np->leds->ifisup[1]) == 0) {
++#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
++ /* Make LED red, link is down */
++ NET_LED_SET(np->leds->ledgrp,LED_RED);
++#else
++ NET_LED_SET(np->leds->ledgrp,LED_OFF);
++#endif
++ }
++ }
++ else if (light_leds) {
++ if (np->current_speed == 10) {
++ NET_LED_SET(np->leds->ledgrp,LED_ORANGE);
++ } else {
++ NET_LED_SET(np->leds->ledgrp,LED_GREEN);
++ }
++ }
++ else {
++ NET_LED_SET(np->leds->ledgrp,LED_OFF);
++ }
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void
++crisv32_netpoll(struct net_device* netdev)
++{
++ crisv32rx_eth_interrupt(DMA0_INTR_VECT, netdev, NULL);
++}
++#endif
++
++#ifdef CONFIG_CPU_FREQ
++static int
++crisv32_ethernet_freq_notifier(struct notifier_block *nb,
++ unsigned long val, void *data)
++{
++ struct cpufreq_freqs *freqs = data;
++ if (val == CPUFREQ_POSTCHANGE) {
++ int i;
++ for (i = 0; i < 2; i++) {
++ struct net_device* dev = crisv32_dev[i];
++ unsigned short data;
++ if (dev == NULL)
++ continue;
++
++ data = crisv32_eth_get_mdio_reg(dev, MII_BMCR);
++ if (freqs->new == 200000)
++ data &= ~BMCR_PDOWN;
++ else
++ data |= BMCR_PDOWN;
++ crisv32_eth_set_mdio_reg(dev, MII_BMCR, data);
++ }
++ }
++ return 0;
++}
++#endif
++
++/*
++ * Must be called with the np->lock held.
++ */
++static void crisv32_ethernet_bug(struct net_device *dev)
++{
++ struct crisv32_ethernet_local *np = netdev_priv(dev);
++ dma_descr_data *dma_pos;
++ dma_descr_data *in_dma_pos;
++ reg_dma_rw_stat stat = {0};
++ reg_dma_rw_stat in_stat = {0};
++ int i;
++
++ /* Get the current output dma position. */
++ stat = REG_RD(dma, np->dma_out_inst, rw_stat);
++ dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_out_inst, rw_data));
++ in_stat = REG_RD(dma, np->dma_in_inst, rw_stat);
++ in_dma_pos = phys_to_virt(REG_RD_INT(dma, np->dma_in_inst, rw_data));
++
++ printk("%s:\n"
++ "stat.list_state=%x\n"
++ "stat.mode=%x\n"
++ "stat.stream_cmd_src=%x\n"
++ "dma_pos=%x\n"
++ "in_stat.list_state=%x\n"
++ "in_stat.mode=%x\n"
++ "in_stat.stream_cmd_src=%x\n"
++ "in_dma_pos=%x\n"
++ "catch=%x active=%x\n"
++ "packets=%d queue=%d\n"
++ "intr_vect.r_vect=%x\n"
++ "dma.r_masked_intr=%x dma.rw_ack_intr=%x "
++ "dma.r_intr=%x dma.rw_intr_masked=%x\n"
++ "eth.r_stat=%x\n",
++ __func__,
++ stat.list_state, stat.mode, stat.stream_cmd_src,
++ (unsigned int)dma_pos,
++ in_stat.list_state, in_stat.mode, in_stat.stream_cmd_src,
++ (unsigned int)in_dma_pos,
++ (unsigned int)&np->catch_tx_desc->descr,
++ (unsigned int)&np->active_tx_desc->descr,
++ np->txpackets,
++ netif_queue_stopped(dev),
++ REG_RD_INT(intr_vect, regi_irq, r_vect),
++ REG_RD_INT(dma, np->dma_out_inst, r_masked_intr),
++ REG_RD_INT(dma, np->dma_out_inst, rw_ack_intr),
++ REG_RD_INT(dma, np->dma_out_inst, r_intr),
++ REG_RD_INT(dma, np->dma_out_inst, rw_intr_mask),
++ REG_RD_INT(eth, np->eth_inst, r_stat));
++
++ printk("tx-descriptors:\n");
++ for (i = 0; i < NBR_TX_DESC; i++) {
++ printk("txdesc[%d]=0x%x\n", i, (unsigned int)
++ virt_to_phys(&np->dma_tx_descr_list[i].descr));
++ printk("txdesc[%d].skb=0x%x\n", i,
++ (unsigned int)np->dma_tx_descr_list[i].skb);
++ printk("txdesc[%d].buf=0x%x\n", i,
++ (unsigned int)np->dma_tx_descr_list[i].descr.buf);
++ printk("txdesc[%d].after=0x%x\n", i,
++ (unsigned int)np->dma_tx_descr_list[i].descr.after);
++ printk("txdesc[%d].intr=%x\n", i,
++ np->dma_tx_descr_list[i].descr.intr);
++ printk("txdesc[%d].eol=%x\n", i,
++ np->dma_tx_descr_list[i].descr.eol);
++ printk("txdesc[%d].out_eop=%x\n", i,
++ np->dma_tx_descr_list[i].descr.out_eop);
++ printk("txdesc[%d].wait=%x\n", i,
++ np->dma_tx_descr_list[i].descr.wait);
++ }
++}
++
++
++static int
++crisv32_init_module(void)
++{
++ return crisv32_ethernet_init();
++}
++
++module_init(crisv32_init_module);
+diff -urN linux-2.6.19.2.orig/drivers/net/cris/eth_v32.h linux-2.6.19.2.dev/drivers/net/cris/eth_v32.h
+--- linux-2.6.19.2.orig/drivers/net/cris/eth_v32.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19.2.dev/drivers/net/cris/eth_v32.h 2007-02-06 11:10:37.000000000 +0100
+@@ -0,0 +1,248 @@
++/*
++ * Definitions for ETRAX FS ethernet driver.
++ *
++ * Copyright (C) 2003, 2004, 2005 Axis Communications.
++ */
++
++#ifndef _ETRAX_ETHERNET_H_
++#define _ETRAX_ETHERNET_H_
++
++#include <asm/arch/hwregs/dma.h>
++
++
++#define MAX_MEDIA_DATA_SIZE 1522 /* Max packet size. */
++
++#define NBR_RX_DESC 64 /* Number of RX descriptors. */
++#define NBR_TX_DESC 16 /* Number of TX descriptors. */
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++#define NBR_INTMEM_RX_DESC 5 /* Number of RX descriptors in int. mem.
++ * when running in gigabit mode.
++ * Should be less then NBR_RX_DESC
++ */
++#define NBR_INTMEM_TX_BUF 4 /* Number of TX buffers in int. mem
++ * when running in gigabit mode.
++ * Should be less than NBR_TX_DESC
++ */
++#endif
++
++/* 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)
++
++#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 ( 0x0001 << 9 )
++#define MDIO_INT_SPEED ( 0x0001 << 14 )
++
++/*National Semiconductor DP83865 specific*/
++#define MDIO_NAT_LINK_AN_REG 0x11
++#define MDIO_NAT_1000 (0x0001 << 4)
++#define MDIO_NAT_100 (0x0001 << 3)
++#define MDIO_NAT_FULL_DUPLEX_IND (0x0001 << 1)
++
++/* 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 seconds. */
++#define NET_DUPLEX_CHECK_INTERVAL (2*HZ) /* 2 seconds. */
++
++/* Duplex settings. */
++enum duplex {
++ half,
++ full,
++ autoneg
++};
++
++/* 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);
++};
++
++typedef struct crisv32_eth_descr {
++ dma_descr_data descr __attribute__ ((__aligned__(32)));
++ struct sk_buff *skb;
++ unsigned char *linearized_packet;
++} crisv32_eth_descr;
++
++
++
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++struct tx_buffer_list {
++ struct tx_buffer_list *next;
++ unsigned char *buf;
++ char free;
++};
++#endif
++
++/* LED stuff */
++#define LED_GRP_0 0
++#define LED_GRP_1 1
++#define LED_GRP_NONE 2
++
++#define LED_ACTIVITY 0
++#define LED_NOACTIVITY 1
++#define LED_LINK 2
++#define LED_NOLINK 3
++
++struct crisv32_eth_leds {
++ unsigned int ledgrp;
++ int led_active;
++ unsigned long led_next_time;
++ struct timer_list clear_led_timer;
++ spinlock_t led_lock; /* Protect LED state */
++ int ifisup[2];
++};
++
++#define NET_LED_SET(x,y) \
++ do { \
++ if (x == 0) LED_NETWORK_GRP0_SET(y); \
++ if (x == 1) LED_NETWORK_GRP1_SET(y); \
++ } while (0)
++
++/* Information that need to be kept for each device. */
++struct crisv32_ethernet_local {
++ dma_descr_context ctxt_in __attribute__ ((__aligned__(32)));
++ dma_descr_context ctxt_out __attribute__ ((__aligned__(32)));
++
++ crisv32_eth_descr *active_rx_desc;
++ crisv32_eth_descr *prev_rx_desc;
++ crisv32_eth_descr *last_rx_desc;
++
++ crisv32_eth_descr *active_tx_desc;
++ crisv32_eth_descr *prev_tx_desc;
++ crisv32_eth_descr *catch_tx_desc;
++
++ crisv32_eth_descr dma_rx_descr_list[NBR_RX_DESC];
++ crisv32_eth_descr dma_tx_descr_list[NBR_TX_DESC];
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++ struct tx_buffer_list tx_intmem_buf_list[NBR_INTMEM_TX_BUF];
++ struct tx_buffer_list *intmem_tx_buf_active;
++ struct tx_buffer_list *intmem_tx_buf_catch;
++ char gigabit_mode;
++#endif
++ char new_rx_package;
++
++ /* DMA and ethernet registers for the device. */
++ int eth_inst;
++ int dma_in_inst;
++ int dma_out_inst;
++
++ /* Network speed indication. */
++ struct timer_list speed_timer;
++ int current_speed; /* Speed read from tranceiver */
++ int current_speed_selection; /* Speed selected by user */
++ int sender_started;
++ int txpackets;
++
++ struct crisv32_eth_leds *leds;
++
++ /* Duplex. */
++ struct timer_list duplex_timer;
++ int full_duplex;
++ enum duplex current_duplex;
++
++ struct net_device_stats stats;
++
++ /* Transciever address. */
++ unsigned int mdio_phy_addr;
++
++ struct transceiver_ops *transceiver;
++
++ /*
++ * 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;
++ spinlock_t transceiver_lock; /* Protect transceiver state. */
++};
++
++/* Function prototypes. */
++static int crisv32_ethernet_init(void);
++static int crisv32_ethernet_device_init(struct net_device* dev);
++static int crisv32_eth_open(struct net_device *dev);
++static int crisv32_eth_close(struct net_device *dev);
++static int crisv32_eth_set_mac_address(struct net_device *dev, void *vpntr);
++static irqreturn_t crisv32rx_eth_interrupt(int irq, void *dev_id);
++static irqreturn_t crisv32tx_eth_interrupt(int irq, void *dev_id);
++static irqreturn_t crisv32nw_eth_interrupt(int irq, void *dev_id);
++static void crisv32_eth_receive_packet(struct net_device *dev);
++static int crisv32_eth_send_packet(struct sk_buff *skb, struct net_device *dev);
++static void crisv32_eth_hw_send_packet(unsigned char *buf, int length,
++ void *priv);
++static void crisv32_eth_tx_timeout(struct net_device *dev);
++static void crisv32_eth_set_multicast_list(struct net_device *dev);
++static int crisv32_eth_ioctl(struct net_device *dev, struct ifreq *ifr,
++ int cmd);
++static int crisv32_eth_set_config(struct net_device* dev, struct ifmap* map);
++#ifdef CONFIG_CRIS_MACH_ARTPEC3
++static void crisv32_eth_switch_intmem_usage(struct net_device *dev);
++#endif
++static void crisv32_eth_negotiate(struct net_device *dev);
++static void crisv32_eth_check_speed(unsigned long idev);
++static void crisv32_eth_set_speed(struct net_device *dev, unsigned long speed);
++static void crisv32_eth_check_duplex(unsigned long idev);
++static void crisv32_eth_set_duplex(struct net_device *dev, enum duplex);
++static int crisv32_eth_probe_transceiver(struct net_device *dev);
++
++static struct ethtool_ops crisv32_ethtool_ops;
++
++static void generic_check_speed(struct net_device *dev);
++static void generic_check_duplex(struct net_device *dev);
++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 national_check_speed(struct net_device* dev);
++static void national_check_duplex(struct net_device *dev);
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void crisv32_netpoll(struct net_device* dev);
++#endif
++
++static void crisv32_clear_network_leds(unsigned long dummy);
++static void crisv32_set_network_leds(int active, struct net_device* dev);
++
++static void crisv32_eth_reset_tranceiver(struct net_device *dev);
++static unsigned short crisv32_eth_get_mdio_reg(struct net_device *dev,
++ unsigned char reg_num);
++static void crisv32_eth_set_mdio_reg(struct net_device *dev,
++ unsigned char reg_num,
++ int val);
++static void crisv32_eth_send_mdio_cmd(struct net_device *dev,
++ unsigned short cmd, int write_cmd);
++static void crisv32_eth_send_mdio_bit(struct net_device *dev,
++ unsigned char bit);
++static unsigned char crisv32_eth_receive_mdio_bit(struct net_device *dev);
++
++static struct net_device_stats *crisv32_get_stats(struct net_device *dev);
++static void crisv32_start_dma_out(struct crisv32_ethernet_local* np);
++
++
++#endif /* _ETRAX_ETHERNET_H_ */