[Prism54-devel] prism54-usb firmware loading
Helmar Spangenberg
hspangenberg@frey.de
Tue, 1 Jun 2004 07:00:25 +0200
--Boundary-00=_p1AvACddcg0Aur4
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Hello Feyd,
since I am not willing to accept that Linux can't control devices Windows is
able to (I am rather angry to have bought USB dongles for WLAN which do not
work with Linux), I spent the last 2 days digging through the Linux USB code
to find the reason for the HC-crash during firmware upload.
I finally came to the conclusion that the problem may be related to the
userspace/kernelspace issue. I added a "memcpy" to fetch chunks of the
firmware into local memory of prism54u before it is sent via usb_bulk_msg.
This seemed to help. At least, I found the complete firmware code printed out
in the kernel log messages; and even the LED on the dongle showed a reaction
(at least sometimes; usually it is turned off, but once it began to blink
like under Windows when it is seeking for an access point).
I will append the modified usb_init.c (which originally was downloaded from
the prism54 CVS); I marked my changes with "hks". Since I use those Medion
dongles, I included their id's in the p54u_table, too.
Unfortunately, it is now much more complicated to rmmod the driver, since now
the network system claims it..... ;-(.
Helmar
--Boundary-00=_p1AvACddcg0Aur4
Content-Type: text/x-csrc;
charset="us-ascii";
name="usb_init.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="usb_init.c"
/*
* 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 */
{USB_DEVICE(0x0cde, 0x0006)}, /* Linksys Medion (hks) */
{}
};
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 = 0;
u32 reg;
// 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;
do_err:
p54u_err("%s: Reset USB device failed.\n", netdev->name);
return err;
}
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, 6);
// 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, NET2280_GPIOCTL);
//reg = 0x3e;
//reg |= 0x3e;
p54u_brg_writel(netdev, NET2280_GPIOCTL, (reg | P54U_BRG_POWER_DOWN) & ~P54U_BRG_POWER_UP);
if(p54u->err)
goto do_err;
p54u_mdelay(100);
p54u_brg_writel(netdev, NET2280_GPIOCTL, (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, NET2280_DEVINIT, NET2280_CLK_30Mhz | NET2280_PCI_ENABLE | NET2280_PCI_SOFT_RESET);
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, NET2280_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, NET2280_RELNUM);
p54u_dbg("%s: Setup bridge pci resources done\n", netdev->name);
/* Magic */
p54u_dbg("%s: Magic 2\n", netdev->name);
p54u_brg_writel(netdev, NET2280_EPA_RSP, NET2280_CLEAR_NAK_OUT_PACKETS_MODE);
p54u_brg_writel(netdev, NET2280_EPC_RSP, NET2280_CLEAR_NAK_OUT_PACKETS_MODE);
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, NET2280_BASE2);
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));
// p54u_pcicfg_dev_writew(netdev, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
/* Set TRDY_TIMEOUT and RETRY_TIMEOUT to 0 */
p54u_pcicfg_dev_writew(netdev, P54U_TRDY_TIMEOUT | 0x10000, 0);
// p54u_pcicfg_dev_writew(netdev, P54U_TRDY_TIMEOUT, 0);
/* Set base address 0 */
p54u_pcicfg_dev_writel(netdev, PCI_BASE_ADDRESS_0 | 0x10000, P54U_DEV_BASE);
// p54u_pcicfg_dev_writel(netdev, PCI_BASE_ADDRESS_0, 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, NET2280_USBIRQENB1, 0);
// p54u_brg_writel(netdev, NET2280_USBIRQENB1, NET2280_PCI_INTA_INTERRUPT_ENABLE | NET2280_USB_INTERRUPT_ENABLE);
p54u_brg_writel(netdev, NET2280_IRQSTAT1, NET2280_PCI_INTA_INTERRUPT);
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);
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_dev_writel(netdev, ISL38XX_INT_EN_REG, 0x00004004);
p54u_dbg("%s: Disable irq done\n", netdev->name);
// p54u_mdelay(50);
/* 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);
/* Magic */
p54u_dbg("%s: Magic 4\n", netdev->name);
p54u_brg_writel(netdev, NET2280_EPA_STAT, NET2280_FIFO_FLUSH);
p54u_brg_writel(netdev, NET2280_EPB_STAT, NET2280_FIFO_FLUSH);
p54u_brg_writel(netdev, NET2280_EPC_STAT, NET2280_FIFO_FLUSH);
p54u_brg_writel(netdev, NET2280_EPD_STAT, NET2280_FIFO_FLUSH);
p54u_brg_writel(netdev, NET2280_EPA_STAT, NET2280_FIFO_FLUSH);
p54u_dbg("%s: Magic 4 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;
unsigned char hksdata[512]; // temporary buffer in kernel space (hks)
p54u_info("%s: Load firmware.\n", netdev->name);
/* Firmware */
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();
memcpy(hksdata,data,len); // Copying data from userland? (hks)
p54u->err = usb_bulk_msg(usbdev, pipe, hksdata, len, &len, HZ);
t2 = p54u_time();
t = t2 - t1;
p54u_data_debug(netdev, P54U_PIPE_DATA, data, len);
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, NET2280_EPA_STAT, NET2280_FIFO_FLUSH);
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;
}
reg = p54u_dev_readl(netdev, ISL38XX_CTRL_STAT_REG);
// reg |= ISL38XX_CTRL_STAT_RAMBOOT | ISL38XX_CTRL_STAT_CLKRUN;
reg |= ISL38XX_CTRL_STAT_RAMBOOT;
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) {
p54u_dbg("%s: Error latching reset: %i\n", netdev->name, p54u->err);
}
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, rst = 0;
int i, j, k, pending, 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, 0x80004004);
p54u_brg_writel(netdev, NET2280_IRQSTAT1, NET2280_PCI_INTA_INTERRUPT);
p54u_brg_writel(netdev, NET2280_USBIRQENB1, NET2280_PCI_INTA_INTERRUPT_ENABLE | NET2280_USB_INTERRUPT_ENABLE);
// p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0xffffffff);
// p54u_dev_writel(netdev, ISL38XX_DEV_INT_REG, ISL38XX_DEV_INT_RESET | ISL38XX_DEV_INT_WAKEUP);
p54u_dev_writel(netdev, ISL38XX_DEV_INT_REG, ISL38XX_DEV_INT_RESET);
do {
pending = p54u_wait_int(netdev);
p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0);
/* while((reg = p54u_dev_readl(netdev, ISL38XX_INT_IDENT_REG))) {
p54u_info("int: %08x\n", reg);
p54u_dev_writel(netdev, ISL38XX_INT_ACK_REG, reg);
}
*/ reg = p54u_dev_readl(netdev, ISL38XX_INT_IDENT_REG);
p54u_dev_writel(netdev, ISL38XX_INT_ACK_REG, reg);
p54u_brg_writel(netdev, NET2280_IRQSTAT1, NET2280_PCI_INTA_INTERRUPT);
p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0x80004004);
// p54u_dev_writel(netdev, ISL38XX_INT_EN_REG, 0xffffffff);
// reg = p54u_brg_readl(netdev, NET2280_IRQSTAT1);
err = usb_submit_urb(p54u->int_rx.urb[0], GFP_KERNEL);
if(err) {
p54u_info("int resubmit failed %i\n", err);
break;
}
} while(pending);
/* 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);
--Boundary-00=_p1AvACddcg0Aur4--