[Prism54-devel] prism54 USB devel

Feyd feyd@seznam.cz
Sat, 3 Apr 2004 11:00:23 +0200


This is a multi-part message in MIME format.

--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

On Wed, 31 Mar 2004 15:19:14 -0700 (MST)
Teunis Peters <teunis@ru2shy.net> wrote:

> Well, seeing as there's no such driver yet, I've started working on it.
> I've got the easy stuff done (a module that loads and detects add/remove
> of USB device) but now am working on device communications so any/all
> suggestions would be helpful :)
> 
> hardware:
> 	Linksys WUSB56G

We are workinkg on that with Johannes. You couldnt see that, as the list
was dead for some time :)

Feyd

--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz
Content-Type: application/octet-stream;
 name="Makefile.k26"
Content-Disposition: attachment;
 filename="Makefile.k26"
Content-Transfer-Encoding: base64

IyAkSWQ6IE1ha2VmaWxlLmsyNix2IDEuOCAyMDA0LzAzLzE4IDA1OjI1OjI0IG1jZ3JvZiBFeHAg
JAoKcHJpc201NC1vYmpzIDo9IGlzbHBjaV9ldGgubyBpc2xwY2lfbWd0Lm8gXAogICAgICAgICAg
ICAgICAgaXNsXzM4eHgubyBpc2xfaW9jdGwubyBpc2xwY2lfZGV2Lm8gXAoJCWlzbHBjaV9ob3Rw
bHVnLm8gb2lkX21ndC5vCgpwcmlzbTU0dS1vYmpzIDo9IHVzYl9pbml0Lm8gdXNiX25ldGRldi5v
IHVzYl90cmFuc3BvcnQubwoKb2JqLSQoQ09ORklHX1BSSVNNNTQpICs9IHByaXNtNTR1Lm8KCkVY
VFJBX0NGTEFHUyA9IC1JJChQV0QpIC1Xbm8tdW51c2VkIy1EQ09ORklHX1BSSVNNNTRfV0RTCgo=

--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz
Content-Type: text/x-chdr;
 name="prism54_usb.h"
Content-Disposition: attachment;
 filename="prism54_usb.h"
Content-Transfer-Encoding: 7bit

/*
 * Prism54 USB driver 
 
T:  Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#=  2 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=5041 ProdID=2234 Rev= 2.02
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=500mA
I:  If#= 0 Alt= 0 #EPs=11 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none)
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=0d(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=0e(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=8f(I) Atr=03(Int.) MxPS=   4 Ivl=125us

 */

//#undef CONFIG_USB_DEBUG
//#define CONFIG_USB_DEBUG y

#ifdef CONFIG_USB_DEBUG
#define p54u_dbg(format, arg...) if(debug > 1) printk(format "\n" ,##arg)
#else
#define p54u_dbg(format, arg...)
#endif
#define p54u_info(format, arg...) if(debug) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
#define p54u_warn(format, arg...) printk(KERN_WARN __FILE__ ": " format "\n" , ##arg)
#define p54u_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)

//#define p54u_time(arg...) 0LL
#define p54u_time(arg...) (get_jiffies_64(##arg) - p54u->time)

#define P54U_TX_TIMEOUT		(2*HZ)

#define P54U_REG_WSIZE		(sizeof(struct p54u_reg))
#define P54U_REG_RSIZE		(P54U_REG_WSIZE - (sizeof(u32)))

#define P54U_PORT_BRG		0x0010
#define P54U_PORT_BRG_CFG	0x0000
#define P54U_PORT_DEV		0x0800
#define P54U_PORT_DEV_CFG	0x0880
#define P54U_PORT_U16		0x0003
#define P54U_PORT_U32		0x000f

#define P54U_PORT_BRG_U32	(P54U_PORT_BRG | P54U_PORT_U32)
#define P54U_PORT_BRG_CFG_U32	(P54U_PORT_BRG_CFG | P54U_PORT_U32)
#define P54U_PORT_BRG_CFG_U16	(P54U_PORT_BRG_CFG | P54U_PORT_U16)

#define P54U_PORT_DEV_U32	(P54U_PORT_DEV | P54U_PORT_U32)
#define P54U_PORT_DEV_CFG_U32	(P54U_PORT_DEV_CFG | P54U_PORT_U32)
#define P54U_PORT_DEV_CFG_U16	(P54U_PORT_DEV_CFG | P54U_PORT_U16)

#define P54U_BRG_BASE		0x10000000
#define P54U_BRG_BASE_2		0x20000000

#define P54U_BRG_POWER_UP	0x01
#define P54U_BRG_POWER_DOWN	0x02

#define P54U_BRG_CTRL_REG	0x50
#define P54U_BRG_REV_REG	0x88

#define P54U_DEV_BASE		0x40000000

#define P54U_TRDY_TIMEOUT	0x40
#define P54U_RETRY_TIMEOUTG	0x41

#define P54U_IMAGE_FILE		"isl3890"

//#define P54U_MAX_FRAME_SIZE	16384
#define P54U_MAX_FRAME_SIZE	2048
//#define P54U_QUEUE_LEN	16
#define P54U_QUEUE_LEN		2
#define P54U_FW_BLOCK		512
#define P54U_INIT_BLOCK		0x03fc

#define p54u_brg_writel(dev, addr, val)		p54u_reg_rw(dev, 1, P54U_PIPE_BRG, P54U_PORT_BRG_U32, addr, val)
#define p54u_pcicfg_brg_writel(dev, addr, val)	p54u_reg_rw(dev, 1, P54U_PIPE_BRG, P54U_PORT_BRG_CFG_U32, addr, val)
#define p54u_pcicfg_brg_writew(dev, addr, val)	p54u_reg_rw(dev, 1, P54U_PIPE_BRG, P54U_PORT_BRG_CFG_U16, addr, (val & 0xffff))

#define p54u_dev_writel(dev, reg, val)		p54u_reg_rw(dev, 1, P54U_PIPE_DEV, P54U_PORT_DEV_U32, (P54U_DEV_BASE | reg), val)
#define p54u_pcicfg_dev_writel(dev, addr, val)	p54u_reg_rw(dev, 1, P54U_PIPE_DEV, P54U_PORT_DEV_CFG_U32, addr, val)
#define p54u_pcicfg_dev_writew(dev, addr, val)	p54u_reg_rw(dev, 1, P54U_PIPE_DEV, P54U_PORT_DEV_CFG_U16, addr, (val & 0xffff))

#define p54u_brg_readl(dev, addr)		p54u_reg_rw(dev, 0, P54U_PIPE_BRG, P54U_PORT_BRG_U32, addr, 0)
#define p54u_pcicfg_brg_readl(dev, addr)	p54u_reg_rw(dev, 0, P54U_PIPE_BRG, P54U_PORT_BRG_CFG_U32, addr, 0)
#define p54u_pcicfg_brg_readw(dev, addr)	(p54u_reg_rw(dev, 0, P54U_PIPE_BRG, P54U_PORT_BRG_CFG_U16, addr, 0) & 0xffff)

#define p54u_dev_readl(dev, reg)		p54u_reg_rw(dev, 0, P54U_PIPE_DEV, P54U_PORT_DEV_U32, (P54U_DEV_BASE | reg), 0)
#define p54u_pcicfg_dev_readl(dev, addr)	p54u_reg_rw(dev, 0, P54U_PIPE_DEV, P54U_PORT_DEV_CFG_U32, addr, 0)
#define p54u_pcicfg_dev_readw(dev, addr)	(p54u_reg_rw(dev, 0, P54U_PIPE_DEV, P54U_PORT_DEV_CFG_U16, addr, 0) & 0xffff)

enum p54u_pipe_addr {
        P54U_PIPE_DATA =	0x01,
        P54U_PIPE_MGMT =	0x02,
	P54U_PIPE_3 =		0x03,
        P54U_PIPE_4 =		0x04,
        P54U_PIPE_BRG =		0x0d,
        P54U_PIPE_DEV =		0x0e,
	P54U_PIPE_INT =		0x0f,
};

enum p54u_pipe_index {
	P54U_TX_DATA,
	P54U_TX_MGMT,
	P54U_TX_BRG,
	P54U_TX_DEV,
	P54U_RX_DATA,
	P54U_RX_MGMT,
	P54U_RX_3,
	P54U_RX_4,
	P54U_RX_BRG,
	P54U_RX_DEV,
	P54U_RX_INT,
	P54U_PIPES,
};

struct p54u_reg {
	u16	port;
	u32	addr;
	u32	val;
} __attribute__ ((packed));

struct p54u_mgmt_tx {
	u32	magic1;
	u32	magic2;
	u32	magic3;
	u16	pos;
	u16	len;
} __attribute__ ((packed));

struct p54u_mgmt_rx {
	u16			len;
	u16			pos;
	u32			magic1;
	u32			magic2;
	u32			magic3;
	struct p54u_mgmt_tx	id;
} __attribute__ ((packed));

struct p54u_pipe_desc {
	u8		addr;	/* the address of the endpoint */
	u8		type;	/* the transfer type of the endpoint */
	size_t		p_size;	/* the size of the packet */
	void		(*callback)(struct urb *urb, struct pt_regs *regs);
};

struct p54u_pipe {
	struct urb	**urb;	/* the urb used to send data */
	void		**buf;	/* the buffer */
	size_t		*size;	/* the size of the buffer */
	int		len;	/* the length of the ringbufer */
	int		head;
	int		tail;
	
	atomic_t	busy;	/* true if urb is busy */
	wait_queue_head_t wqh;
	struct completion comp; /* wait for the operation to finish */
	int done;
	
	u8		addr;	/* the address of the endpoint */
	u8		type;	/* the transfer type of the endpoint */
	size_t		pkt_size; /* the size of the packet */
};

/* Structure to hold all of our device specific stuff */
struct p54u {
	struct usb_device	*usbdev;	/* save off the usb device pointer */
	struct usb_interface	*interface;	/* save off the usb device pointer */
	struct net_device	*netdev;
	
	int			running;
	int			err;
	
	struct workqueue_struct	*queue;
	struct work		*boot;
	struct completion	*comp;
	
	struct p54u_pipe	data_tx;
	struct p54u_pipe	data_rx;
	struct p54u_pipe	mgmt_tx;
	struct p54u_pipe	mgmt_rx;
	struct p54u_pipe	int_rx;
	
	struct semaphore	disconnect_sem;	/* prevent races between open() and disconnect() */
	
	const struct firmware	*fw_entry;
	u64 			time;
};

extern int load_fw;
extern int debug;
extern const char dummy_mac[ETH_ALEN];

int p54u_setup_net(struct net_device *netdev);
int p54u_boot(struct net_device *netdev);
int p54u_shutdown(struct net_device *netdev);

void p54u_mdelay(int ms);
u32 p54u_reg_rw(struct net_device *netdev, int write, int ep, int port, u32 addr, u32 val);
u32 p54u_readi(struct net_device *netdev);

void p54u_int_rx_cb(struct urb *urb, struct pt_regs *p);
void p54u_data_rx_cb(struct urb *urb, struct pt_regs *p);
void p54u_mgmt_rx_cb(struct urb *urb, struct pt_regs *p);

u32 p54u_wait_int(struct net_device *netdev);
int p54u_bulk_msg(struct net_device *netdev, unsigned int ep, void *data, int len);

--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz
Content-Type: text/x-csrc;
 name="usb_init.c"
Content-Disposition: attachment;
 filename="usb_init.c"
Content-Transfer-Encoding: 7bit

/*
 * Prism54 USB driver
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/usb.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <asm/uaccess.h>
#include "prism54_usb.h"
#include "isl_38xx.h"

#ifdef CONFIG_USB_DEBUG
int debug = 2;
#else
int debug;
#endif

int load_fw;
static const char driver_name[] = "prism54_usb";

static const struct usb_device_id p54u_table[] = {
	{USB_DEVICE(0x5041, 0x2234)},	/* Linksys WUSB54G */
	{}
};

static const struct p54u_pipe_desc p54u_pipes[] = {
	{ P54U_PIPE_DATA,		USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_MGMT,		USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_BRG,		USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_DEV,		USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_DATA | USB_DIR_IN,	USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_MGMT | USB_DIR_IN,	USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_3    | USB_DIR_IN,	USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_4    | USB_DIR_IN,	USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_BRG  | USB_DIR_IN,	USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_DEV  | USB_DIR_IN,	USB_ENDPOINT_XFER_BULK },
	{ P54U_PIPE_INT  | USB_DIR_IN,	USB_ENDPOINT_XFER_INT  },
};

static const char p54u_mgmt_0c[16] = {
	0x6c, 0x06, 0x02, 0x00, 0x0c, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static const char p54u_mgmt_30[16] = {
	0x6c, 0x06, 0x02, 0x00, 0x30, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

MODULE_DESCRIPTION("Prism54 USB Driver");
MODULE_AUTHOR("Feyd <feyd@seznam.cz>");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(usb, p54u_table);
MODULE_PARM(debug, "i");
MODULE_PARM(load_fw, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
MODULE_PARM_DESC(load_fw, "Load firmware on probe (1) or open (0)");

static int p54u_reset_usb(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	int err;

//	return 0;
	
	p54u_info("%s: Reset USB device.\n", netdev->name);
	err = usb_reset_device(usbdev);
	if(err) {
		p54u_err("%s: Reset USB device failed.\n", netdev->name);
		return err;
	}
//	p54u_mdelay(200);
	p54u_info("%s: Reset USB device done.\n", netdev->name);
	
	return 0;
}

static void p54u_free_pipe(struct net_device *netdev, struct p54u_pipe *pipe)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	int i;

	p54u_info("Freeing pipe.\n");
	
	if(!pipe->buf) {
		p54u_info("pipe->buf == NULL\n");
		goto do_free_urb;
	}

	if(!pipe->urb) {
		p54u_info("pipe->urb == NULL\n");
		goto do_free_size;
	}

	if(!pipe->size) {
		p54u_info("pipe->size == NULL\n");
		goto do_clear;
	}
	
	for(i = 0; i < pipe->len; i++) {
		if(pipe->urb[i]) {
			/* FIXME: unlink the busy one */
			if(pipe->buf[i]) {
				usb_buffer_free(usbdev, pipe->size[i], pipe->buf[i], pipe->urb[i]->transfer_dma);
			} else {
				p54u_info("pipe->buf[%i] == NULL\n", i);

			}
			usb_free_urb(pipe->urb[i]);
		} else {
			p54u_info("pipe->urb[%i] == NULL\n", i);
		}
	}

	kfree(pipe->buf);
	
    do_free_urb:
	if(pipe->urb) {
	    kfree(pipe->urb);
	} else {
		p54u_info("pipe->urb == NULL\n");
	}
	
    do_free_size:
    	if(pipe->size) {
		kfree(pipe->size);
	} else {
		p54u_info("pipe->size == NULL\n");
	}
	
    do_clear:
	p54u_info("Clear the memory.\n");

	memset(pipe, 0, sizeof(*pipe));
	
	p54u_info("Freeing pipe done.\n");
	
	return;
}

static void p54u_free_buffers(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;

	p54u_free_pipe(netdev, &p54u->data_tx);
	p54u_free_pipe(netdev, &p54u->data_rx);
	p54u_free_pipe(netdev, &p54u->mgmt_tx);
	p54u_free_pipe(netdev, &p54u->mgmt_rx);
	p54u_free_pipe(netdev, &p54u->int_rx);
	
	return;
}

static int p54u_alloc_pipe(struct net_device *netdev, struct usb_endpoint_descriptor *desc, struct p54u_pipe *pipe, usb_complete_t callback)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	int err, i, p, e;
	
	if(!pipe)
		return 0;

	p54u_info("%s: Allocate pipe %02x.\n", netdev->name, desc->bEndpointAddress);
	
	pipe->pkt_size = desc->wMaxPacketSize;
	pipe->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
	pipe->addr = desc->bEndpointAddress;
	pipe->len = P54U_QUEUE_LEN;
	
	pipe->size = kmalloc(sizeof(*pipe->size) * pipe->len, GFP_KERNEL);
	if(!pipe->size) {
		p54u_info("Failed to allocate pipe->size\n");
		goto do_enomem;
	} else {
		p54u_info("pipe->size == %p\n", pipe->size);
	}
	memset(pipe->size, 0, sizeof(*pipe->size) * pipe->len);


	pipe->urb = kmalloc(sizeof(*pipe->urb) * pipe->len, GFP_KERNEL);
	if(!pipe->urb) {
		p54u_info("Failed to allocate pipe->urb\n");
		goto do_enomem;
	} else {
		p54u_info("pipe->urb == %p\n", pipe->urb);
	}
	memset(pipe->urb, 0, sizeof(*pipe->urb) * pipe->len);
	
	pipe->buf = kmalloc(sizeof(*pipe->buf) * pipe->len, GFP_KERNEL);
	if(!pipe->buf) {
		p54u_info("Failed to allocate pipe->buf\n");
		goto do_enomem;
	} else {
		p54u_info("pipe->buf == %p\n", pipe->buf);
	}
	memset(pipe->buf, 0, sizeof(*pipe->buf) * pipe->len);
	
	p54u_info("%s: Allocate buffers.\n", netdev->name);
	
	for(i = 0; i < pipe->len; i++) {
		pipe->size[i] = P54U_MAX_FRAME_SIZE;
		if(pipe->type == USB_ENDPOINT_XFER_INT) {
			pipe->size[i] = 4;
		}
		
		p54u_info("pipe->size [%i] = %i\n", i, pipe->size[i]);
		
		pipe->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
		if(!pipe->urb[i]) {
			p54u_info("Failed to allocate pipe->urb[%i]\n", i);
			goto do_enomem;
		} else {
			p54u_info("pipe->urb[%i] == %p\n", i, pipe->urb[i]);
		}
		pipe->urb[i]->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);

		pipe->buf[i] = usb_buffer_alloc(usbdev, pipe->size[i], GFP_KERNEL, &pipe->urb[i]->transfer_dma);
		if(!pipe->buf[i]) {
			p54u_info("Failed to allocate pipe->buf[%i]\n", i);
			goto do_enomem;
		} else {
			p54u_info("pipe->buf[%i] == %p\n", i, pipe->buf[i]);
		}
		
		e = pipe->addr & USB_ENDPOINT_NUMBER_MASK;
		p54u_info("pipe->addr = %i\n", e);
//		e = pipe->addr;
		switch(pipe->type) {
		case USB_ENDPOINT_XFER_BULK:
			p = pipe->addr & USB_DIR_IN ? usb_rcvbulkpipe(usbdev, e) : usb_sndbulkpipe(usbdev, e);
			usb_fill_bulk_urb(pipe->urb[i], usbdev, p, pipe->buf[i], pipe->size[i], callback, netdev);
		case USB_ENDPOINT_XFER_INT:
			p = usb_rcvintpipe(usbdev, e);
			usb_fill_int_urb(pipe->urb[i], usbdev, p, pipe->buf[i], pipe->size[i], callback, netdev, 10);
//			usb_fill_int_urb(pipe->urb[i], usbdev, p, pipe->buf[i], pipe->size[i], callback, netdev, HZ / 4);
//			p = pipe->addr & USB_DIR_IN ? usb_rcvbulkpipe(usbdev, e) : usb_sndbulkpipe(usbdev, e);
//			usb_fill_bulk_urb(pipe->urb[i], usbdev, p, pipe->buf[i], pipe->size[i], callback, netdev);
		}
		
		init_completion(&pipe->comp);
	}
	
	p54u_info("%s: Allocate pipe done.\n", netdev->name);
	return 0;
	
    do_enomem:
	p54u_info("%s: Not enough memory.\n", netdev->name);
	err = -ENOMEM;
    do_err:
	p54u_info("%s: Allocate pipe failed.\n", netdev->name);
	return err;
}

static int p54u_alloc_buffers(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	struct usb_interface *interface = p54u->interface;
	struct usb_host_interface *iface_desc = &interface->altsetting[0];
	struct usb_endpoint_descriptor *desc;
	struct p54u_pipe *pipe;
	int err = 0, i;
	
	p54u_info("%s: Setup USB structures.\n", netdev->name);
	
	for(i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		desc = &iface_desc->endpoint[i].desc;
		switch(desc->bEndpointAddress) {
		case P54U_PIPE_DATA:
			err = p54u_alloc_pipe(netdev, desc, &p54u->data_tx, NULL);
			break;
		case P54U_PIPE_MGMT:
			err = p54u_alloc_pipe(netdev, desc, &p54u->mgmt_tx, NULL);
			break;
		case P54U_PIPE_DATA | USB_DIR_IN:
			err = p54u_alloc_pipe(netdev, desc, &p54u->data_rx, p54u_data_rx_cb);
			break;
		case P54U_PIPE_MGMT | USB_DIR_IN:
			err = p54u_alloc_pipe(netdev, desc, &p54u->mgmt_rx, p54u_mgmt_rx_cb);
			break;
		case P54U_PIPE_INT | USB_DIR_IN:
			err = p54u_alloc_pipe(netdev, desc , &p54u->int_rx, p54u_int_rx_cb);
			break;
		default:
			break;
		}
		if(err)
			goto do_err;
	}
	p54u_info("%s: Setup USB structures successful.\n", netdev->name);


	return 0;
	
    do_err:
    	p54u_info("%s: Setup USB structures failed: %i\n", netdev->name, err);
	p54u_free_buffers(netdev);
	
	return err;
}

static int p54u_reset_dev(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	u32 reg, revision;
	int err;
	
	p54u_info("%s: Reset device.\n", netdev->name);
	
	/* Bridge */
	/* Reset the usb<->pci bridge */
	p54u_dbg("%s: Reset bridge\n", netdev->name);
	reg = p54u_brg_readl(netdev, P54U_BRG_CTRL_REG);
	//reg = 0x3e;
	p54u_brg_writel(netdev, P54U_BRG_CTRL_REG, (reg | P54U_BRG_POWER_DOWN) & ~P54U_BRG_POWER_UP);
	if(p54u->err)
		goto do_err;
	p54u_mdelay(100);
	p54u_brg_writel(netdev, P54U_BRG_CTRL_REG, (reg | P54U_BRG_POWER_UP) & ~P54U_BRG_POWER_DOWN);
	if(p54u->err)
		goto do_err;
	p54u_dbg("%s: Reset bridge done\n", netdev->name);
	p54u_mdelay(100);
	
	/* Magic */
	p54u_dbg("%s: Magic 1\n", netdev->name);
	p54u_brg_writel(netdev, 0, 0x0224);
	if(p54u->err)
		goto do_err;
	p54u_dbg("%s: Magic 1 done\n", netdev->name);
	p54u_mdelay(20);
	
	/* Enable mmio and busmaster on the bridge */
	p54u_dbg("%s: Setup bridge pci resources\n", netdev->name);
	p54u_pcicfg_brg_writew(netdev, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
	
	/* Set base address 0 */
	p54u_pcicfg_brg_writel(netdev, PCI_BASE_ADDRESS_0, P54U_BRG_BASE);
	
	/* Set PCI_STATUS_REC_MASTER_ABORT) (why?) */
	reg = p54u_pcicfg_brg_readw(netdev, PCI_STATUS);
	p54u_pcicfg_brg_writew(netdev, PCI_STATUS, (reg | PCI_STATUS_REC_MASTER_ABORT));
	
	/* Read revision? */
	revision = p54u_brg_readl(netdev, P54U_BRG_REV_REG);
	p54u_dbg("%s: Setup bridge pci resources done\n", netdev->name);
	
	/* Magic */
	p54u_dbg("%s: Magic 2\n", netdev->name);
	p54u_brg_writel(netdev, 0x0324, 0x04);
	p54u_brg_writel(netdev, 0x0364, 0x04);
	p54u_dbg("%s: Magic 2 done\n", netdev->name);
	
	/* Set base address 2 */
	p54u_dbg("%s: Setup bridge base addr 2\n", netdev->name);
	p54u_pcicfg_brg_writel(netdev, PCI_BASE_ADDRESS_2, P54U_BRG_BASE_2);
	p54u_dbg("%s: Setup bridge base addr 2 done\n", netdev->name);
	
	/* Device */
	/* Enable mmio and busmaster on the device */
	p54u_dbg("%s: Setup device pci resources\n", netdev->name);
	p54u_pcicfg_dev_writew(netdev, PCI_COMMAND | 0x10000, (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
	
	/* Set TRDY_TIMEOUT and RETRY_TIMEOUT to 0 */
	p54u_pcicfg_dev_writew(netdev, P54U_TRDY_TIMEOUT | 0x10000, 0);
	
	/* Set base address 0 */
	p54u_pcicfg_dev_writel(netdev, PCI_BASE_ADDRESS_0 | 0x10000, P54U_DEV_BASE);
	p54u_dbg("%s: Setup device pci resources done\n", netdev->name);
	
	/* Magic */
	p54u_dbg("%s: Magic 3\n", netdev->name);
	p54u_brg_writel(netdev, 0x24, 0);
	p54u_brg_writel(netdev, 0x2c, 0x01000000);
	p54u_dbg("%s: Magic 3 done\n", netdev->name);
	
	/* Assert wakeup */
	p54u_dbg("%s: Assert device\n", netdev->name);
	p54u_dev_writel(netdev, ISL38XX_DEV_INT_REG,  ISL38XX_DEV_INT_WAKEUP);
	if(p54u->err)
		goto do_err;
	p54u_mdelay(20);
	
	/* Assert something unknown */
	p54u_dev_writel(netdev, ISL38XX_DEV_INT_REG,  0x20);
	if(p54u->err)
		goto do_err;
	p54u_dbg("%s: Assert device done\n", netdev->name);
	p54u_mdelay(20);
	
	/* Reset the device */
	p54u_dbg("%s: Reset device\n", netdev->name);
	reg = p54u_dev_readl(netdev, ISL38XX_CTRL_STAT_REG);
	reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT | ISL38XX_CTRL_STAT_CLKRUN);
	p54u_dev_writel(netdev, ISL38XX_CTRL_STAT_REG, reg);
	p54u_dev_writel(netdev, ISL38XX_CTRL_STAT_REG, reg | ISL38XX_CTRL_STAT_RESET);
	p54u_dev_writel(netdev, ISL38XX_CTRL_STAT_REG, reg);
	if(p54u->err)
		goto do_err;
	p54u_dbg("%s: Reset device done\n", netdev->name);
	p54u_mdelay(100);
	p54u_dbg("%s: Disable irq\n", netdev->name);
	p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0);
	p54u_dbg("%s: Disable irq done\n", netdev->name);
	
	/* Ack the irqs */
	p54u_dbg("%s: Ack irq\n", netdev->name);
	reg = p54u_dev_readl(netdev, ISL38XX_INT_IDENT_REG);
	p54u_dev_writel(netdev, ISL38XX_INT_ACK_REG, reg);
	if(p54u->err)
		goto do_err;
	p54u_dbg("%s: Ack done\n", netdev->name);

	p54u_info("%s: Reset device done.\n", netdev->name);
	
	return 0;
	
    do_err:
    	p54u_err("%s: Reset error: %i\n", netdev->name, p54u->err);
    	err = p54u->err;
	p54u->err = 0;
	return err;
}

static int p54u_load_firmware(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	unsigned int pipe;
	u32 reg;
	void *data;
	size_t len;
	int err, i, j, k, l;
	u64 t, t1, t2;

	char *rcv;
	
	p54u_info("%s: Load firmware.\n", netdev->name);

	/* Firmware */
	/* Magic */
	p54u_dbg("%s: Magic 4\n", netdev->name);
	p54u_brg_writel(netdev, 0x032c, P54U_FW_BLOCK);
	p54u_brg_writel(netdev, 0x034c, P54U_FW_BLOCK);
	p54u_brg_writel(netdev, 0x036c, P54U_FW_BLOCK);
	p54u_brg_writel(netdev, 0x038c, P54U_FW_BLOCK);
	p54u_brg_writel(netdev, 0x032c, P54U_FW_BLOCK);
	p54u_dbg("%s: Magic 4 done\n", netdev->name);
	
	
	pipe = usb_sndbulkpipe(usbdev, P54U_PIPE_DATA);
	data = p54u->fw_entry->data;
	i = p54u->fw_entry->size;
	j = 0;
	while(i > 0) {
		len = i > P54U_FW_BLOCK ? P54U_FW_BLOCK : i;
		t1 =  p54u_time();
		p54u->err = usb_bulk_msg(usbdev, pipe, data, len, &len, HZ);
		t2 =  p54u_time();
		t = t2 - t1;
		
		for(k = 0; k < len; k+= 16) {
			if(k == 0) {
				printk(KERN_CRIT "[OUT >%-6lld<%-6lld+%-6lld]\t%02x -> 00000000:", t1, t2, t, P54U_PIPE_DATA);
				//printk(KERN_CRIT "%02x -> %08x:", P54U_PIPE_DATA, k);
			} else {
				printk(KERN_CRIT "\t\t\t\t   -> %08x:", k);
			}
			for (l = 0; (l < 16) && (k + l < len); ++l) {
				printk(" %02x", ((unsigned char *)data)[k + l]);
			}
			printk("\n");
		}
		
		if(p54u->err) {
			p54u_dbg("%s: Error writing firmware block: writen %i of %i.\n", netdev->name, j, p54u->fw_entry->size);
			goto do_release;
		}
		data += P54U_FW_BLOCK;
		i -= P54U_FW_BLOCK;
		
		/* Magic */
		p54u_dev_writel(netdev, ISL38XX_DIR_MEM_BASE_REG, 0xc0000f00);
		p54u_dev_writel(netdev, 0x1020, 0);
		p54u_dev_writel(netdev, 0x1020, 1);
		p54u_dev_writel(netdev, 0x1024, len);
		p54u_dev_writel(netdev, 0x1028, j | 0x00020000);
		p54u_dev_writel(netdev, 0x0060, 0x20000000);
		p54u_dev_writel(netdev, 0x0064, i > 0 ? 0x80 : 0x2e);
		p54u_dev_writel(netdev, 0x0068, 4);
		reg = p54u_dev_readl(netdev, 0x102c);
		if(i > 0)
			p54u_brg_writel(netdev, 0x032c, P54U_FW_BLOCK);
		if(p54u->err) {
			p54u_dbg("%s: Error updating registers: writen %i of %i.\n", netdev->name, j, p54u->fw_entry->size);
			goto do_release;
		}
		j += P54U_FW_BLOCK;

	}
	
	p54u_info("%s: Load firmware done.\n", netdev->name);
	return 0;
	
    do_release:
    do_err:
    	p54u_err("%s: Load error: %i\n", netdev->name, p54u->err);
    	err = p54u->err;
	p54u->err = 0;
	return err;
}

int p54u_setup_dev(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	struct p54u_mgmt_tx *tx1, *tx2;
	u32 reg;
	int i, j, k;

	reg = p54u_dev_readl(netdev, ISL38XX_CTRL_STAT_REG);
	p54u_dev_writel(netdev, ISL38XX_CTRL_STAT_REG, reg | ISL38XX_CTRL_STAT_RAMBOOT);
	p54u_dev_writel(netdev, ISL38XX_CTRL_STAT_REG, reg | ISL38XX_CTRL_STAT_RAMBOOT | ISL38XX_CTRL_STAT_RESET);
	p54u_dev_writel(netdev, ISL38XX_CTRL_STAT_REG, reg | ISL38XX_CTRL_STAT_RAMBOOT);
	if(p54u->err) {
		p54u_dbg("%s: Error latching reset: %i\n", netdev->name, p54u->err);
	}
	
	p54u->err = usb_submit_urb(p54u->int_rx.urb[0], GFP_KERNEL);
	if(p54u->err) {
		p54u_dbg("%s: Error submit int 0: %i\n", netdev->name, p54u->err);
	} else {
		p54u_dbg("%s: Submit int 0 ok.\n", netdev->name);
	}

	p54u->err = usb_submit_urb(p54u->data_rx.urb[0], GFP_KERNEL);
	if(p54u->err) {
		p54u_dbg("%s: Error submit data: %i\n", netdev->name, p54u->err);
	} else {
		p54u_dbg("%s: Submit data ok.\n", netdev->name);
	}
	
	p54u->err = usb_submit_urb(p54u->mgmt_rx.urb[0], GFP_KERNEL);
	if(p54u->err) {
		p54u_dbg("%s: Error submit mgmt: %i\n", netdev->name, p54u->err);
	} else {
		p54u_dbg("%s: Submit mgmt ok.\n", netdev->name);
	}

	p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0xffffffff);
    	p54u_brg_writel(netdev, 0x2c, 0x01000000);
	p54u_brg_writel(netdev, 0x24, 0x81000000);
	p54u_dev_writel(netdev, ISL38XX_DEV_INT_REG, ISL38XX_DEV_INT_RESET);
	
	while(p54u_wait_int(netdev)) {
		p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0xffffffff);
		p54u_brg_writel(netdev, 0x2c, 0x01000000);
	}
	
//	p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0x00004004);
	p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0xffffffff);
	p54u_brg_writel(netdev, 0x2c, 0x01000000);
	
	
	/* Send the initial data to 0x02 pipe */
	
	memset(p54u->mgmt_tx.buf[0], 0, p54u->mgmt_tx.size[0]);
	memset(p54u->mgmt_tx.buf[1], 0, p54u->mgmt_tx.size[1]);
	
	tx1 = p54u->mgmt_tx.buf[0];
	tx2 = p54u->mgmt_tx.buf[1];
	
	tx1->magic1 = 0x0002066c;
	tx1->magic2 = 0x0002040c;
	tx1->magic3 = 0;
	tx1->pos = 0;
	tx1->len = 0;

	tx2->magic1 = 0x04008000;
	tx2->magic2 = 0x813376b0;
	tx2->magic3 = 0x0000000c;
	tx2->pos = 0;
	tx2->len = P54U_INIT_BLOCK;
	
	for(i = 0; i < 1; i++) {
		p54u_bulk_msg(netdev, P54U_PIPE_MGMT, tx1, 16);
		p54u_dev_writel(netdev, ISL38XX_DEV_INT_REG, 0x80);
		p54u_bulk_msg(netdev, P54U_PIPE_MGMT, tx2, P54U_INIT_BLOCK + 16);
//		p54u_bulk_msg(netdev, P54U_PIPE_MGMT, tx2, 512);
		tx2->pos += P54U_INIT_BLOCK;
		p54u_mdelay(200);
	}
	
	return p54u->err;
}

int p54u_boot(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	int err;
	
	p54u_info("%s: Boot the device.\n", netdev->name);

	p54u_dbg("%s: Request firmware.\n", netdev->name);
	
	err = request_firmware(&p54u->fw_entry, P54U_IMAGE_FILE, netdev->class_dev.dev);
	if(err) {
		p54u_err("%s: Request firmware failed: %i\n", netdev->name, err);
		return err;
	}
		
	p54u_dbg("%s: Request firmware done: len = %i.\n", netdev->name, p54u->fw_entry->size);
	
	p54u->time = get_jiffies_64();
	
	err = p54u_reset_usb(netdev);
	
	if(!err)
		err = p54u_alloc_buffers(netdev);
	if(!err)
		err = p54u_reset_dev(netdev);
	if(!err)
		err = p54u_load_firmware(netdev);
	if(!err)
		err = p54u_setup_dev(netdev);
	
	release_firmware(p54u->fw_entry);
	memcpy(netdev->dev_addr, dummy_mac, ETH_ALEN);
	p54u->running = 1;
	
	if(err) {
		p54u_err("%s: Boot the device failed: %i\n", netdev->name, err);
		return err;
	}
	
	p54u_info("%s: Boot the device done.\n", netdev->name);
	return 0;
}

int p54u_shutdown(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	u32 reg;

	p54u_dbg("%s: Shutting down the device.\n", netdev->name);
	
	p54u_free_buffers(netdev);
	
//	reg = p54u_brg_readl(netdev, P54U_BRG_CTRL_REG);
//	p54u_brg_writel(netdev, P54U_BRG_CTRL_REG, (reg | P54U_BRG_POWER_DOWN) & ~P54U_BRG_POWER_UP);
//	p54u_brg_writel(netdev, P54U_BRG_CTRL_REG, 0x3e);
	p54u->running = 0;
	
	p54u_dbg("%s: Shutdown complete.\n", netdev->name);
	
	return 0;
}

static int p54u_validate_device(struct usb_interface *interface, const struct usb_device_id *id)
{
	/* See if the device offered us matches what we can accept */

	return 0;
}

static int p54u_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
	struct usb_device *usbdev = interface_to_usbdev(interface);
	struct net_device *netdev;
	struct p54u *p54u;
	
	
	p54u_dbg("Prism54 USB Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", usbdev->devnum, (int) usbdev->descriptor.idVendor, (int) usbdev->descriptor.idProduct, (int) usbdev->descriptor.bcdDevice);
	p54u_dbg("Device at %p", usbdev);
	p54u_dbg("Descriptor length: %x type: %x", (int) usbdev->descriptor.bLength, (int) usbdev->descriptor.bDescriptorType);
	
	if(p54u_validate_device(interface, id))
		return -ENODEV;
	
	netdev = alloc_etherdev(sizeof(*p54u));
	if (!netdev) {
		p54u_err("Failed to allocate netdevice.");
		return -ENOMEM;
	}
	
	SET_MODULE_OWNER(netdev);
	SET_NETDEV_DEV(netdev, &interface->dev);
	
	usb_set_intfdata(interface, netdev);
	
	p54u = netdev_priv(netdev);
	p54u->interface = interface;
	p54u->usbdev = usbdev;
	p54u->netdev = netdev;
	
	init_MUTEX (&p54u->disconnect_sem);
	memcpy(netdev->dev_addr, dummy_mac, ETH_ALEN);
	
	if(load_fw)
		/* Dont error if it fails, give it chance on open. */
		p54u_boot(netdev);

	if(p54u_setup_net(netdev)) {
		p54u_err("Failed to setup netdevice.");
		goto do_cleanup;
	}
	
	if(register_netdev(netdev)) {
		p54u_err("Failed to register netdevice.");
		goto do_cleanup;
	}
	
	p54u_info("Prism54 USB device now attached to %s", netdev->name);
	return 0;
	
    do_cleanup:
	p54u_free_buffers(netdev);
	usb_set_intfdata(interface, NULL);
	free_netdev(netdev);

	return -EIO;
}

static void p54u_disconnect(struct usb_interface *interface)
{
	struct net_device *netdev = usb_get_intfdata(interface);
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;

	p54u_info("Prism54 USB device %s disconnecing\n", netdev->name);
	
	p54u_dbg("sem down\n");
	down(&p54u->disconnect_sem);
	p54u_dbg("sem down done\n");
	
	p54u->running = 0;
	
	p54u_dbg("Running = 0.\n");
	
	usb_set_intfdata(interface, NULL);
	
	p54u_dbg("Cleared interface data.\n");
	
	unregister_netdev(netdev);
	
	p54u_dbg("Unregistered netdevice.\n");
	
	p54u_free_buffers(netdev);
	
	p54u_dbg("Freed buffers.\n");
	
	free_netdev(netdev);
	
	p54u_dbg("Freed netdevice.\n");
		
	p54u_info("Disconnect complete.\n");

	p54u_dbg("sem up\n");
	up(&p54u->disconnect_sem);
	p54u_dbg("sem up done\n");
}

static struct usb_driver p54u_driver = {
	.owner = THIS_MODULE,
	.name = driver_name,
	.probe = p54u_probe,
	.disconnect = p54u_disconnect,
	.id_table = p54u_table,
};

static int __init p54u_init(void)
{
	int result;

	/* register this driver with the USB subsystem */
	result = usb_register(&p54u_driver);
	if (result) {
		p54u_err("usb_register failed. Error number %d", result);
		return result;
	}

	return 0;
}

static void __exit p54u_exit(void)
{
	/* deregister this driver with the USB subsystem */
	usb_deregister(&p54u_driver);
}

module_init(p54u_init);
module_exit(p54u_exit);


--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz
Content-Type: text/x-csrc;
 name="usb_netdev.c"
Content-Disposition: attachment;
 filename="usb_netdev.c"
Content-Transfer-Encoding: 7bit

/*
 * Prism54 USB driver
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include "prism54_usb.h"
#include "isl_38xx.h"

const char dummy_mac[ETH_ALEN] = {0x00, 0x3d, 0xb4, 0x00, 0x00, 0x00};

static int p54u_open(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	
	p54u_info("sem down\n");
	down (&p54u->disconnect_sem);
	p54u_info("sem down done\n");

	
	if(!p54u->running && p54u_boot(netdev)) {
		p54u_err("Failed to boot device.\n");
		goto do_err;
	}
	
	netif_start_queue(netdev);
	p54u_info("sem up\n");
	up(&p54u->disconnect_sem);
	p54u_info("sem up done\n");
	return 0;

    do_err:
    	p54u_err("Failed to open device.\n");
	p54u_info("sem up\n");
	up(&p54u->disconnect_sem);
	p54u_info("sem up done\n");
	return -EIO;
}

static int p54u_close(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	
	netif_stop_queue(netdev);

	if(!load_fw && p54u->running && p54u_shutdown(netdev))
		return -EIO;
	
	return 0;
}

static void p54u_tx_timeout(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	
	return;
}

static int p54u_transmit(struct sk_buff *skb, struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	
	return 0;
}


int p54u_setup_net(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;

	/* initialize the function pointers */
	netdev->open = &p54u_open;
	netdev->stop = &p54u_close;
//	netdev->get_stats = &p54u_statistics;
//	netdev->get_wireless_stats = &p54u_wireless_stats;
//	netdev->do_ioctl = &p54u_ioctl;
//	netdev->wireless_handlers = (struct iw_handler_def *) &p54u_handler_def;

	netdev->hard_start_xmit = &p54u_transmit;
	netdev->addr_len = ETH_ALEN;
//	netdev->set_mac_address = &prism54_set_mac_address;

	netdev->watchdog_timeo = P54U_TX_TIMEOUT;
	netdev->tx_timeout = &p54u_tx_timeout;

	return 0;
}


--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz
Content-Type: text/x-csrc;
 name="usb_transport.c"
Content-Disposition: attachment;
 filename="usb_transport.c"
Content-Transfer-Encoding: 7bit

/*
 * Prism54 USB driver
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/usb.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <asm/uaccess.h>
#include "prism54_usb.h"
#include "isl_38xx.h"

void p54u_mdelay(int ms)
{
	int t = (ms * HZ + 500) / 1000;
	
	if(!t && ms)
		t = 1;
	
	set_current_state(TASK_UNINTERRUPTIBLE);
	while(t) {
		//printk("t: %i\n", t);
		t = schedule_timeout(t);
	}
	
	return;
}


void p54u_data_debug(struct net_device *netdev, unsigned int ep, void *_data, int len)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	unsigned char *data = _data;
	int k, l, in;
	
	in = ep & USB_DIR_IN;
	if(debug > 1) {
		for(k = 0; k < len; k+= 16) {
			if(k == 0) {
				printk(KERN_CRIT "[%s >%-6lld<%-6lld+%-6lld]\t%02x %s 00000000:", in?"IN ":"OUT", 0LL, 0LL, 0LL, ep, in?"<-":"->");
			} else {
				printk(KERN_CRIT "\t\t\t\t   -> %08x:", k);
			}
			for (l = 0; (l < 16) && (k + l < len); ++l) {
				printk(" %02x", ((unsigned char *)data)[k + l]);
			}
			printk("\n");
		}
	}
}

int p54u_bulk_msg(struct net_device *netdev, unsigned int ep, void *_data, int len)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	unsigned char *data = _data;
	size_t alen;
	int pipe, err, k, l;

	p54u_data_debug(netdev, ep, data, len);
	
	pipe = usb_sndbulkpipe(usbdev, ep);
	err = usb_bulk_msg(usbdev, pipe, data, len, &alen, 2 * HZ);
	if(err)
		p54u_info("bulk submit failed: %i\n", err);

	
/*	for(;;) {
		err = usb_bulk_msg(usbdev, pipe, data, len, alen, HZ);
		switch(err) {
		case -EPIPE:
			
		default:
			return err;
		}
	} while(err);
*/
	
	return err;
}


u32 p54u_reg_rw(struct net_device *netdev, int write, int ep, int port, u32 addr, u32 val)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	struct p54u_reg *reg;
	unsigned char data[sizeof(*reg)];
	unsigned int pipe;
	size_t len;
	int err, i, epd;
	u64 t, t1, t2;
	
	if(debug > 2) {
		if(write) {
			printk(KERN_DEBUG __FILE__ " Write %02x %04x %08x %08x", ep, port, addr, val);
		} else {
			printk(KERN_DEBUG __FILE__ " Read  %02x %04x %08x         ", ep, port, addr);
		}
	}
	
	reg = (struct p54u_reg *)data;
	reg->port = cpu_to_le16(port);
	reg->addr = cpu_to_le32(addr);
	reg->val = ((port & P54U_PORT_U32) == P54U_PORT_U32) ? cpu_to_le32(val) : cpu_to_le16(val);
	len = write ? P54U_REG_WSIZE : P54U_REG_RSIZE;
	pipe = usb_sndbulkpipe(usbdev, ep & USB_ENDPOINT_NUMBER_MASK);
	
	t1 = p54u_time();
	err = usb_bulk_msg(usbdev, pipe, data, len, &len, HZ);
	t2 = p54u_time();
	t = t2 - t1;
	
	if(debug > 1) {
		printk(KERN_CRIT "[OUT >%-6lld<%-6lld+%-6lld]\t%02x -> 00000000:", t1, t2, t, ep);
		for (i = 0; i < len; ++i) {
			printk(" %02x", data[i]);
		}
	}
	
	if(err)
		p54u->err = err;
	
	if(debug > 1) {
		if(err) {
			printk(" failed: %i", err);
		}
		printk("\n");
	} else if(err) {
		p54u_err("%s %02x %04x %08x %08x: failed: %i", write ? "Write": "Read", ep, port, addr, val, err);
		return 0;
	}
	
	if(write)
		return 0;
	
	pipe = usb_rcvbulkpipe(usbdev, ep & USB_ENDPOINT_NUMBER_MASK);
	len = sizeof(data);
	
	t1 = p54u_time();
	err = usb_bulk_msg(usbdev, pipe, data, len, &len, HZ);
	t2 = p54u_time();
	t = t2 - t1;
	
	if(err)
		p54u->err = err;
	
	if(debug > 1) {
		printk(KERN_CRIT "[IN  >%-6lld<%-6lld+%-6lld]\t%02x <- 00000000:", t1, t2, t, ep | USB_DIR_IN);
		if(err) {
			printk("failed: %i\n", err);
			return 0;
		}
		for (i = 0; i < len; ++i) {
			printk(" %02x", data[i]);
		}
		printk("\n");
	} else {
		if(err) {
			p54u_err("Register read %02x %04x %08x %08x: failed: %i", ep, port, addr, val, err);
			return 0;
		}
	}
	
	return ((port & P54U_PORT_U32) == P54U_PORT_U32) ? le32_to_cpu(*(u32*)data) : le16_to_cpu(*(u32*)data);
}


u32 p54u_wait_int(struct net_device *netdev)
{
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	u32 reg;
	int err;
	
	wait_for_completion(&p54u->int_rx.comp);
	
	p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0);
	reg = p54u_dev_readl(netdev, ISL38XX_INT_IDENT_REG);
	p54u_dev_writel(netdev, ISL38XX_INT_ACK_REG, reg);
	
	printk("readi: %08x\n", reg);
	
	err = usb_submit_urb(p54u->int_rx.urb[0], GFP_KERNEL);
	if(err)
		p54u_info("int resubmit failed  %i\n", err);

	return reg;
}


void p54u_int_rx_cb(struct urb *urb, struct pt_regs *p)
{
	struct net_device *netdev = urb->context;
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	int err;
	u32 reg;
	u64 t;
	
	t = p54u_time();
	
	p54u_info("Int  %08x\t%d\t\%lld\n", *(int *)urb->transfer_buffer, urb->status, t);
	
	complete(&p54u->int_rx.comp);
//	INIT_COMPLETION(p54u->int_rx.comp);
	
	return;
}

void p54u_data_rx_cb(struct urb *urb, struct pt_regs *p)
{
	struct net_device *netdev = urb->context;
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	int err;
	
	p54u_info("Data  %08x\t%d\n", *(int *)urb->transfer_buffer, urb->status);
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if(err)
		p54u_info("data resubmit failed  %i\n", err);

	
	return;
}

void p54u_mgmt_rx_cb(struct urb *urb, struct pt_regs *p)
{
	struct net_device *netdev = urb->context;
	struct p54u *p54u = netdev_priv(netdev);
	struct usb_device *usbdev = p54u->usbdev;
	unsigned char *data;
	size_t len;
	int err, k, l;
	u64 t;

	p54u_dbg("Mgmt  %d\n", urb->status);
	
	t = p54u_time();
	len = urb->actual_length;
	data = urb->transfer_buffer;
	
	if(debug > 1) {
		for(k = 0; k < len; k+= 16) {
			if(k == 0) {
				printk(KERN_CRIT "[IN  >%-6lld<%-6lld+%-6lld]\t%02x <- 00000000:", 0LL, t, 0LL, 0x82);
			} else {
				printk(KERN_CRIT "\t\t\t\t   -> %08x:", k);
			}
			for (l = 0; (l < 16) && (k + l < len); ++l) {
				printk(" %02x", ((unsigned char *)data)[k + l]);
			}
			printk("\n");
		}
	}
	
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if(err)
		p54u_info("mgmt resubmit failed  %i\n", err);

	
	return;
}


--Multipart=_Sat__3_Apr_2004_11_00_23_+0200_qXiU4ylBeKckvszz--