blob: 0eaabeb37ac31ffe82049fa0de91753fa080ad91 [file] [log] [blame]
/*
* usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
*
* Copyright (c) 2002, 2003 Axis Communications AB.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/arch/svinto.h>
#include <linux/usb.h>
/* Ugly include because we don't live with the other host drivers. */
#include <../drivers/usb/core/hcd.h>
#include <../drivers/usb/core/usb.h>
#include "hc_crisv10.h"
#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
static const char *usb_hcd_version = "$Revision: 1.2 $";
#undef KERN_DEBUG
#define KERN_DEBUG ""
#undef USB_DEBUG_RH
#undef USB_DEBUG_EPID
#undef USB_DEBUG_SB
#undef USB_DEBUG_DESC
#undef USB_DEBUG_URB
#undef USB_DEBUG_TRACE
#undef USB_DEBUG_BULK
#undef USB_DEBUG_CTRL
#undef USB_DEBUG_INTR
#undef USB_DEBUG_ISOC
#ifdef USB_DEBUG_RH
#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
#else
#define dbg_rh(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_EPID
#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)
#else
#define dbg_epid(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_SB
#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)
#else
#define dbg_sb(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_CTRL
#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
#else
#define dbg_ctrl(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_BULK
#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
#else
#define dbg_bulk(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_INTR
#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
#else
#define dbg_intr(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_ISOC
#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)
#else
#define dbg_isoc(format, arg...) do {} while (0)
#endif
#ifdef USB_DEBUG_TRACE
#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
#define DBFEXIT (printk(": Exiting: %s\n", __FUNCTION__))
#else
#define DBFENTER do {} while (0)
#define DBFEXIT do {} while (0)
#endif
#define usb_pipeslow(pipe) (((pipe) >> 26) & 1)
/*-------------------------------------------------------------------
Virtual Root Hub
-------------------------------------------------------------------*/
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x00, /* __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); \
} \
}
*/
/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?
To adjust it dynamically we would have to get an interrupt when we reach the end
of the rx descriptor list, or when we get close to the end, and then allocate more
descriptors. */
#define NBR_OF_RX_DESC 512
#define RX_DESC_BUF_SIZE 1024
#define RX_BUF_SIZE (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
/* The number of epids is, among other things, used for pre-allocating
ctrl, bulk and isoc EP descriptors (one for each epid).
Assumed to be > 1 when initiating the DMA lists. */
#define NBR_OF_EPIDS 32
/* Support interrupt traffic intervals up to 128 ms. */
#define MAX_INTR_INTERVAL 128
/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table
must be "invalid". By this we mean that we shouldn't care about epid attentions
for this epid, or at least handle them differently from epid attentions for "valid"
epids. This define determines which one to use (don't change it). */
#define INVALID_EPID 31
/* A special epid for the bulk dummys. */
#define DUMMY_EPID 30
/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */
static __u32 epid_usage_bitmask;
/* A bitfield to keep information on in/out traffic is needed to uniquely identify
an endpoint on a device, since the most significant bit which indicates traffic
direction is lacking in the ep_id field (ETRAX epids can handle both in and
out traffic on endpoints that are otherwise identical). The USB framework, however,
relies on them to be handled separately. For example, bulk IN and OUT urbs cannot
be queued in the same list, since they would block each other. */
static __u32 epid_out_traffic;
/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */
static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
/* Pointers into RxDescList. */
static volatile USB_IN_Desc_t *myNextRxDesc;
static volatile USB_IN_Desc_t *myLastRxDesc;
static volatile USB_IN_Desc_t *myPrevRxDesc;
/* EP descriptors must be 32-bit aligned. */
static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,
causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
in each frame. */
static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));
static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting
this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0
results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point
it to this buffer. */
static int zout_buffer[4] __attribute__ ((aligned (4)));
/* Cache for allocating new EP and SB descriptors. */
static kmem_cache_t *usb_desc_cache;
/* Cache for the registers allocated in the top half. */
static kmem_cache_t *top_half_reg_cache;
/* Cache for the data allocated in the isoc descr top half. */
static kmem_cache_t *isoc_compl_cache;
static struct usb_bus *etrax_usb_bus;
/* This is a circular (double-linked) list of the active urbs for each epid.
The head is never removed, and new urbs are linked onto the list as
urb_entry_t elements. Don't reference urb_list directly; use the wrapper
functions instead. Note that working with these lists might require spinlock
protection. */
static struct list_head urb_list[NBR_OF_EPIDS];
/* Read about the need and usage of this lock in submit_ctrl_urb. */
static spinlock_t urb_list_lock;
/* Used when unlinking asynchronously. */
static struct list_head urb_unlink_list;
/* for returning string descriptors in UTF-16LE */
static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
{
int retval;
for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
*utf++ = *ascii++ & 0x7f;
*utf++ = 0;
}
return retval;
}
static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
{
char buf [30];
// assert (len > (2 * (sizeof (buf) + 1)));
// assert (strlen (type) <= 8);
// language ids
if (id == 0) {
*data++ = 4; *data++ = 3; /* 4 bytes data */
*data++ = 0; *data++ = 0; /* some language id */
return 4;
// serial number
} else if (id == 1) {
sprintf (buf, "%x", serial);
// product description
} else if (id == 2) {
sprintf (buf, "USB %s Root Hub", type);
// id 3 == vendor description
// unsupported IDs --> "stall"
} else
return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
data [1] = 3;
return data [0];
}
/* Wrappers around the list functions (include/linux/list.h). */
static inline int urb_list_empty(int epid)
{
return list_empty(&urb_list[epid]);
}
/* Returns first urb for this epid, or NULL if list is empty. */
static inline struct urb *urb_list_first(int epid)
{
struct urb *first_urb = 0;
if (!urb_list_empty(epid)) {
/* Get the first urb (i.e. head->next). */
urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
first_urb = urb_entry->urb;
}
return first_urb;
}
/* Adds an urb_entry last in the list for this epid. */
static inline void urb_list_add(struct urb *urb, int epid)
{
urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
assert(urb_entry);
urb_entry->urb = urb;
list_add_tail(&urb_entry->list, &urb_list[epid]);
}
/* Search through the list for an element that contains this urb. (The list
is expected to be short and the one we are about to delete will often be
the first in the list.) */
static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid)
{
struct list_head *entry;
struct list_head *tmp;
urb_entry_t *urb_entry;
list_for_each_safe(entry, tmp, &urb_list[epid]) {
urb_entry = list_entry(entry, urb_entry_t, list);
assert(urb_entry);
assert(urb_entry->urb);
if (urb_entry->urb == urb) {
return urb_entry;
}
}
return 0;
}
/* Delete an urb from the list. */
static inline void urb_list_del(struct urb *urb, int epid)
{
urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
assert(urb_entry);
/* Delete entry and free. */
list_del(&urb_entry->list);
kfree(urb_entry);
}
/* Move an urb to the end of the list. */
static inline void urb_list_move_last(struct urb *urb, int epid)
{
urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
assert(urb_entry);
list_del(&urb_entry->list);
list_add_tail(&urb_entry->list, &urb_list[epid]);
}
/* Get the next urb in the list. */
static inline struct urb *urb_list_next(struct urb *urb, int epid)
{
urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
assert(urb_entry);
if (urb_entry->list.next != &urb_list[epid]) {
struct list_head *elem = urb_entry->list.next;
urb_entry = list_entry(elem, urb_entry_t, list);
return urb_entry->urb;
} else {
return NULL;
}
}
/* For debug purposes only. */
static inline void urb_list_dump(int epid)
{
struct list_head *entry;
struct list_head *tmp;
urb_entry_t *urb_entry;
int i = 0;
info("Dumping urb list for epid %d", epid);
list_for_each_safe(entry, tmp, &urb_list[epid]) {
urb_entry = list_entry(entry, urb_entry_t, list);
info(" entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb);
}
}
static void init_rx_buffers(void);
static int etrax_rh_unlink_urb(struct urb *urb);
static void etrax_rh_send_irq(struct urb *urb);
static void etrax_rh_init_int_timer(struct urb *urb);
static void etrax_rh_int_timer_do(unsigned long ptr);
static int etrax_usb_setup_epid(struct urb *urb);
static int etrax_usb_lookup_epid(struct urb *urb);
static int etrax_usb_allocate_epid(void);
static void etrax_usb_free_epid(int epid);
static int etrax_remove_from_sb_list(struct urb *urb);
static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size,
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, struct pt_regs *regs);
static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
static void etrax_usb_hc_interrupt_bottom_half(void *data);
static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
/* The following is a list of interrupt handlers for the host controller interrupts we use.
They are called from etrax_usb_hc_interrupt_bottom_half. */
static void etrax_usb_hc_isoc_eof_interrupt(void);
static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);
static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);
static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);
static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);
static int etrax_rh_submit_urb (struct urb *urb);
/* Forward declaration needed because they are used in the rx interrupt routine. */
static void etrax_usb_complete_urb(struct urb *urb, int status);
static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);
static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);
static void etrax_usb_complete_intr_urb(struct urb *urb, int status);
static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);
static int etrax_usb_hc_init(void);
static void etrax_usb_hc_cleanup(void);
static struct usb_operations etrax_usb_device_operations =
{
.get_frame_number = etrax_usb_get_frame_number,
.submit_urb = etrax_usb_submit_urb,
.unlink_urb = etrax_usb_unlink_urb,
.buffer_alloc = etrax_usb_buffer_alloc,
.buffer_free = etrax_usb_buffer_free
};
/* Note that these functions are always available in their "__" variants, for use in
error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/
USB_DEBUG_URB macros. */
static void __dump_urb(struct urb* purb)
{
printk("\nurb :0x%08lx\n", (unsigned long)purb);
printk("dev :0x%08lx\n", (unsigned long)purb->dev);
printk("pipe :0x%08x\n", purb->pipe);
printk("status :%d\n", purb->status);
printk("transfer_flags :0x%08x\n", purb->transfer_flags);
printk("transfer_buffer :0x%08lx\n", (unsigned long)purb->transfer_buffer);
printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
printk("actual_length :%d\n", purb->actual_length);
printk("setup_packet :0x%08lx\n", (unsigned long)purb->setup_packet);
printk("start_frame :%d\n", purb->start_frame);
printk("number_of_packets :%d\n", purb->number_of_packets);
printk("interval :%d\n", purb->interval);
printk("error_count :%d\n", purb->error_count);
printk("context :0x%08lx\n", (unsigned long)purb->context);
printk("complete :0x%08lx\n\n", (unsigned long)purb->complete);
}
static void __dump_in_desc(volatile USB_IN_Desc_t *in)
{
printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
printk(" sw_len : 0x%04x (%d)\n", in->sw_len, in->sw_len);
printk(" command : 0x%04x\n", in->command);
printk(" next : 0x%08lx\n", in->next);
printk(" buf : 0x%08lx\n", in->buf);
printk(" hw_len : 0x%04x (%d)\n", in->hw_len, in->hw_len);
printk(" status : 0x%04x\n\n", in->status);
}
static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
{
char tt = (sb->command & 0x30) >> 4;
char *tt_string;
switch (tt) {
case 0:
tt_string = "zout";
break;
case 1:
tt_string = "in";
break;
case 2:
tt_string = "out";
break;
case 3:
tt_string = "setup";
break;
default:
tt_string = "unknown (weird)";
}
printk("\n USB_SB_Desc at 0x%08lx\n", (unsigned long)sb);
printk(" command : 0x%04x\n", sb->command);
printk(" rem : %d\n", (sb->command & 0x3f00) >> 8);
printk(" full : %d\n", (sb->command & 0x40) >> 6);
printk(" tt : %d (%s)\n", tt, tt_string);
printk(" intr : %d\n", (sb->command & 0x8) >> 3);
printk(" eot : %d\n", (sb->command & 0x2) >> 1);
printk(" eol : %d\n", sb->command & 0x1);
printk(" sw_len : 0x%04x (%d)\n", sb->sw_len, sb->sw_len);
printk(" next : 0x%08lx\n", sb->next);
printk(" buf : 0x%08lx\n\n", sb->buf);
}
static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
{
printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep);
printk(" command : 0x%04x\n", ep->command);
printk(" ep_id : %d\n", (ep->command & 0x1f00) >> 8);
printk(" enable : %d\n", (ep->command & 0x10) >> 4);
printk(" intr : %d\n", (ep->command & 0x8) >> 3);
printk(" eof : %d\n", (ep->command & 0x2) >> 1);
printk(" eol : %d\n", ep->command & 0x1);
printk(" hw_len : 0x%04x (%d)\n", ep->hw_len, ep->hw_len);
printk(" next : 0x%08lx\n", ep->next);
printk(" sub : 0x%08lx\n\n", ep->sub);
}
static inline void __dump_ep_list(int pipe_type)
{
volatile USB_EP_Desc_t *ep;
volatile USB_EP_Desc_t *first_ep;
volatile USB_SB_Desc_t *sb;
switch (pipe_type)
{
case PIPE_BULK:
first_ep = &TxBulkEPList[0];
break;
case PIPE_CONTROL:
first_ep = &TxCtrlEPList[0];
break;
case PIPE_INTERRUPT:
first_ep = &TxIntrEPList[0];
break;
case PIPE_ISOCHRONOUS:
first_ep = &TxIsocEPList[0];
break;
default:
warn("Cannot dump unknown traffic type");
return;
}
ep = first_ep;
printk("\n\nDumping EP list...\n\n");
do {
__dump_ep_desc(ep);
/* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
sb = ep->sub ? phys_to_virt(ep->sub) : 0;
while (sb) {
__dump_sb_desc(sb);
sb = sb->next ? phys_to_virt(sb->next) : 0;
}
ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next));
} while (ep != first_ep);
}
static inline void __dump_ept_data(int epid)
{
unsigned long flags;
__u32 r_usb_ept_data;
if (epid < 0 || epid > 31) {
printk("Cannot dump ept data for invalid epid %d\n", epid);
return;
}
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
r_usb_ept_data = *R_USB_EPT_DATA;
restore_flags(flags);
printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
if (r_usb_ept_data == 0) {
/* No need for more detailed printing. */
return;
}
printk(" valid : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
printk(" hold : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
printk(" error_count_in : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
printk(" t_in : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
printk(" low_speed : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
printk(" port : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
printk(" error_code : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
printk(" t_out : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
printk(" error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
printk(" max_len : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
printk(" ep : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
printk(" dev : %d\n", (r_usb_ept_data & 0x0000003f));
}
static inline void __dump_ept_data_list(void)
{
int i;
printk("Dumping the whole R_USB_EPT_DATA list\n");
for (i = 0; i < 32; i++) {
__dump_ept_data(i);
}
}
#ifdef USB_DEBUG_DESC
#define dump_in_desc(...) __dump_in_desc(...)
#define dump_sb_desc(...) __dump_sb_desc(...)
#define dump_ep_desc(...) __dump_ep_desc(...)
#else
#define dump_in_desc(...) do {} while (0)
#define dump_sb_desc(...) do {} while (0)
#define dump_ep_desc(...) do {} while (0)
#endif
#ifdef USB_DEBUG_URB
#define dump_urb(x) __dump_urb(x)
#else
#define dump_urb(x) do {} while (0)
#endif
static void init_rx_buffers(void)
{
int i;
DBFENTER;
for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
RxDescList[i].command = 0;
RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
RxDescList[i].hw_len = 0;
RxDescList[i].status = 0;
/* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc
for the relevant fields.) */
prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
}
RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
RxDescList[i].next = virt_to_phys(&RxDescList[0]);
RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
RxDescList[i].hw_len = 0;
RxDescList[i].status = 0;
myNextRxDesc = &RxDescList[0];
myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
*R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
DBFEXIT;
}
static void init_tx_bulk_ep(void)
{
int i;
DBFENTER;
for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
CHECK_ALIGN(&TxBulkEPList[i]);
TxBulkEPList[i].hw_len = 0;
TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
TxBulkEPList[i].sub = 0;
TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]);
/* Initiate two EPs, disabled and with the eol flag set. No need for any
preserved epid. */
/* The first one has the intr flag set so we get an interrupt when the DMA
channel is about to become disabled. */
CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
TxBulkDummyEPList[i][0].hw_len = 0;
TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
IO_STATE(USB_EP_command, eol, yes) |
IO_STATE(USB_EP_command, intr, yes));
TxBulkDummyEPList[i][0].sub = 0;
TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
/* The second one. */
CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
TxBulkDummyEPList[i][1].hw_len = 0;
TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
IO_STATE(USB_EP_command, eol, yes));
TxBulkDummyEPList[i][1].sub = 0;
/* The last dummy's next pointer is the same as the current EP's next pointer. */
TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
}
/* Configure the last one. */
CHECK_ALIGN(&TxBulkEPList[i]);
TxBulkEPList[i].hw_len = 0;
TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
IO_FIELD(USB_EP_command, epid, i));
TxBulkEPList[i].sub = 0;
TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]);
/* No need configuring dummy EPs for the last one as it will never be used for
bulk traffic (i == INVALD_EPID at this point). */
/* Set up to start on the last EP so we will enable it when inserting traffic
for the first time (imitating the situation where the DMA has stopped
because there was no more traffic). */
*R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
/* No point in starting the bulk channel yet.
*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
DBFEXIT;
}
static void init_tx_ctrl_ep(void)
{
int i;
DBFENTER;
for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
CHECK_ALIGN(&TxCtrlEPList[i]);
TxCtrlEPList[i].hw_len = 0;
TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
TxCtrlEPList[i].sub = 0;
TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]);
}
CHECK_ALIGN(&TxCtrlEPList[i]);
TxCtrlEPList[i].hw_len = 0;
TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
IO_FIELD(USB_EP_command, epid, i));
TxCtrlEPList[i].sub = 0;
TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
*R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
DBFEXIT;
}
static void init_tx_intr_ep(void)
{
int i;
DBFENTER;
/* Read comment at zout_buffer declaration for an explanation to this. */
TxIntrSB_zout.sw_len = 1;
TxIntrSB_zout.next = 0;
TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
IO_STATE(USB_SB_command, tt, zout) |
IO_STATE(USB_SB_command, full, yes) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, eol, yes));
for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
CHECK_ALIGN(&TxIntrEPList[i]);
TxIntrEPList[i].hw_len = 0;
TxIntrEPList[i].command =
(IO_STATE(USB_EP_command, eof, yes) |
IO_STATE(USB_EP_command, enable, yes) |
IO_FIELD(USB_EP_command, epid, INVALID_EPID));
TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
}
CHECK_ALIGN(&TxIntrEPList[i]);
TxIntrEPList[i].hw_len = 0;
TxIntrEPList[i].command =
(IO_STATE(USB_EP_command, eof, yes) |
IO_STATE(USB_EP_command, eol, yes) |
IO_STATE(USB_EP_command, enable, yes) |
IO_FIELD(USB_EP_command, epid, INVALID_EPID));
TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
DBFEXIT;
}
static void init_tx_isoc_ep(void)
{
int i;
DBFENTER;
/* Read comment at zout_buffer declaration for an explanation to this. */
TxIsocSB_zout.sw_len = 1;
TxIsocSB_zout.next = 0;
TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
IO_STATE(USB_SB_command, tt, zout) |
IO_STATE(USB_SB_command, full, yes) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, eol, yes));
/* The last isochronous EP descriptor is a dummy. */
for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
CHECK_ALIGN(&TxIsocEPList[i]);
TxIsocEPList[i].hw_len = 0;
TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
TxIsocEPList[i].sub = 0;
TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
}
CHECK_ALIGN(&TxIsocEPList[i]);
TxIsocEPList[i].hw_len = 0;
/* Must enable the last EP descr to get eof interrupt. */
TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
IO_STATE(USB_EP_command, eof, yes) |
IO_STATE(USB_EP_command, eol, yes) |
IO_FIELD(USB_EP_command, epid, INVALID_EPID));
TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
*R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
DBFEXIT;
}
static void etrax_usb_unlink_intr_urb(struct urb *urb)
{
volatile USB_EP_Desc_t *first_ep; /* First EP in the list. */
volatile USB_EP_Desc_t *curr_ep; /* Current EP, the iterator. */
volatile USB_EP_Desc_t *next_ep; /* The EP after current. */
volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */
int epid;
/* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */
DBFENTER;
epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;
first_ep = &TxIntrEPList[0];
curr_ep = first_ep;
/* Note that this loop removes all EP descriptors with this epid. This assumes
that all EP descriptors belong to the one and only urb for this epid. */
do {
next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);
if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
dbg_intr("Found EP to unlink for epid %d", epid);
/* This is the one we should unlink. */
unlink_ep = next_ep;
/* Actually unlink the EP from the DMA list. */
curr_ep->next = unlink_ep->next;
/* Wait until the DMA is no longer at this descriptor. */
while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));
/* Now we are free to remove it and its SB descriptor.
Note that it is assumed here that there is only one sb in the
sb list for this ep. */
kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));
kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);
}
curr_ep = phys_to_virt(curr_ep->next);
} while (curr_ep != first_ep);
urb->hcpriv = NULL;
}
void etrax_usb_do_intr_recover(int epid)
{
USB_EP_Desc_t *first_ep, *tmp_ep;
DBFENTER;
first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
tmp_ep = first_ep;
/* What this does is simply to walk the list of interrupt
ep descriptors and enable those that are disabled. */
do {
if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
!(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
}
tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
} while (tmp_ep != first_ep);
DBFEXIT;
}
static int etrax_rh_unlink_urb (struct urb *urb)
{
etrax_hc_t *hc;
DBFENTER;
hc = urb->dev->bus->hcpriv;
if (hc->rh.urb == urb) {
hc->rh.send = 0;
del_timer(&hc->rh.rh_int_timer);
}
DBFEXIT;
return 0;
}
static void etrax_rh_send_irq(struct urb *urb)
{
__u16 data = 0;
etrax_hc_t *hc = urb->dev->bus->hcpriv;
DBFENTER;
/*
dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER);
dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
*/
data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
/* FIXME: Why is actual_length set to 1 when data is 2 bytes?
Since only 1 byte is used, why not declare data as __u8? */
urb->actual_length = 1;
urb->status = 0;
if (hc->rh.send && urb->complete) {
dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);
dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
urb->complete(urb, NULL);
}
DBFEXIT;
}
static void etrax_rh_init_int_timer(struct urb *urb)
{
etrax_hc_t *hc;
DBFENTER;
hc = urb->dev->bus->hcpriv;
hc->rh.interval = urb->interval;
init_timer(&hc->rh.rh_int_timer);
hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
hc->rh.rh_int_timer.data = (unsigned long)urb;
/* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped
to 0, and the rest to the nearest lower 10 ms. */
hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
add_timer(&hc->rh.rh_int_timer);
DBFEXIT;
}
static void etrax_rh_int_timer_do(unsigned long ptr)
{
struct urb *urb;
etrax_hc_t *hc;
DBFENTER;
urb = (struct urb*)ptr;
hc = urb->dev->bus->hcpriv;
if (hc->rh.send) {
etrax_rh_send_irq(urb);
}
DBFEXIT;
}
static int etrax_usb_setup_epid(struct urb *urb)
{
int epid;
char devnum, endpoint, out_traffic, slow;
int maxlen;
unsigned long flags;
DBFENTER;
epid = etrax_usb_lookup_epid(urb);
if ((epid != -1)){
/* An epid that fits this urb has been found. */
DBFEXIT;
return epid;
}
/* We must find and initiate a new epid for this urb. */
epid = etrax_usb_allocate_epid();
if (epid == -1) {
/* Failed to allocate a new epid. */
DBFEXIT;
return epid;
}
/* We now have a new epid to use. Initiate it. */
set_bit(epid, (void *)&epid_usage_bitmask);
devnum = usb_pipedevice(urb->pipe);
endpoint = usb_pipeendpoint(urb->pipe);
slow = usb_pipeslow(urb->pipe);
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
out_traffic = 1;
} else {
out_traffic = usb_pipeout(urb->pipe);
}
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
*R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
/* FIXME: Change any to the actual port? */
IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
} else {
*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
/* FIXME: Change any to the actual port? */
IO_STATE(R_USB_EPT_DATA, port, any) |
IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
IO_FIELD(R_USB_EPT_DATA, dev, devnum);
}
restore_flags(flags);
if (out_traffic) {
set_bit(epid, (void *)&epid_out_traffic);
} else {
clear_bit(epid, (void *)&epid_out_traffic);
}
dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",
epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");
DBFEXIT;
return epid;
}
static void etrax_usb_free_epid(int epid)
{
unsigned long flags;
DBFENTER;
if (!test_bit(epid, (void *)&epid_usage_bitmask)) {
warn("Trying to free unused epid %d", epid);
DBFEXIT;
return;
}
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));
/* This will, among other things, set the valid field to 0. */
*R_USB_EPT_DATA = 0;
restore_flags(flags);
clear_bit(epid, (void *)&epid_usage_bitmask);
dbg_epid("Freed epid %d", epid);
DBFEXIT;
}
static int etrax_usb_lookup_epid(struct urb *urb)
{
int i;
__u32 data;
char devnum, endpoint, slow, out_traffic;
int maxlen;
unsigned long flags;
DBFENTER;
devnum = usb_pipedevice(urb->pipe);
endpoint = usb_pipeendpoint(urb->pipe);
slow = usb_pipeslow(urb->pipe);
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
out_traffic = 1;
} else {
out_traffic = usb_pipeout(urb->pipe);
}
/* Step through att epids. */
for (i = 0; i < NBR_OF_EPIDS; i++) {
if (test_bit(i, (void *)&epid_usage_bitmask) &&
test_bit(i, (void *)&epid_out_traffic) == out_traffic) {
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
nop();
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
data = *R_USB_EPT_DATA_ISO;
restore_flags(flags);
if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&
(IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&
(IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&
(IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {
dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
i, devnum, endpoint, out_traffic ? "OUT" : "IN");
DBFEXIT;
return i;
}
} else {
data = *R_USB_EPT_DATA;
restore_flags(flags);
if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
(IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
(IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
(IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
(IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {
dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
i, devnum, endpoint, out_traffic ? "OUT" : "IN");
DBFEXIT;
return i;
}
}
}
}
DBFEXIT;
return -1;
}
static int etrax_usb_allocate_epid(void)
{
int i;
DBFENTER;
for (i = 0; i < NBR_OF_EPIDS; i++) {
if (!test_bit(i, (void *)&epid_usage_bitmask)) {
dbg_epid("Found free epid %d", i);
DBFEXIT;
return i;
}
}
dbg_epid("Found no free epids");
DBFEXIT;
return -1;
}
static int etrax_usb_submit_urb(struct urb *urb, 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, struct pt_regs *regs)
{
DBFENTER;
/* This interrupt handler could be used when unlinking EP descriptors. */
if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
USB_EP_Desc_t *ep;
//dbg_bulk("dma8_sub0_descr (BULK) intr.");
/* It should be safe clearing the interrupt here, since we don't expect to get a new
one until we restart the bulk channel. */
*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
/* Wait while the DMA is running (though we don't expect it to be). */
while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));
/* Advance the DMA to the next EP descriptor. */
ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
//dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);
/* ep->next is already a physical address; no need for a virt_to_phys. */
*R_DMA_CH8_SUB0_EP = ep->next;
/* Start the DMA bulk channel again. */
*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
}
if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
struct urb *urb;
int epid;
etrax_urb_priv_t *urb_priv;
unsigned long int flags;
dbg_ctrl("dma8_sub1_descr (CTRL) intr.");
*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
/* The complete callback gets called so we cli. */
save_flags(flags);
cli();
for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
if ((TxCtrlEPList[epid].sub == 0) ||
(epid == DUMMY_EPID) ||
(epid == INVALID_EPID)) {
/* Nothing here to see. */
continue;
}
/* Get the first urb (if any). */
urb = urb_list_first(epid);
if (urb) {
/* Sanity check. */
assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);
urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
assert(urb_priv);
if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {
assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
etrax_usb_complete_urb(urb, 0);
}
}
}
restore_flags(flags);
}
if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
dbg_intr("dma8_sub2_descr (INTR) intr.");
*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
}
if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
struct urb *urb;
int epid;
int epid_done;
etrax_urb_priv_t *urb_priv;
USB_SB_Desc_t *sb_desc;
usb_isoc_complete_data_t *comp_data = NULL;
/* One or more isoc out transfers are done. */
dbg_isoc("dma8_sub3_descr (ISOC) intr.");
/* For each isoc out EP search for the first sb_desc with the intr flag
set. This descriptor must be the last packet from an URB. Then
traverse the URB list for the EP until the URB with urb_priv->last_sb
matching the intr-marked sb_desc is found. All URBs before this have
been sent.
*/
for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
/* Skip past epids with no SB lists, epids used for in traffic,
and special (dummy, invalid) epids. */
if ((TxIsocEPList[epid].sub == 0) ||
(test_bit(epid, (void *)&epid_out_traffic) == 0) ||
(epid == DUMMY_EPID) ||
(epid == INVALID_EPID)) {
/* Nothing here to see. */
continue;
}
sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
/* Find the last descriptor of the currently active URB for this ep.
This is the first descriptor in the sub list marked for a descriptor
interrupt. */
while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
}
assert(sb_desc);
dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",
epid,
phys_to_virt(TxIsocEPList[epid].sub),
sb_desc);
epid_done = 0;
/* Get the first urb (if any). */
urb = urb_list_first(epid);
assert(urb);
while (urb && !epid_done) {
/* Sanity check. */
assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
if (!usb_pipeout(urb->pipe)) {
/* descr interrupts are generated only for out pipes. */
epid_done = 1;
continue;
}
urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
assert(urb_priv);
if (sb_desc != urb_priv->last_sb) {
/* This urb has been sent. */
dbg_isoc("out URB 0x%p sent", urb);
urb_priv->urb_state = TRANSFER_DONE;
} else if ((sb_desc == urb_priv->last_sb) &&
!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));
assert(sb_desc->next == 0);
dbg_isoc("out URB 0x%p last in list, epid disabled", urb);
TxIsocEPList[epid].sub = 0;
TxIsocEPList[epid].hw_len = 0;
urb_priv->urb_state = TRANSFER_DONE;
epid_done = 1;
} else {
epid_done = 1;
}
if (!epid_done) {
urb = urb_list_next(urb, epid);
}
}
}
*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
assert(comp_data != NULL);
INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);
schedule_work(&comp_data->usb_bh);
}
DBFEXIT;
return IRQ_HANDLED;
}
static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
{
usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;
struct urb *urb;
int epid;
int epid_done;
etrax_urb_priv_t *urb_priv;
DBFENTER;
dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");
for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
unsigned long flags;
save_flags(flags);
cli();
epid_done = 0;
/* The descriptor interrupt handler has marked all transmitted isoch. out
URBs with TRANSFER_DONE. Now we traverse all epids and for all that
have isoch. out traffic traverse its URB list and complete the
transmitted URB.
*/
while (!epid_done) {
/* Get the first urb (if any). */
urb = urb_list_first(epid);
if (urb == 0) {
epid_done = 1;
continue;
}
if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
epid_done = 1;
continue;
}
if (!usb_pipeout(urb->pipe)) {
/* descr interrupts are generated only for out pipes. */
epid_done = 1;
continue;
}
dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);
urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
assert(urb_priv);
if (urb_priv->urb_state == TRANSFER_DONE) {
int i;
struct usb_iso_packet_descriptor *packet;
/* This urb has been sent. */
dbg_isoc("Completing isoc out URB 0x%p", urb);
for (i = 0; i < urb->number_of_packets; i++) {
packet = &urb->iso_frame_desc[i];
packet->status = 0;
packet->actual_length = packet->length;
}
etrax_usb_complete_isoc_urb(urb, 0);
if (urb_list_empty(epid)) {
etrax_usb_free_epid(epid);
epid_done = 1;
}
} else {
epid_done = 1;
}
}
restore_flags(flags);
}
kmem_cache_free(isoc_compl_cache, comp_data);
DBFEXIT;
}
static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
{
struct urb *urb;
etrax_urb_priv_t *urb_priv;
int epid = 0;
unsigned long flags;
/* Isoc diagnostics. */
static int curr_fm = 0;
static int prev_fm = 0;
DBFENTER;
/* Clear this interrupt. */
*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
/* Note that this while loop assumes that all packets span only
one rx descriptor. */
/* The reason we cli here is that we call the driver's callback functions. */
save_flags(flags);
cli();
while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
urb = urb_list_first(epid);
//printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);
if (!urb) {
err("No urb for epid %d in rx interrupt", epid);
__dump_ept_data(epid);
goto skip_out;
}
/* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since
ctrl pipes are not. */
if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
__u32 r_usb_ept_data;
int no_error = 0;
assert(test_bit(epid, (void *)&epid_usage_bitmask));
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
r_usb_ept_data = *R_USB_EPT_DATA_ISO;
if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
(IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
(myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
/* Not an error, just a failure to receive an expected iso
in packet in this frame. This is not documented
in the designers reference.
*/
no_error++;
} else {
warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);
}
} else {
r_usb_ept_data = *R_USB_EPT_DATA;
warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);
}
if (!no_error){
warn("error in rx desc->status, epid %d, first urb = 0x%lx",
epid, (unsigned long)urb);
__dump_in_desc(myNextRxDesc);
warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);
/* Check that ept was disabled when error occurred. */
switch (usb_pipetype(urb->pipe)) {
case PIPE_BULK:
assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
break;
case PIPE_CONTROL:
assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
break;
case PIPE_INTERRUPT:
assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));
break;
case PIPE_ISOCHRONOUS:
assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));
break;
default:
warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",
usb_pipetype(urb->pipe),
urb);
}
etrax_usb_complete_urb(urb, -EPROTO);
goto skip_out;
}
}
urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
assert(urb_priv);
if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
(usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
(usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
/* We get nodata for empty data transactions, and the rx descriptor's
hw_len field is not valid in that case. No data to copy in other
words. */
} else {
/* Make sure the data fits in the buffer. */
assert(urb_priv->rx_offset + myNextRxDesc->hw_len
<= urb->transfer_buffer_length);
memcpy(urb->transfer_buffer + urb_priv->rx_offset,
phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
urb_priv->rx_offset += myNextRxDesc->hw_len;
}
if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&
((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==
IO_STATE(USB_EP_command, enable, yes))) {
/* The EP is still enabled, so the OUT packet used to ack
the in data is probably not processed yet. If the EP
sub pointer has not moved beyond urb_priv->last_sb mark
it for a descriptor interrupt and complete the urb in
the descriptor interrupt handler.
*/
USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;
while ((sub != NULL) && (sub != urb_priv->last_sb)) {
sub = sub->next ? phys_to_virt(sub->next) : 0;
}
if (sub != NULL) {
/* The urb has not been fully processed. */
urb_priv->urb_state = WAITING_FOR_DESCR_INTR;
} else {
warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);
etrax_usb_complete_urb(urb, 0);
}
} else {
etrax_usb_complete_urb(urb, 0);
}
}
} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
struct usb_iso_packet_descriptor *packet;
if (urb_priv->urb_state == UNLINK) {
info("Ignoring rx data for urb being unlinked.");
goto skip_out;
} else if (urb_priv->urb_state == NOT_STARTED) {
info("What? Got rx data for urb that isn't started?");
goto skip_out;
}
packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
packet->status = 0;
if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
/* We get nodata for empty data transactions, and the rx descriptor's
hw_len field is not valid in that case. We copy 0 bytes however to
stay in synch. */
packet->actual_length = 0;
} else {
packet->actual_length = myNextRxDesc->hw_len;
/* Make sure the data fits in the buffer. */
assert(packet->actual_length <= packet->length);
memcpy(urb->transfer_buffer + packet->offset,
phys_to_virt(myNextRxDesc->buf), packet->actual_length);
}
/* Increment the packet counter. */
urb_priv->isoc_packet_counter++;
/* Note that we don't care about the eot field in the rx descriptor's status.
It will always be set for isoc traffic. */
if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
/* Out-of-synch diagnostics. */
curr_fm = (*R_USB_FM_NUMBER & 0x7ff);
if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {
/* This test is wrong, if there is more than one isoc
in endpoint active it will always calculate wrong
since prev_fm is shared by all endpoints.
FIXME Make this check per URB using urb->start_frame.
*/
dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",
prev_fm, curr_fm);
}
prev_fm = curr_fm;
/* Complete the urb with status OK. */
etrax_usb_complete_isoc_urb(urb, 0);
}
}
skip_out:
/* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr
has the same layout as USB_IN_Desc for the relevant fields.) */
prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);
myPrevRxDesc = myNextRxDesc;
myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
myLastRxDesc = myPrevRxDesc;
myNextRxDesc->status = 0;
myNextRxDesc = phys_to_virt(myNextRxDesc->next);
}
restore_flags(flags);
DBFEXIT;
return IRQ_HANDLED;
}
/* This function will unlink the SB descriptors associated with this urb. */
static int etrax_remove_from_sb_list(struct urb *urb)
{
USB_SB_Desc_t *next_sb, *first_sb, *last_sb;
etrax_urb_priv_t *urb_priv;
int i = 0;
DBFENTER;
urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
assert(urb_priv);
/* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor
doesn't really need to be disabled, it's just that we expect it to be. */
if (usb_pipetype(urb->pipe) == PIPE_BULK) {
assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
}
first_sb = urb_priv->first_sb;
last_sb = urb_priv->last_sb;
assert(first_sb);
assert(last_sb);
while (first_sb != last_sb) {
next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);
kmem_cache_free(usb_desc_cache, first_sb);
first_sb = next_sb;
i++;
}
kmem_cache_free(usb_desc_cache, last_sb);
i++;
dbg_sb("%d SB descriptors freed", i);
/* Compare i with urb->number_of_packets for Isoc traffic.
Should be same when calling unlink_urb */
DBFEXIT;
return i;
}
static int etrax_usb_submit_bulk_urb(struct urb *urb)
{
int epid;
int empty;
unsigned long flags;
etrax_urb_priv_t *urb_priv;
DBFENTER;
/* Epid allocation, empty check and list add must be protected.
Read about this in etrax_usb_submit_ctrl_urb. */
spin_lock_irqsave(&urb_list_lock, flags);
epid = etrax_usb_setup_epid(urb);
if (epid == -1) {
DBFEXIT;
spin_unlock_irqrestore(&urb_list_lock, flags);
return -ENOMEM;
}
empty = urb_list_empty(epid);
urb_list_add(urb, epid);
spin_unlock_irqrestore(&urb_list_lock, flags);
dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",
usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);
/* Mark the urb as being in progress. */
urb->status = -EINPROGRESS;
/* Setup the hcpriv data. */
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
assert(urb_priv != NULL);
/* This sets rx_offset to 0. */
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
urb_priv->urb_state = NOT_STARTED;
urb->hcpriv = urb_priv;
if (empty) {
etrax_usb_add_to_bulk_sb_list(urb, epid);
}
DBFEXIT;
return 0;
}
static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
{
USB_SB_Desc_t *sb_desc;
etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
unsigned long flags;
char maxlen;
DBFENTER;
dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
assert(sb_desc != NULL);
memset(sb_desc, 0, sizeof(USB_SB_Desc_t));
if (usb_pipeout(urb->pipe)) {
dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);
/* This is probably a sanity check of the bulk transaction length
not being larger than 64 kB. */
if (urb->transfer_buffer_length > 0xffff) {
panic("urb->transfer_buffer_length > 0xffff");
}
sb_desc->sw_len = urb->transfer_buffer_length;
/* The rem field is don't care if it's not a full-length transfer, so setting
it shouldn't hurt. Also, rem isn't used for OUT traffic. */
sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
IO_STATE(USB_SB_command, tt, out) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, eol, yes));
/* The full field is set to yes, even if we don't actually check that this is
a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).
Setting full prevents the USB controller from sending an empty packet in
that case. However, if URB_ZERO_PACKET was set we want that. */
if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
}
sb_desc->buf = virt_to_phys(urb->transfer_buffer);
sb_desc->next = 0;
} else if (usb_pipein(urb->pipe)) {
dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);
sb_desc->sw_len = urb->transfer_buffer_length ?
(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
/* The rem field is don't care if it's not a full-length transfer, so setting
it shouldn't hurt. */
sb_desc->command =
(IO_FIELD(USB_SB_command, rem,
urb->transfer_buffer_length % maxlen) |
IO_STATE(USB_SB_command, tt, in) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, eol, yes));
sb_desc->buf = 0;
sb_desc->next = 0;
}
urb_priv->first_sb = sb_desc;
urb_priv->last_sb = sb_desc;
urb_priv->epid = epid;
urb->hcpriv = urb_priv;
/* Reset toggle bits and reset error count. */
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
/* FIXME: Is this a special case since the hold field is checked,
or should we check hold in a lot of other cases as well? */
if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
panic("Hold was set in %s", __FUNCTION__);
}
/* Reset error counters (regardless of which direction this traffic is). */
*R_USB_EPT_DATA &=
~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
IO_MASK(R_USB_EPT_DATA, error_count_out));
/* Software must preset the toggle bits. */
if (usb_pipeout(urb->pipe)) {
char toggle =
usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
} else {
char toggle =
usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
}
/* Assert that the EP descriptor is disabled. */
assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
/* The reason we set the EP's sub pointer directly instead of
walking the SB list and linking it last in the list is that we only
have one active urb at a time (the rest are queued). */
/* Note that we cannot have interrupts running when we have set the SB descriptor
but the EP is not yet enabled. If a bulk eot happens for another EP, we will
find this EP disabled and with a SB != 0, which will make us think that it's done. */
TxBulkEPList[epid].sub = virt_to_phys(sb_desc);
TxBulkEPList[epid].hw_len = 0;
/* Note that we don't have to fill in the ep_id field since this
was done when we allocated the EP descriptors in init_tx_bulk_ep. */
/* Check if the dummy list is already with us (if several urbs were queued). */
if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {
dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d",
(unsigned long)urb, epid);
/* The last EP in the dummy list already has its next pointer set to
TxBulkEPList[epid].next. */
/* We don't need to check if the DMA is at this EP or not before changing the
next pointer, since we will do it in one 32-bit write (EP descriptors are
32-bit aligned). */
TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
}
/* Enable the EP descr. */
dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);
TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
/* Everything is set up, safe to enable interrupts again. */
restore_flags(flags);
/* If the DMA bulk channel isn't running, we need to restart it if it
has stopped at the last EP descriptor (DMA stopped because there was
no more traffic) or if it has stopped at a dummy EP with the intr flag
set (DMA stopped because we were too slow in inserting new traffic). */
if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
USB_EP_Desc_t *ep;
ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
dbg_bulk("DMA channel not running in add");
dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);
if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||
(ep->command & 0x8) >> 3) {
*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
/* Update/restart the bulk start timer since we just started the channel. */
mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
/* Update/restart the bulk eot timer since we just inserted traffic. */
mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
}
}
DBFEXIT;
}
static void etrax_usb_complete_bulk_urb(struct urb *urb, int status)
{
etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
int epid = urb_priv->epid;
unsigned long flags;
DBFENTER;
if (status)
warn("Completing bulk urb with status %d.", status);
dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid);
/* Update the urb list. */
urb_list_del(urb, epid);
/* For an IN pipe, we always set the actual length, regardless of whether there was
an error or not (which means the device driver can use the data if it wants to). */
if (usb_pipein(urb->pipe)) {
urb->actual_length = urb_priv->rx_offset;
} else {
/* Set actual_length for OUT urbs also; the USB mass storage driver seems
to want that. We wouldn't know of any partial writes if there was an error. */
if (status == 0) {
urb->actual_length = urb->transfer_buffer_length;
} else {
urb->actual_length = 0;
}
}
/* FIXME: Is there something of the things below we shouldn't do if there was an error?
Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
/* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */
if (usb_pipeout(urb->pipe)) {
char toggle =
IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
} else {
char toggle =
IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
}
restore_flags(flags);
/* Remember to free the SBs. */
etrax_remove_from_sb_list(urb);
kfree(urb_priv);
urb->hcpriv = 0;
/* If there are any more urb's in the list we'd better start sending */
if (!urb_list_empty(epid)) {
struct urb *new_urb;
/* Get the first urb. */
new_urb = urb_list_first(epid);
assert(new_urb);
dbg_bulk("More bulk for epid %d", epid);
etrax_usb_add_to_bulk_sb_list(new_urb, epid);
}
urb->status = status;
/* We let any non-zero status from the layer above have precedence. */
if (status == 0) {
/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
is to be treated as an error. */
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
if (usb_pipein(urb->pipe) &&
(urb->actual_length !=
usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
urb->status = -EREMOTEIO;
}
}
}
if (urb->complete) {
urb->complete(urb, NULL);
}
if (urb_list_empty(epid)) {
/* This means that this EP is now free, deconfigure it. */
etrax_usb_free_epid(epid);
/* No more traffic; time to clean up.
Must set sub pointer to 0, since we look at the sub pointer when handling
the bulk eot interrupt. */
dbg_bulk("No bulk for epid %d", epid);
TxBulkEPList[epid].sub = 0;
/* Unlink the dummy list. */
dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d",
(unsigned long)urb, epid);
/* No need to wait for the DMA before changing the next pointer.
The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
the last one (INVALID_EPID) for actual traffic. */
TxBulkEPList[epid].next =
virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
}
DBFEXIT;
}
static int etrax_usb_submit_ctrl_urb(struct urb *urb)
{
int epid;
int empty;
unsigned long flags;
etrax_urb_priv_t *urb_priv;
DBFENTER;
/* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */
/* Epid allocation, empty check and list add must be protected.
Epid allocation because if we find an existing epid for this endpoint an urb might be
completed (emptying the list) before we add the new urb to the list, causing the epid
to be de-allocated. We would then start the transfer with an invalid epid -> epid attn.
Empty check and add because otherwise we might conclude that the list is not empty,
after which it becomes empty before we add the new urb to the list, causing us not to
insert the new traffic into the SB list. */
spin_lock_irqsave(&urb_list_lock, flags);
epid = etrax_usb_setup_epid(urb);
if (epid == -1) {
spin_unlock_irqrestore(&urb_list_lock, flags);
DBFEXIT;
return -ENOMEM;
}
empty = urb_list_empty(epid);
urb_list_add(urb, epid);
spin_unlock_irqrestore(&urb_list_lock, flags);
dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d",
(unsigned long)urb, empty ? "empty" : "", epid);
/* Mark the urb as being in progress. */
urb->status = -EINPROGRESS;
/* Setup the hcpriv data. */
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
assert(urb_priv != NULL);
/* This sets rx_offset to 0. */
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
urb_priv->urb_state = NOT_STARTED;
urb->hcpriv = urb_priv;
if (empty) {
etrax_usb_add_to_ctrl_sb_list(urb, epid);
}
DBFEXIT;
return 0;
}
static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid)
{
USB_SB_Desc_t *sb_desc_setup;
USB_SB_Desc_t *sb_desc_data;
USB_SB_Desc_t *sb_desc_status;
etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
unsigned long flags;
char maxlen;
DBFENTER;
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
assert(sb_desc_setup != NULL);
sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
assert(sb_desc_status != NULL);
/* Initialize the mandatory setup SB descriptor (used only in control transfers) */
sb_desc_setup->sw_len = 8;
sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) |
IO_STATE(USB_SB_command, tt, setup) |
IO_STATE(USB_SB_command, full, yes) |
IO_STATE(USB_SB_command, eot, yes));
sb_desc_setup->buf = virt_to_phys(urb->setup_packet);
if (usb_pipeout(urb->pipe)) {
dbg_ctrl("Transfer for epid %d is OUT", epid);
/* If this Control OUT transfer has an optional data stage we add an OUT token
before the mandatory IN (status) token, hence the reordered SB list */
sb_desc_setup->next = virt_to_phys(sb_desc_status);
if (urb->transfer_buffer) {
dbg_ctrl("This OUT transfer has an extra data stage");
sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
assert(sb_desc_data != NULL);
sb_desc_setup->next = virt_to_phys(sb_desc_data);
sb_desc_data->sw_len = urb->transfer_buffer_length;
sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) |
IO_STATE(USB_SB_command, full, yes) |
IO_STATE(USB_SB_command, eot, yes));
sb_desc_data->buf = virt_to_phys(urb->transfer_buffer);
sb_desc_data->next = virt_to_phys(sb_desc_status);
}
sb_desc_status->sw_len = 1;
sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
IO_STATE(USB_SB_command, tt, in) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, intr, yes) |
IO_STATE(USB_SB_command, eol, yes));
sb_desc_status->buf = 0;
sb_desc_status->next = 0;
} else if (usb_pipein(urb->pipe)) {
dbg_ctrl("Transfer for epid %d is IN", epid);
dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
assert(sb_desc_data != NULL);
sb_desc_setup->next = virt_to_phys(sb_desc_data);
sb_desc_data->sw_len = urb->transfer_buffer_length ?
(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
dbg_ctrl("sw_len got %d", sb_desc_data->sw_len);
sb_desc_data->command =
(IO_FIELD(USB_SB_command, rem,
urb->transfer_buffer_length % maxlen) |
IO_STATE(USB_SB_command, tt, in) |
IO_STATE(USB_SB_command, eot, yes));
sb_desc_data->buf = 0;
sb_desc_data->next = virt_to_phys(sb_desc_status);
/* Read comment at zout_buffer declaration for an explanation to this. */
sb_desc_status->sw_len = 1;
sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
IO_STATE(USB_SB_command, tt, zout) |
IO_STATE(USB_SB_command, full, yes) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, intr, yes) |
IO_STATE(USB_SB_command, eol, yes));
sb_desc_status->buf = virt_to_phys(&zout_buffer[0]);
sb_desc_status->next = 0;
}
urb_priv->first_sb = sb_desc_setup;
urb_priv->last_sb = sb_desc_status;
urb_priv->epid = epid;
urb_priv->urb_state = STARTED;
/* Reset toggle bits and reset error count, remember to di and ei */
/* Warning: it is possible that this locking doesn't work with bottom-halves */
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
panic("Hold was set in %s", __FUNCTION__);
}
/* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits
are set to a specific value. Why the difference? Read "Transfer and Toggle Bits
in Designer's Reference, p. 8 - 11. */
*R_USB_EPT_DATA &=
~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
IO_MASK(R_USB_EPT_DATA, error_count_out) |
IO_MASK(R_USB_EPT_DATA, t_in) |
IO_MASK(R_USB_EPT_DATA, t_out));
/* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now
(i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */
restore_flags(flags);
/* Assert that the EP descriptor is disabled. */
assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
/* Set up and enable the EP descriptor. */
TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup);
TxCtrlEPList[epid].hw_len = 0;
TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
/* We start the DMA sub channel without checking if it's running or not, because:
1) If it's already running, issuing the start command is a nop.
2) We avoid a test-and-set race condition. */
*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
DBFEXIT;
}
static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status)
{
etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
int epid = urb_priv->epid;
DBFENTER;
if (status)
warn("Completing ctrl urb with status %d.", status);
dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb);
/* Remove this urb from the list. */
urb_list_del(urb, epid);
/* For an IN pipe, we always set the actual length, regardless of whether there was
an error or not (which means the device driver can use the data if it wants to). */
if (usb_pipein(urb->pipe)) {
urb->actual_length = urb_priv->rx_offset;
}
/* FIXME: Is there something of the things below we shouldn't do if there was an error?
Like, maybe we shouldn't insert more traffic. */
/* Remember to free the SBs. */
etrax_remove_from_sb_list(urb);
kfree(urb_priv);
urb->hcpriv = 0;
/* If there are any more urbs in the list we'd better start sending. */
if (!urb_list_empty(epid)) {
struct urb *new_urb;
/* Get the first urb. */
new_urb = urb_list_first(epid);
assert(new_urb);
dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb);
etrax_usb_add_to_ctrl_sb_list(new_urb, epid);
}
urb->status = status;
/* We let any non-zero status from the layer above have precedence. */
if (status == 0) {
/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
is to be treated as an error. */
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
if (usb_pipein(urb->pipe) &&
(urb->actual_length !=
usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
urb->status = -EREMOTEIO;
}
}
}
if (urb->complete) {
urb->complete(urb, NULL);
}
if (urb_list_empty(epid)) {
/* No more traffic. Time to clean up. */
etrax_usb_free_epid(epid);
/* Must set sub pointer to 0. */
dbg_ctrl("No ctrl for epid %d", epid);
TxCtrlEPList[epid].sub = 0;
}
DBFEXIT;
}
static int etrax_usb_submit_intr_urb(struct urb *urb)
{
int epid;
DBFENTER;
if (usb_pipeout(urb->pipe)) {
/* Unsupported transfer type.
We don't support interrupt out traffic. (If we do, we can't support
intervals for neither in or out traffic, but are forced to schedule all
interrupt traffic in one frame.) */
return -EINVAL;
}
epid = etrax_usb_setup_epid(urb);
if (epid == -1) {
DBFEXIT;
return -ENOMEM;
}
if (!urb_list_empty(epid)) {
/* There is already a queued urb for this endpoint. */
etrax_usb_free_epid(epid);
return -ENXIO;
}
urb->status = -EINPROGRESS;
dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid);
urb_list_add(urb, epid);
etrax_usb_add_to_intr_sb_list(urb, epid);
return 0;
DBFEXIT;
}
static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
{
volatile USB_EP_Desc_t *tmp_ep;
volatile USB_EP_Desc_t *first_ep;
char maxlen;
int interval;
int i;
etrax_urb_priv_t *urb_priv;
DBFENTER;
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
interval = urb->interval;
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
assert(urb_priv != NULL);
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
urb->hcpriv = urb_priv;
first_ep = &TxIntrEPList[0];
/* Round of the interval to 2^n, it is obvious that this code favours
smaller numbers, but that is actually a good thing */
/* FIXME: The "rounding error" for larger intervals will be quite
large. For in traffic this shouldn't be a problem since it will only
mean that we "poll" more often. */
for (i = 0; interval; i++) {
interval = interval >> 1;
}
interval = 1 << (i - 1);
dbg_intr("Interval rounded to %d", interval);
tmp_ep = first_ep;
i = 0;
do {
if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
if ((i % interval) == 0) {
/* Insert the traffic ep after tmp_ep */
USB_EP_Desc_t *ep_desc;
USB_SB_Desc_t *sb_desc;
dbg_intr("Inserting EP for epid %d", epid);
ep_desc = (USB_EP_Desc_t *)
kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
sb_desc = (USB_SB_Desc_t *)
kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
assert(ep_desc != NULL);
CHECK_ALIGN(ep_desc);
assert(sb_desc != NULL);
ep_desc->sub = virt_to_phys(sb_desc);
ep_desc->hw_len = 0;
ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
IO_STATE(USB_EP_command, enable, yes));
/* Round upwards the number of packets of size maxlen
that this SB descriptor should receive. */
sb_desc->sw_len = urb->transfer_buffer_length ?
(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
sb_desc->next = 0;
sb_desc->buf = 0;
sb_desc->command =
(IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) |
IO_STATE(USB_SB_command, tt, in) |
IO_STATE(USB_SB_command, eot, yes) |
IO_STATE(USB_SB_command, eol, yes));
ep_desc->next = tmp_ep->next;
tmp_ep->next = virt_to_phys(ep_desc);
}
i++;
}
tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
} while (tmp_ep != first_ep);
/* Note that first_sb/last_sb doesn't apply to interrupt traffic. */
urb_priv->epid = epid;
/* We start the DMA sub channel without checking if it's running or not, because:
1) If it's already running, issuing the start command is a nop.
2) We avoid a test-and-set race condition. */
*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
DBFEXIT;
}
static void etrax_usb_complete_intr_urb(struct urb *urb, int status)
{
etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
int epid = urb_priv->epid;
DBFENTER;
if (status)
warn("Completing intr urb with status %d.", status);
dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb);
urb->status = status;
urb->actual_length = urb_priv->rx_offset;
dbg_intr("interrupt urb->actual_length = %d", urb->actual_length);
/* We let any non-zero status from the layer above have precedence. */
if (status == 0) {
/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
is to be treated as an error. */
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
if (urb->actual_length !=
usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
urb->status = -EREMOTEIO;
}
}
}
/* The driver will resubmit the URB so we need to remove it first */
etrax_usb_unlink_urb(urb, 0);
if (urb->complete) {
urb->complete(urb, NULL);
}
DBFEXIT;
}
static int etrax_usb_submit_isoc_urb(struct urb *urb)
{
int epid;
unsigned long flags;
DBFENTER;
dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb);
/* Epid allocation, empty check and list add must be protected.
Read about this in etrax_usb_submit_ctrl_urb. */
spin_lock_irqsave(&urb_list_lock, flags);
/* Is there an active epid for this urb ? */
epid = etrax_usb_setup_epid(urb);
if (epid == -1) {
DBFEXIT;
spin_unlock_irqrestore(&urb_list_lock, flags);
return -ENOMEM;
}
/* Ok, now we got valid endpoint, lets insert some traffic */
urb->status = -EINPROGRESS;
/* Find the last urb in the URB_List and add this urb after that one.
Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list. This
is important to make this in "real time" since isochronous traffic is
time sensitive. */
dbg_isoc("Adding isoc urb to (possibly empty) list");
urb_list_add(urb, epid);
etrax_usb_add_to_isoc_sb_list(urb, epid);
spin_unlock_irqrestore(&urb_list_lock, flags);
DBFEXIT;
return 0;
}
static void etrax_usb_check_error_isoc_ep(const int epid)
{
unsigned long int flags;
int error_code;
__u32 r_usb_ept_data;
/* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof,
bulk_eot and epid_attn interrupts. So we just check the status of
the epid without testing if for it in R_USB_EPID_ATTN. */
save_flags(flags);
cli();
*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
nop();
/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
registers, they are located at the same address and are of the same size.
In other words, this read should be ok for isoc also. */
r_usb_ept_data = *R_USB_EPT_DATA;
restore_flags(flags);
error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
warn("Hold was set for epid %d.", epid);
return;
}
if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) {
/* This indicates that the SB list of the ept was completed before
new data was appended to it. This is not an error, but indicates
large system or USB load and could possibly cause trouble for
very timing sensitive USB device drivers so we log it.
*/
info("Isoc. epid %d disabled with no error", epid);
return;
} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) {
/* Not really a protocol error, just says that the endpoint gave
a stall response. Note that error_code cannot be stall for isoc. */
panic("Isoc traffic cannot stall");
} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) {
/* Two devices responded to a transaction request. Must be resolved
by software. FIXME: Reset ports? */
panic("Bus error for epid %d."
" Two devices responded to transaction request",
epid);
} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
/* DMA overrun or underrun. */
warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
/* It seems that error_code = buffer_error in
R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
are the same error. */
}
}
static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
{
int i = 0;
etrax_urb_priv_t *urb_priv;
USB_SB_Desc_t *prev_sb_desc, *next_sb_desc, *temp_sb_desc;
DBFENTER;
prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
assert(urb_priv != NULL);
memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
urb->hcpriv = urb_priv;
urb_priv->epid = epid;
if (usb_pipeout(urb