summaryrefslogtreecommitdiff
path: root/drivers/staging/ft1000/ft1000-usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/ft1000/ft1000-usb')
-rw-r--r--drivers/staging/ft1000/ft1000-usb/Makefile3
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_debug.c783
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_download.c1229
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c1948
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h107
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_proc.c238
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.c263
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.h155
8 files changed, 4726 insertions, 0 deletions
diff --git a/drivers/staging/ft1000/ft1000-usb/Makefile b/drivers/staging/ft1000/ft1000-usb/Makefile
new file mode 100644
index 00000000..f0f52401
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FT1000_USB) += ft1000.o
+
+ft1000-y := ft1000_debug.o ft1000_download.o ft1000_hw.o ft1000_proc.o ft1000_usb.o
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c
new file mode 100644
index 00000000..3251d2e0
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c
@@ -0,0 +1,783 @@
+//---------------------------------------------------------------------------
+// FT1000 driver for Flarion Flash OFDM NIC Device
+//
+// Copyright (C) 2006 Flarion Technologies, All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 of the License, or (at your option) any
+// later version. This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details. You should have received a copy of the GNU General Public
+// License along with this program; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place -
+// Suite 330, Boston, MA 02111-1307, USA.
+//---------------------------------------------------------------------------
+//
+// File: ft1000_chdev.c
+//
+// Description: Custom character device dispatch routines.
+//
+// History:
+// 8/29/02 Whc Ported to Linux.
+// 6/05/06 Whc Porting to Linux 2.6.9
+//
+//---------------------------------------------------------------------------
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+
+#include <linux/ioctl.h>
+#include <linux/debugfs.h>
+#include "ft1000_usb.h"
+
+static int ft1000_flarion_cnt = 0;
+
+static int ft1000_open (struct inode *inode, struct file *file);
+static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait);
+static long ft1000_ioctl(struct file *file, unsigned int command,
+ unsigned long argument);
+static int ft1000_release (struct inode *inode, struct file *file);
+
+// List to free receive command buffer pool
+struct list_head freercvpool;
+
+// lock to arbitrate free buffer list for receive command data
+spinlock_t free_buff_lock;
+
+int numofmsgbuf = 0;
+
+//
+// Table of entry-point routines for char device
+//
+static const struct file_operations ft1000fops =
+{
+ .unlocked_ioctl = ft1000_ioctl,
+ .poll = ft1000_poll_dev,
+ .open = ft1000_open,
+ .release = ft1000_release,
+ .llseek = no_llseek,
+};
+
+//---------------------------------------------------------------------------
+// Function: ft1000_get_buffer
+//
+// Parameters:
+//
+// Returns:
+//
+// Description:
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist)
+{
+ unsigned long flags;
+ struct dpram_blk *ptr;
+
+ spin_lock_irqsave(&free_buff_lock, flags);
+ // Check if buffer is available
+ if ( list_empty(bufflist) ) {
+ DEBUG("ft1000_get_buffer: No more buffer - %d\n", numofmsgbuf);
+ ptr = NULL;
+ }
+ else {
+ numofmsgbuf--;
+ ptr = list_entry(bufflist->next, struct dpram_blk, list);
+ list_del(&ptr->list);
+ //DEBUG("ft1000_get_buffer: number of free msg buffers = %d\n", numofmsgbuf);
+ }
+ spin_unlock_irqrestore(&free_buff_lock, flags);
+
+ return ptr;
+}
+
+
+
+
+//---------------------------------------------------------------------------
+// Function: ft1000_free_buffer
+//
+// Parameters:
+//
+// Returns:
+//
+// Description:
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&free_buff_lock, flags);
+ // Put memory back to list
+ list_add_tail(&pdpram_blk->list, plist);
+ numofmsgbuf++;
+ //DEBUG("ft1000_free_buffer: number of free msg buffers = %d\n", numofmsgbuf);
+ spin_unlock_irqrestore(&free_buff_lock, flags);
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_CreateDevice
+//
+// Parameters: dev - pointer to adapter object
+//
+// Returns: 0 if successful
+//
+// Description: Creates a private char device.
+//
+// Notes: Only called by init_module().
+//
+//---------------------------------------------------------------------------
+int ft1000_create_dev(struct ft1000_usb *dev)
+{
+ int result;
+ int i;
+ struct dentry *dir, *file;
+ struct ft1000_debug_dirs *tmp;
+
+ // make a new device name
+ sprintf(dev->DeviceName, "%s%d", "FT1000_", dev->CardNumber);
+
+ DEBUG("%s: number of instance = %d\n", __func__, ft1000_flarion_cnt);
+ DEBUG("DeviceCreated = %x\n", dev->DeviceCreated);
+
+ if (dev->DeviceCreated)
+ {
+ DEBUG("%s: \"%s\" already registered\n", __func__, dev->DeviceName);
+ return -EIO;
+ }
+
+
+ // register the device
+ DEBUG("%s: \"%s\" debugfs device registration\n", __func__, dev->DeviceName);
+
+ tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL);
+ if (tmp == NULL) {
+ result = -1;
+ goto fail;
+ }
+
+ dir = debugfs_create_dir(dev->DeviceName, NULL);
+ if (IS_ERR(dir)) {
+ result = PTR_ERR(dir);
+ goto debug_dir_fail;
+ }
+
+ file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir,
+ dev, &ft1000fops);
+ if (IS_ERR(file)) {
+ result = PTR_ERR(file);
+ goto debug_file_fail;
+ }
+
+ tmp->dent = dir;
+ tmp->file = file;
+ tmp->int_number = dev->CardNumber;
+ list_add(&(tmp->list), &(dev->nodes.list));
+
+ DEBUG("%s: registered debugfs directory \"%s\"\n", __func__, dev->DeviceName);
+
+ // initialize application information
+ dev->appcnt = 0;
+ for (i=0; i<MAX_NUM_APP; i++) {
+ dev->app_info[i].nTxMsg = 0;
+ dev->app_info[i].nRxMsg = 0;
+ dev->app_info[i].nTxMsgReject = 0;
+ dev->app_info[i].nRxMsgMiss = 0;
+ dev->app_info[i].fileobject = NULL;
+ dev->app_info[i].app_id = i+1;
+ dev->app_info[i].DspBCMsgFlag = 0;
+ dev->app_info[i].NumOfMsg = 0;
+ init_waitqueue_head(&dev->app_info[i].wait_dpram_msg);
+ INIT_LIST_HEAD (&dev->app_info[i].app_sqlist);
+ }
+
+ dev->DeviceCreated = TRUE;
+ ft1000_flarion_cnt++;
+
+ return 0;
+
+debug_file_fail:
+ debugfs_remove(dir);
+debug_dir_fail:
+ kfree(tmp);
+fail:
+ return result;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_DestroyDeviceDEBUG
+//
+// Parameters: dev - pointer to adapter object
+//
+// Description: Destroys a private char device.
+//
+// Notes: Only called by cleanup_module().
+//
+//---------------------------------------------------------------------------
+void ft1000_destroy_dev(struct net_device *netdev)
+{
+ struct ft1000_info *info = netdev_priv(netdev);
+ struct ft1000_usb *dev = info->priv;
+ int i;
+ struct dpram_blk *pdpram_blk;
+ struct dpram_blk *ptr;
+ struct list_head *pos, *q;
+ struct ft1000_debug_dirs *dir;
+
+ DEBUG("%s called\n", __func__);
+
+
+
+ if (dev->DeviceCreated)
+ {
+ ft1000_flarion_cnt--;
+ list_for_each_safe(pos, q, &dev->nodes.list) {
+ dir = list_entry(pos, struct ft1000_debug_dirs, list);
+ if (dir->int_number == dev->CardNumber) {
+ debugfs_remove(dir->file);
+ debugfs_remove(dir->dent);
+ list_del(pos);
+ kfree(dir);
+ }
+ }
+ DEBUG("%s: unregistered device \"%s\"\n", __func__,
+ dev->DeviceName);
+
+ // Make sure we free any memory reserve for slow Queue
+ for (i=0; i<MAX_NUM_APP; i++) {
+ while (list_empty(&dev->app_info[i].app_sqlist) == 0) {
+ pdpram_blk = list_entry(dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
+ list_del(&pdpram_blk->list);
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+
+ }
+ wake_up_interruptible(&dev->app_info[i].wait_dpram_msg);
+ }
+
+ // Remove buffer allocated for receive command data
+ if (ft1000_flarion_cnt == 0) {
+ while (list_empty(&freercvpool) == 0) {
+ ptr = list_entry(freercvpool.next, struct dpram_blk, list);
+ list_del(&ptr->list);
+ kfree(ptr->pbuffer);
+ kfree(ptr);
+ }
+ }
+ dev->DeviceCreated = FALSE;
+ }
+
+
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_open
+//
+// Parameters:
+//
+// Description:
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static int ft1000_open (struct inode *inode, struct file *file)
+{
+ struct ft1000_info *info;
+ struct ft1000_usb *dev = (struct ft1000_usb *)inode->i_private;
+ int i,num;
+
+ DEBUG("%s called\n", __func__);
+ num = (MINOR(inode->i_rdev) & 0xf);
+ DEBUG("ft1000_open: minor number=%d\n", num);
+
+ info = file->private_data = netdev_priv(dev->net);
+
+ DEBUG("f_owner = %p number of application = %d\n", (&file->f_owner), dev->appcnt );
+
+ // Check if maximum number of application exceeded
+ if (dev->appcnt > MAX_NUM_APP) {
+ DEBUG("Maximum number of application exceeded\n");
+ return -EACCES;
+ }
+
+ // Search for available application info block
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if ( (dev->app_info[i].fileobject == NULL) ) {
+ break;
+ }
+ }
+
+ // Fail due to lack of application info block
+ if (i == MAX_NUM_APP) {
+ DEBUG("Could not find an application info block\n");
+ return -EACCES;
+ }
+
+ dev->appcnt++;
+ dev->app_info[i].fileobject = &file->f_owner;
+ dev->app_info[i].nTxMsg = 0;
+ dev->app_info[i].nRxMsg = 0;
+ dev->app_info[i].nTxMsgReject = 0;
+ dev->app_info[i].nRxMsgMiss = 0;
+
+ nonseekable_open(inode, file);
+ return 0;
+}
+
+
+//---------------------------------------------------------------------------
+// Function: ft1000_poll_dev
+//
+// Parameters:
+//
+// Description:
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+
+static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait)
+{
+ struct net_device *netdev = file->private_data;
+ struct ft1000_info *info = netdev_priv(netdev);
+ struct ft1000_usb *dev = info->priv;
+ int i;
+
+ //DEBUG("ft1000_poll_dev called\n");
+ if (ft1000_flarion_cnt == 0) {
+ DEBUG("FT1000:ft1000_poll_dev called when ft1000_flarion_cnt is zero\n");
+ return (-EBADF);
+ }
+
+ // Search for matching file object
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if ( dev->app_info[i].fileobject == &file->f_owner) {
+ //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", dev->app_info[i].app_id);
+ break;
+ }
+ }
+
+ // Could not find application info block
+ if (i == MAX_NUM_APP) {
+ DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n");
+ return ( -EACCES );
+ }
+
+ if (list_empty(&dev->app_info[i].app_sqlist) == 0) {
+ DEBUG("FT1000:ft1000_poll_dev:Message detected in slow queue\n");
+ return(POLLIN | POLLRDNORM | POLLPRI);
+ }
+
+ poll_wait (file, &dev->app_info[i].wait_dpram_msg, wait);
+ //DEBUG("FT1000:ft1000_poll_dev:Polling for data from DSP\n");
+
+ return (0);
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_ioctl
+//
+// Parameters:
+//
+// Description:
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static long ft1000_ioctl (struct file *file, unsigned int command,
+ unsigned long argument)
+{
+ void __user *argp = (void __user *)argument;
+ struct ft1000_info *info;
+ struct ft1000_usb *ft1000dev;
+ int result=0;
+ int cmd;
+ int i;
+ u16 tempword;
+ unsigned long flags;
+ struct timeval tv;
+ IOCTL_GET_VER get_ver_data;
+ IOCTL_GET_DSP_STAT get_stat_data;
+ u8 ConnectionMsg[] = {0x00,0x44,0x10,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x93,0x64,
+ 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x02,0x37,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x7f,0x00,
+ 0x00,0x01,0x00,0x00};
+
+ unsigned short ledStat=0;
+ unsigned short conStat=0;
+
+ //DEBUG("ft1000_ioctl called\n");
+
+ if (ft1000_flarion_cnt == 0) {
+ DEBUG("FT1000:ft1000_ioctl called when ft1000_flarion_cnt is zero\n");
+ return (-EBADF);
+ }
+
+ //DEBUG("FT1000:ft1000_ioctl:command = 0x%x argument = 0x%8x\n", command, (u32)argument);
+
+ info = file->private_data;
+ ft1000dev = info->priv;
+ cmd = _IOC_NR(command);
+ //DEBUG("FT1000:ft1000_ioctl:cmd = 0x%x\n", cmd);
+
+ // process the command
+ switch (cmd) {
+ case IOCTL_REGISTER_CMD:
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_REGISTER called\n");
+ result = get_user(tempword, (__u16 __user*)argp);
+ if (result) {
+ DEBUG("result = %d failed to get_user\n", result);
+ break;
+ }
+ if (tempword == DSPBCMSGID) {
+ // Search for matching file object
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
+ ft1000dev->app_info[i].DspBCMsgFlag = 1;
+ DEBUG("FT1000:ft1000_ioctl:Registered for broadcast messages\n");
+ break;
+ }
+ }
+ }
+ break;
+
+ case IOCTL_GET_VER_CMD:
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_VER called\n");
+
+ get_ver_data.drv_ver = FT1000_DRV_VER;
+
+ if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data)) ) {
+ DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n");
+ result = -EFAULT;
+ break;
+ }
+
+ DEBUG("FT1000:ft1000_ioctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver);
+
+ break;
+ case IOCTL_CONNECT:
+ // Connect Message
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_CONNECT\n");
+ ConnectionMsg[79] = 0xfc;
+ card_send_command(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
+
+ break;
+ case IOCTL_DISCONNECT:
+ // Disconnect Message
+ DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_DISCONNECT\n");
+ ConnectionMsg[79] = 0xfd;
+ card_send_command(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c);
+ break;
+ case IOCTL_GET_DSP_STAT_CMD:
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DSP_STAT called\n");
+ memset(&get_stat_data, 0, sizeof(get_stat_data));
+ memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ);
+ memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ);
+ memcpy(get_stat_data.Sku, info->Sku, SKUSZ);
+ memcpy(get_stat_data.eui64, info->eui64, EUISZ);
+
+ if (info->ProgConStat != 0xFF) {
+ ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
+ get_stat_data.LedStat = ntohs(ledStat);
+ DEBUG("FT1000:ft1000_ioctl: LedStat = 0x%x\n", get_stat_data.LedStat);
+ ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
+ get_stat_data.ConStat = ntohs(conStat);
+ DEBUG("FT1000:ft1000_ioctl: ConStat = 0x%x\n", get_stat_data.ConStat);
+ }
+ else {
+ get_stat_data.ConStat = 0x0f;
+ }
+
+
+ get_stat_data.nTxPkts = info->stats.tx_packets;
+ get_stat_data.nRxPkts = info->stats.rx_packets;
+ get_stat_data.nTxBytes = info->stats.tx_bytes;
+ get_stat_data.nRxBytes = info->stats.rx_bytes;
+ do_gettimeofday ( &tv );
+ get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm);
+ DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm);
+ if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data)) ) {
+ DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n");
+ result = -EFAULT;
+ break;
+ }
+ DEBUG("ft1000_chioctl: GET_DSP_STAT succeed\n");
+ break;
+ case IOCTL_SET_DPRAM_CMD:
+ {
+ IOCTL_DPRAM_BLK *dpram_data = NULL;
+ //IOCTL_DPRAM_COMMAND dpram_command;
+ u16 qtype;
+ u16 msgsz;
+ struct pseudo_hdr *ppseudo_hdr;
+ u16 *pmsg;
+ u16 total_len;
+ u16 app_index;
+ u16 status;
+
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_SET_DPRAM called\n");
+
+
+ if (ft1000_flarion_cnt == 0) {
+ return (-EBADF);
+ }
+
+ if (ft1000dev->DrvMsgPend) {
+ return (-ENOTTY);
+ }
+
+ if (ft1000dev->fProvComplete == 0) {
+ return (-EACCES);
+ }
+
+ ft1000dev->fAppMsgPend = 1;
+
+ if (info->CardReady) {
+
+ //DEBUG("FT1000:ft1000_ioctl: try to SET_DPRAM \n");
+
+ // Get the length field to see how many bytes to copy
+ result = get_user(msgsz, (__u16 __user *)argp);
+ msgsz = ntohs (msgsz);
+ //DEBUG("FT1000:ft1000_ioctl: length of message = %d\n", msgsz);
+
+ if (msgsz > MAX_CMD_SQSIZE) {
+ DEBUG("FT1000:ft1000_ioctl: bad message length = %d\n", msgsz);
+ result = -EINVAL;
+ break;
+ }
+
+ result = -ENOMEM;
+ dpram_data = kmalloc(msgsz + 2, GFP_KERNEL);
+ if (!dpram_data)
+ break;
+
+ if ( copy_from_user(dpram_data, argp, msgsz+2) ) {
+ DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n");
+ result = -EFAULT;
+ }
+ else {
+ // Check if this message came from a registered application
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
+ break;
+ }
+ }
+ if (i==MAX_NUM_APP) {
+ DEBUG("FT1000:No matching application fileobject\n");
+ result = -EINVAL;
+ kfree(dpram_data);
+ break;
+ }
+ app_index = i;
+
+ // Check message qtype type which is the lower byte within qos_class
+ qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff;
+ //DEBUG("FT1000_ft1000_ioctl: qtype = %d\n", qtype);
+ if (qtype) {
+ }
+ else {
+ // Put message into Slow Queue
+ // Only put a message into the DPRAM if msg doorbell is available
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
+ //DEBUG("FT1000_ft1000_ioctl: READ REGISTER tempword=%x\n", tempword);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ // Suspend for 2ms and try again due to DSP doorbell busy
+ mdelay(2);
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ // Suspend for 1ms and try again due to DSP doorbell busy
+ mdelay(1);
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ // Suspend for 3ms and try again due to DSP doorbell busy
+ mdelay(3);
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ DEBUG("FT1000:ft1000_ioctl:Doorbell not available\n");
+ result = -ENOTTY;
+ kfree(dpram_data);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //DEBUG("FT1000_ft1000_ioctl: finished reading register\n");
+
+ // Make sure we are within the limits of the slow queue memory limitation
+ if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) {
+ // Need to put sequence number plus new checksum for message
+ pmsg = (u16 *)&dpram_data->pseudohdr;
+ ppseudo_hdr = (struct pseudo_hdr *)pmsg;
+ total_len = msgsz+2;
+ if (total_len & 0x1) {
+ total_len++;
+ }
+
+ // Insert slow queue sequence number
+ ppseudo_hdr->seq_num = info->squeseqnum++;
+ ppseudo_hdr->portsrc = ft1000dev->app_info[app_index].app_id;
+ // Calculate new checksum
+ ppseudo_hdr->checksum = *pmsg++;
+ //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum);
+ for (i=1; i<7; i++) {
+ ppseudo_hdr->checksum ^= *pmsg++;
+ //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum);
+ }
+ pmsg++;
+ ppseudo_hdr = (struct pseudo_hdr *)pmsg;
+ card_send_command(ft1000dev,(unsigned short*)dpram_data,total_len+2);
+
+
+ ft1000dev->app_info[app_index].nTxMsg++;
+ }
+ else {
+ result = -EINVAL;
+ }
+ }
+ }
+ }
+ else {
+ DEBUG("FT1000:ft1000_ioctl: Card not ready take messages\n");
+ result = -EACCES;
+ }
+ kfree(dpram_data);
+
+ }
+ break;
+ case IOCTL_GET_DPRAM_CMD:
+ {
+ struct dpram_blk *pdpram_blk;
+ IOCTL_DPRAM_BLK __user *pioctl_dpram;
+ int msglen;
+
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM called\n");
+
+ if (ft1000_flarion_cnt == 0) {
+ return (-EBADF);
+ }
+
+ // Search for matching file object
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if (ft1000dev->app_info[i].fileobject == &file->f_owner) {
+ //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", ft1000dev->app_info[i].app_id);
+ break;
+ }
+ }
+
+ // Could not find application info block
+ if (i == MAX_NUM_APP) {
+ DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n");
+ result = -EBADF;
+ break;
+ }
+
+ result = 0;
+ pioctl_dpram = argp;
+ if (list_empty(&ft1000dev->app_info[i].app_sqlist) == 0) {
+ //DEBUG("FT1000:ft1000_ioctl:Message detected in slow queue\n");
+ spin_lock_irqsave(&free_buff_lock, flags);
+ pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
+ list_del(&pdpram_blk->list);
+ ft1000dev->app_info[i].NumOfMsg--;
+ //DEBUG("FT1000:ft1000_ioctl:NumOfMsg for app %d = %d\n", i, ft1000dev->app_info[i].NumOfMsg);
+ spin_unlock_irqrestore(&free_buff_lock, flags);
+ msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ;
+ result = get_user(msglen, &pioctl_dpram->total_len);
+ if (result)
+ break;
+ msglen = htons(msglen);
+ //DEBUG("FT1000:ft1000_ioctl:msg length = %x\n", msglen);
+ if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen))
+ {
+ DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n");
+ result = -EFAULT;
+ break;
+ }
+
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+ result = msglen;
+ }
+ //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM no message\n");
+ }
+ break;
+
+ default:
+ DEBUG("FT1000:ft1000_ioctl:unknown command: 0x%x\n", command);
+ result = -ENOTTY;
+ break;
+ }
+ ft1000dev->fAppMsgPend = 0;
+ return result;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_release
+//
+// Parameters:
+//
+// Description:
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static int ft1000_release (struct inode *inode, struct file *file)
+{
+ struct ft1000_info *info;
+ struct net_device *dev;
+ struct ft1000_usb *ft1000dev;
+ int i;
+ struct dpram_blk *pdpram_blk;
+
+ DEBUG("ft1000_release called\n");
+
+ dev = file->private_data;
+ info = netdev_priv(dev);
+ ft1000dev = info->priv;
+
+ if (ft1000_flarion_cnt == 0) {
+ ft1000dev->appcnt--;
+ return (-EBADF);
+ }
+
+ // Search for matching file object
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if ( ft1000dev->app_info[i].fileobject == &file->f_owner) {
+ //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", ft1000dev->app_info[i].app_id);
+ break;
+ }
+ }
+
+ if (i==MAX_NUM_APP)
+ return 0;
+
+ while (list_empty(&ft1000dev->app_info[i].app_sqlist) == 0) {
+ DEBUG("Remove and free memory queue up on slow queue\n");
+ pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, struct dpram_blk, list);
+ list_del(&pdpram_blk->list);
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+ }
+
+ // initialize application information
+ ft1000dev->appcnt--;
+ DEBUG("ft1000_chdev:%s:appcnt = %d\n", __FUNCTION__, ft1000dev->appcnt);
+ ft1000dev->app_info[i].fileobject = NULL;
+
+ return 0;
+}
+
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c
new file mode 100644
index 00000000..5190c8ac
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c
@@ -0,0 +1,1229 @@
+//=====================================================
+// CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved.
+//
+//
+// This file is part of Express Card USB Driver
+//
+// $Id:
+//====================================================
+// 20090926; aelias; removed compiler warnings; ubuntu 9.04; 2.6.28-15-generic
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include "ft1000_usb.h"
+
+
+#define DWNLD_HANDSHAKE_LOC 0x02
+#define DWNLD_TYPE_LOC 0x04
+#define DWNLD_SIZE_MSW_LOC 0x06
+#define DWNLD_SIZE_LSW_LOC 0x08
+#define DWNLD_PS_HDR_LOC 0x0A
+
+#define MAX_DSP_WAIT_LOOPS 40
+#define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */
+#define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */
+
+#define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
+#define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
+#define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */
+#define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
+#define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* At start DSP writes this when bootloader ready */
+#define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
+#define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
+
+#define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
+#define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
+
+#define REQUEST_CODE_LENGTH 0x0000
+#define REQUEST_RUN_ADDRESS 0x0001
+#define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
+#define REQUEST_DONE_BL 0x0003
+#define REQUEST_DONE_CL 0x0004
+#define REQUEST_VERSION_INFO 0x0005
+#define REQUEST_CODE_BY_VERSION 0x0006
+#define REQUEST_MAILBOX_DATA 0x0007
+#define REQUEST_FILE_CHECKSUM 0x0008
+
+#define STATE_START_DWNLD 0x01
+#define STATE_BOOT_DWNLD 0x02
+#define STATE_CODE_DWNLD 0x03
+#define STATE_DONE_DWNLD 0x04
+#define STATE_SECTION_PROV 0x05
+#define STATE_DONE_PROV 0x06
+#define STATE_DONE_FILE 0x07
+
+#define MAX_LENGTH 0x7f0
+
+// Temporary download mechanism for Magnemite
+#define DWNLD_MAG_TYPE_LOC 0x00
+#define DWNLD_MAG_LEN_LOC 0x01
+#define DWNLD_MAG_ADDR_LOC 0x02
+#define DWNLD_MAG_CHKSUM_LOC 0x03
+#define DWNLD_MAG_VAL_LOC 0x04
+
+#define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */
+#define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */
+#define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */
+#define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */
+
+#define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */
+#define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */
+#define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */
+
+#define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1
+
+
+// New Magnemite downloader
+#define DWNLD_MAG1_HANDSHAKE_LOC 0x00
+#define DWNLD_MAG1_TYPE_LOC 0x01
+#define DWNLD_MAG1_SIZE_LOC 0x02
+#define DWNLD_MAG1_PS_HDR_LOC 0x03
+
+struct dsp_file_hdr {
+ long version_id; // Version ID of this image format.
+ long package_id; // Package ID of code release.
+ long build_date; // Date/time stamp when file was built.
+ long commands_offset; // Offset to attached commands in Pseudo Hdr format.
+ long loader_offset; // Offset to bootloader code.
+ long loader_code_address; // Start address of bootloader.
+ long loader_code_end; // Where bootloader code ends.
+ long loader_code_size;
+ long version_data_offset; // Offset were scrambled version data begins.
+ long version_data_size; // Size, in words, of scrambled version data.
+ long nDspImages; // Number of DSP images in file.
+};
+
+#pragma pack(1)
+struct dsp_image_info {
+ long coff_date; // Date/time when DSP Coff image was built.
+ long begin_offset; // Offset in file where image begins.
+ long end_offset; // Offset in file where image begins.
+ long run_address; // On chip Start address of DSP code.
+ long image_size; // Size of image.
+ long version; // Embedded version # of DSP code.
+ unsigned short checksum; // DSP File checksum
+ unsigned short pad1;
+};
+
+
+//---------------------------------------------------------------------------
+// Function: check_usb_db
+//
+// Parameters: struct ft1000_usb - device structure
+//
+// Returns: 0 - success
+//
+// Description: This function checks if the doorbell register is cleared
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static u32 check_usb_db (struct ft1000_usb *ft1000dev)
+{
+ int loopcnt;
+ u16 temp;
+ u32 status;
+
+ loopcnt = 0;
+
+ while (loopcnt < 10) {
+ status = ft1000_read_register(ft1000dev, &temp,
+ FT1000_REG_DOORBELL);
+ DEBUG("check_usb_db: read FT1000_REG_DOORBELL value is %x\n",
+ temp);
+ if (temp & 0x0080) {
+ DEBUG("FT1000:Got checkusb doorbell\n");
+ status = ft1000_write_register(ft1000dev, 0x0080,
+ FT1000_REG_DOORBELL);
+ status = ft1000_write_register(ft1000dev, 0x0100,
+ FT1000_REG_DOORBELL);
+ status = ft1000_write_register(ft1000dev, 0x8000,
+ FT1000_REG_DOORBELL);
+ break;
+ } else {
+ loopcnt++;
+ msleep(10);
+ }
+
+ }
+
+ loopcnt = 0;
+ while (loopcnt < 20) {
+ status = ft1000_read_register(ft1000dev, &temp,
+ FT1000_REG_DOORBELL);
+ DEBUG("FT1000:check_usb_db:Doorbell = 0x%x\n", temp);
+ if (temp & 0x8000) {
+ loopcnt++;
+ msleep(10);
+ } else {
+ DEBUG("check_usb_db: door bell is cleared, return 0\n");
+ return 0;
+ }
+ }
+
+ return HANDSHAKE_MAG_TIMEOUT_VALUE;
+}
+
+//---------------------------------------------------------------------------
+// Function: get_handshake
+//
+// Parameters: struct ft1000_usb - device structure
+// u16 expected_value - the handshake value expected
+//
+// Returns: handshakevalue - success
+// HANDSHAKE_TIMEOUT_VALUE - failure
+//
+// Description: This function gets the handshake and compare with the expected value
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value)
+{
+ u16 handshake;
+ int loopcnt;
+ u32 status = 0;
+
+ loopcnt = 0;
+
+ while (loopcnt < 100) {
+ /* Need to clear downloader doorbell if Hartley ASIC */
+ status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_RX,
+ FT1000_REG_DOORBELL);
+ if (ft1000dev->fcodeldr) {
+ DEBUG(" get_handshake: fcodeldr is %d\n",
+ ft1000dev->fcodeldr);
+ ft1000dev->fcodeldr = 0;
+ status = check_usb_db(ft1000dev);
+ if (status != STATUS_SUCCESS) {
+ DEBUG("get_handshake: check_usb_db failed\n");
+ status = STATUS_FAILURE;
+ break;
+ }
+ status = ft1000_write_register(ft1000dev,
+ FT1000_DB_DNLD_RX,
+ FT1000_REG_DOORBELL);
+ }
+
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
+ handshake = ntohs(handshake);
+
+ if (status)
+ return HANDSHAKE_TIMEOUT_VALUE;
+
+ if ((handshake == expected_value) ||
+ (handshake == HANDSHAKE_RESET_VALUE_USB)) {
+ return handshake;
+ } else {
+ loopcnt++;
+ msleep(10);
+ }
+ }
+
+ return HANDSHAKE_TIMEOUT_VALUE;
+}
+
+//---------------------------------------------------------------------------
+// Function: put_handshake
+//
+// Parameters: struct ft1000_usb - device structure
+// u16 handshake_value - handshake to be written
+//
+// Returns: none
+//
+// Description: This function write the handshake value to the handshake location
+// in DPRAM
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static void put_handshake(struct ft1000_usb *ft1000dev,u16 handshake_value)
+{
+ u32 tempx;
+ u16 tempword;
+ u32 status;
+
+ tempx = (u32)handshake_value;
+ tempx = ntohl(tempx);
+
+ tempword = (u16)(tempx & 0xffff);
+ status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC,
+ tempword, 0);
+ tempword = (u16)(tempx >> 16);
+ status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC,
+ tempword, 1);
+ status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX,
+ FT1000_REG_DOORBELL);
+}
+
+static u16 get_handshake_usb(struct ft1000_usb *ft1000dev, u16 expected_value)
+{
+ u16 handshake;
+ int loopcnt;
+ u16 temp;
+ u32 status = 0;
+
+ loopcnt = 0;
+ handshake = 0;
+
+ while (loopcnt < 100) {
+ if (ft1000dev->usbboot == 2) {
+ status = ft1000_read_dpram32(ft1000dev, 0,
+ (u8 *)&(ft1000dev->tempbuf[0]), 64);
+ for (temp = 0; temp < 16; temp++) {
+ DEBUG("tempbuf %d = 0x%x\n", temp,
+ ft1000dev->tempbuf[temp]);
+ }
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_HANDSHAKE_LOC,
+ (u8 *)&handshake, 1);
+ DEBUG("handshake from read_dpram16 = 0x%x\n",
+ handshake);
+ if (ft1000dev->dspalive == ft1000dev->tempbuf[6]) {
+ handshake = 0;
+ } else {
+ handshake = ft1000dev->tempbuf[1];
+ ft1000dev->dspalive =
+ ft1000dev->tempbuf[6];
+ }
+ } else {
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_HANDSHAKE_LOC,
+ (u8 *)&handshake, 1);
+ }
+
+ loopcnt++;
+ msleep(10);
+ handshake = ntohs(handshake);
+ if ((handshake == expected_value) ||
+ (handshake == HANDSHAKE_RESET_VALUE_USB))
+ return handshake;
+ }
+
+ return HANDSHAKE_TIMEOUT_VALUE;
+}
+
+static void put_handshake_usb(struct ft1000_usb *ft1000dev,u16 handshake_value)
+{
+ int i;
+
+ for (i=0; i<1000; i++);
+}
+
+//---------------------------------------------------------------------------
+// Function: get_request_type
+//
+// Parameters: struct ft1000_usb - device structure
+//
+// Returns: request type - success
+//
+// Description: This function returns the request type
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static u16 get_request_type(struct ft1000_usb *ft1000dev)
+{
+ u16 request_type;
+ u32 status;
+ u16 tempword;
+ u32 tempx;
+
+ if (ft1000dev->bootmode == 1) {
+ status = fix_ft1000_read_dpram32(ft1000dev,
+ DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
+ tempx = ntohl(tempx);
+ } else {
+ tempx = 0;
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1);
+ tempx |= (tempword << 16);
+ tempx = ntohl(tempx);
+ }
+ request_type = (u16)tempx;
+
+ return request_type;
+}
+
+static u16 get_request_type_usb(struct ft1000_usb *ft1000dev)
+{
+ u16 request_type;
+ u32 status;
+ u16 tempword;
+ u32 tempx;
+
+ if (ft1000dev->bootmode == 1) {
+ status = fix_ft1000_read_dpram32(ft1000dev,
+ DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
+ tempx = ntohl(tempx);
+ } else {
+ if (ft1000dev->usbboot == 2) {
+ tempx = ft1000dev->tempbuf[2];
+ tempword = ft1000dev->tempbuf[3];
+ } else {
+ tempx = 0;
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_TYPE_LOC,
+ (u8 *)&tempword, 1);
+ }
+ tempx |= (tempword << 16);
+ tempx = ntohl(tempx);
+ }
+ request_type = (u16)tempx;
+
+ return request_type;
+}
+
+//---------------------------------------------------------------------------
+// Function: get_request_value
+//
+// Parameters: struct ft1000_usb - device structure
+//
+// Returns: request value - success
+//
+// Description: This function returns the request value
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static long get_request_value(struct ft1000_usb *ft1000dev)
+{
+ u32 value;
+ u16 tempword;
+ u32 status;
+
+ if (ft1000dev->bootmode == 1) {
+ status = fix_ft1000_read_dpram32(ft1000dev,
+ DWNLD_MAG1_SIZE_LOC, (u8 *)&value);
+ value = ntohl(value);
+ } else {
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0);
+ value = tempword;
+ status = ft1000_read_dpram16(ft1000dev,
+ DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1);
+ value |= (tempword << 16);
+ value = ntohl(value);
+ }
+
+ return value;
+}
+
+
+//---------------------------------------------------------------------------
+// Function: put_request_value
+//
+// Parameters: struct ft1000_usb - device structure
+// long lvalue - value to be put into DPRAM location DWNLD_MAG1_SIZE_LOC
+//
+// Returns: none
+//
+// Description: This function writes a value to DWNLD_MAG1_SIZE_LOC
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static void put_request_value(struct ft1000_usb *ft1000dev, long lvalue)
+{
+ u32 tempx;
+ u32 status;
+
+ tempx = ntohl(lvalue);
+ status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC,
+ (u8 *)&tempx);
+}
+
+
+
+//---------------------------------------------------------------------------
+// Function: hdr_checksum
+//
+// Parameters: struct pseudo_hdr *pHdr - Pseudo header pointer
+//
+// Returns: checksum - success
+//
+// Description: This function returns the checksum of the pseudo header
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static u16 hdr_checksum(struct pseudo_hdr *pHdr)
+{
+ u16 *usPtr = (u16 *)pHdr;
+ u16 chksum;
+
+
+ chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
+ usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
+
+ return chksum;
+}
+
+static int check_buffers(u16 *buff_w, u16 *buff_r, int len, int offset)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (buff_w[i] != buff_r[i + offset])
+ return -1;
+ }
+
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+// Function: write_blk
+//
+// Parameters: struct ft1000_usb - device structure
+// u16 **pUsFile - DSP image file pointer in u16
+// u8 **pUcFile - DSP image file pointer in u8
+// long word_length - length of the buffer to be written
+// to DPRAM
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function writes a block of DSP image to DPRAM
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static u32 write_blk (struct ft1000_usb *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length)
+{
+ u32 Status = STATUS_SUCCESS;
+ u16 dpram;
+ int loopcnt, i, j;
+ u16 tempword;
+ u16 tempbuffer[64];
+ u16 resultbuffer[64];
+
+ //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length);
+ dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
+ tempword = *(*pUsFile);
+ (*pUsFile)++;
+ Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0);
+ tempword = *(*pUsFile);
+ (*pUsFile)++;
+ Status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1);
+
+ *pUcFile = *pUcFile + 4;
+ word_length--;
+ tempword = (u16)word_length;
+ word_length = (word_length / 16) + 1;
+ for (; word_length > 0; word_length--) /* In words */
+ {
+ loopcnt = 0;
+
+ for (i=0; i<32; i++)
+ {
+ if (tempword != 0)
+ {
+ tempbuffer[i++] = *(*pUsFile);
+ (*pUsFile)++;
+ tempbuffer[i] = *(*pUsFile);
+ (*pUsFile)++;
+ *pUcFile = *pUcFile + 4;
+ loopcnt++;
+ tempword--;
+ }
+ else
+ {
+ tempbuffer[i++] = 0;
+ tempbuffer[i] = 0;
+ }
+ }
+
+ //DEBUG("write_blk: loopcnt is %d\n", loopcnt);
+ //DEBUG("write_blk: bootmode = %d\n", bootmode);
+ //DEBUG("write_blk: dpram = %x\n", dpram);
+ if (ft1000dev->bootmode == 0)
+ {
+ if (dpram >= 0x3F4)
+ Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 8);
+ else
+ Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
+ }
+ else
+ {
+ for (j=0; j<10; j++)
+ {
+ Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
+ if (Status == STATUS_SUCCESS)
+ {
+ // Work around for ASIC bit stuffing problem.
+ if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
+ {
+ Status = ft1000_write_dpram32(ft1000dev, dpram+12, (u8 *)&tempbuffer[24], 64);
+ }
+ // Let's check the data written
+ Status = ft1000_read_dpram32 (ft1000dev, dpram, (u8 *)&resultbuffer[0], 64);
+ if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
+ {
+ if (check_buffers(tempbuffer, resultbuffer, 28, 0)) {
+ DEBUG("FT1000:download:DPRAM write failed 1 during bootloading\n");
+ msleep(10);
+ Status = STATUS_FAILURE;
+ break;
+ }
+ Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (u8 *)&resultbuffer[0], 64);
+
+ if (check_buffers(tempbuffer, resultbuffer, 16, 24)) {
+ DEBUG("FT1000:download:DPRAM write failed 2 during bootloading\n");
+ msleep(10);
+ Status = STATUS_FAILURE;
+ break;
+ }
+
+ }
+ else
+ {
+ if (check_buffers(tempbuffer, resultbuffer, 32, 0)) {
+ DEBUG("FT1000:download:DPRAM write failed 3 during bootloading\n");
+ msleep(10);
+ Status = STATUS_FAILURE;
+ break;
+ }
+
+ }
+
+ if (Status == STATUS_SUCCESS)
+ break;
+
+ }
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ DEBUG("FT1000:download:Write failed tempbuffer[31] = 0x%x\n", tempbuffer[31]);
+ break;
+ }
+
+ }
+ dpram = dpram + loopcnt;
+ }
+
+ return Status;
+}
+
+static void usb_dnld_complete (struct urb *urb)
+{
+ //DEBUG("****** usb_dnld_complete\n");
+}
+
+//---------------------------------------------------------------------------
+// Function: write_blk_fifo
+//
+// Parameters: struct ft1000_usb - device structure
+// u16 **pUsFile - DSP image file pointer in u16
+// u8 **pUcFile - DSP image file pointer in u8
+// long word_length - length of the buffer to be written
+// to DPRAM
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function writes a block of DSP image to DPRAM
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static u32 write_blk_fifo(struct ft1000_usb *ft1000dev, u16 **pUsFile,
+ u8 **pUcFile, long word_length)
+{
+ u32 Status = STATUS_SUCCESS;
+ int byte_length;
+
+ byte_length = word_length * 4;
+
+ if (byte_length && ((byte_length % 64) == 0))
+ byte_length += 4;
+
+ if (byte_length < 64)
+ byte_length = 68;
+
+ usb_init_urb(ft1000dev->tx_urb);
+ memcpy(ft1000dev->tx_buf, *pUcFile, byte_length);
+ usb_fill_bulk_urb(ft1000dev->tx_urb,
+ ft1000dev->dev,
+ usb_sndbulkpipe(ft1000dev->dev,
+ ft1000dev->bulk_out_endpointAddr),
+ ft1000dev->tx_buf, byte_length, usb_dnld_complete,
+ (void *)ft1000dev);
+
+ usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC);
+
+ *pUsFile = *pUsFile + (word_length << 1);
+ *pUcFile = *pUcFile + (word_length << 2);
+
+ return Status;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: scram_dnldr
+//
+// Synopsis: Scramble downloader for Harley based ASIC via USB interface
+//
+// Arguments: pFileStart - pointer to start of file
+// FileLength - file length
+//
+// Returns: status - return code
+//---------------------------------------------------------------------------
+
+u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart,
+ u32 FileLength)
+{
+ u16 status = STATUS_SUCCESS;
+ u32 state;
+ u16 handshake;
+ struct pseudo_hdr *pseudo_header;
+ u16 pseudo_header_len;
+ long word_length;
+ u16 request;
+ u16 temp;
+ u16 tempword;
+
+ struct dsp_file_hdr *file_hdr;
+ struct dsp_image_info *dsp_img_info = NULL;
+ long requested_version;
+ bool correct_version;
+ struct drv_msg *mailbox_data;
+ u16 *data = NULL;
+ u16 *s_file = NULL;
+ u8 *c_file = NULL;
+ u8 *boot_end = NULL, *code_end = NULL;
+ int image;
+ long loader_code_address, loader_code_size = 0;
+ long run_address = 0, run_size = 0;
+
+ u32 templong;
+ u32 image_chksum = 0;
+
+ u16 dpram = 0;
+ u8 *pbuffer;
+ struct prov_record *pprov_record;
+ struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
+
+ DEBUG("Entered scram_dnldr...\n");
+
+ ft1000dev->fcodeldr = 0;
+ ft1000dev->usbboot = 0;
+ ft1000dev->dspalive = 0xffff;
+
+ //
+ // Get version id of file, at first 4 bytes of file, for newer files.
+ //
+
+ state = STATE_START_DWNLD;
+
+ file_hdr = (struct dsp_file_hdr *)pFileStart;
+
+ ft1000_write_register(ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK);
+
+ s_file = (u16 *) (pFileStart + file_hdr->loader_offset);
+ c_file = (u8 *) (pFileStart + file_hdr->loader_offset);
+
+ boot_end = (u8 *) (pFileStart + file_hdr->loader_code_end);
+
+ loader_code_address = file_hdr->loader_code_address;
+ loader_code_size = file_hdr->loader_code_size;
+ correct_version = FALSE;
+
+ while ((status == STATUS_SUCCESS) && (state != STATE_DONE_FILE)) {
+ switch (state) {
+ case STATE_START_DWNLD:
+ DEBUG("FT1000:STATE_START_DWNLD\n");
+ if (ft1000dev->usbboot)
+ handshake =
+ get_handshake_usb(ft1000dev,
+ HANDSHAKE_DSP_BL_READY);
+ else
+ handshake =
+ get_handshake(ft1000dev,
+ HANDSHAKE_DSP_BL_READY);
+
+ if (handshake == HANDSHAKE_DSP_BL_READY) {
+ DEBUG
+ ("scram_dnldr: handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n");
+ put_handshake(ft1000dev,
+ HANDSHAKE_DRIVER_READY);
+ } else {
+ DEBUG
+ ("FT1000:download:Download error: Handshake failed\n");
+ status = STATUS_FAILURE;
+ }
+
+ state = STATE_BOOT_DWNLD;
+
+ break;
+
+ case STATE_BOOT_DWNLD:
+ DEBUG("FT1000:STATE_BOOT_DWNLD\n");
+ ft1000dev->bootmode = 1;
+ handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST);
+ if (handshake == HANDSHAKE_REQUEST) {
+ /*
+ * Get type associated with the request.
+ */
+ request = get_request_type(ft1000dev);
+ switch (request) {
+ case REQUEST_RUN_ADDRESS:
+ DEBUG("FT1000:REQUEST_RUN_ADDRESS\n");
+ put_request_value(ft1000dev,
+ loader_code_address);
+ break;
+ case REQUEST_CODE_LENGTH:
+ DEBUG("FT1000:REQUEST_CODE_LENGTH\n");
+ put_request_value(ft1000dev,
+ loader_code_size);
+ break;
+ case REQUEST_DONE_BL:
+ DEBUG("FT1000:REQUEST_DONE_BL\n");
+ /* Reposition ptrs to beginning of code section */
+ s_file = (u16 *) (boot_end);
+ c_file = (u8 *) (boot_end);
+ //DEBUG("FT1000:download:s_file = 0x%8x\n", (int)s_file);
+ //DEBUG("FT1000:download:c_file = 0x%8x\n", (int)c_file);
+ state = STATE_CODE_DWNLD;
+ ft1000dev->fcodeldr = 1;
+ break;
+ case REQUEST_CODE_SEGMENT:
+ //DEBUG("FT1000:REQUEST_CODE_SEGMENT\n");
+ word_length =
+ get_request_value(ft1000dev);
+ //DEBUG("FT1000:word_length = 0x%x\n", (int)word_length);
+ //NdisMSleep (100);
+ if (word_length > MAX_LENGTH) {
+ DEBUG
+ ("FT1000:download:Download error: Max length exceeded\n");
+ status = STATUS_FAILURE;
+ break;
+ }
+ if ((word_length * 2 + c_file) >
+ boot_end) {
+ /*
+ * Error, beyond boot code range.
+ */
+ DEBUG
+ ("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundary.\n",
+ (int)word_length);
+ status = STATUS_FAILURE;
+ break;
+ }
+ /*
+ * Position ASIC DPRAM auto-increment pointer.
+ */
+ dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
+ if (word_length & 0x1)
+ word_length++;
+ word_length = word_length / 2;
+
+ status =
+ write_blk(ft1000dev, &s_file,
+ &c_file, word_length);
+ //DEBUG("write_blk returned %d\n", status);
+ break;
+ default:
+ DEBUG
+ ("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n",
+ request);
+ status = STATUS_FAILURE;
+ break;
+ }
+ if (ft1000dev->usbboot)
+ put_handshake_usb(ft1000dev,
+ HANDSHAKE_RESPONSE);
+ else
+ put_handshake(ft1000dev,
+ HANDSHAKE_RESPONSE);
+ } else {
+ DEBUG
+ ("FT1000:download:Download error: Handshake failed\n");
+ status = STATUS_FAILURE;
+ }
+
+ break;
+
+ case STATE_CODE_DWNLD:
+ //DEBUG("FT1000:STATE_CODE_DWNLD\n");
+ ft1000dev->bootmode = 0;
+ if (ft1000dev->usbboot)
+ handshake =
+ get_handshake_usb(ft1000dev,
+ HANDSHAKE_REQUEST);
+ else
+ handshake =
+ get_handshake(ft1000dev, HANDSHAKE_REQUEST);
+ if (handshake == HANDSHAKE_REQUEST) {
+ /*
+ * Get type associated with the request.
+ */
+ if (ft1000dev->usbboot)
+ request =
+ get_request_type_usb(ft1000dev);
+ else
+ request = get_request_type(ft1000dev);
+ switch (request) {
+ case REQUEST_FILE_CHECKSUM:
+ DEBUG
+ ("FT1000:download:image_chksum = 0x%8x\n",
+ image_chksum);
+ put_request_value(ft1000dev,
+ image_chksum);
+ break;
+ case REQUEST_RUN_ADDRESS:
+ DEBUG
+ ("FT1000:download: REQUEST_RUN_ADDRESS\n");
+ if (correct_version) {
+ DEBUG
+ ("FT1000:download:run_address = 0x%8x\n",
+ (int)run_address);
+ put_request_value(ft1000dev,
+ run_address);
+ } else {
+ DEBUG
+ ("FT1000:download:Download error: Got Run address request before image offset request.\n");
+ status = STATUS_FAILURE;
+ break;
+ }
+ break;
+ case REQUEST_CODE_LENGTH:
+ DEBUG
+ ("FT1000:download:REQUEST_CODE_LENGTH\n");
+ if (correct_version) {
+ DEBUG
+ ("FT1000:download:run_size = 0x%8x\n",
+ (int)run_size);
+ put_request_value(ft1000dev,
+ run_size);
+ } else {
+ DEBUG
+ ("FT1000:download:Download error: Got Size request before image offset request.\n");
+ status = STATUS_FAILURE;
+ break;
+ }
+ break;
+ case REQUEST_DONE_CL:
+ ft1000dev->usbboot = 3;
+ /* Reposition ptrs to beginning of provisioning section */
+ s_file =
+ (u16 *) (pFileStart +
+ file_hdr->commands_offset);
+ c_file =
+ (u8 *) (pFileStart +
+ file_hdr->commands_offset);
+ state = STATE_DONE_DWNLD;
+ break;
+ case REQUEST_CODE_SEGMENT:
+ //DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n");
+ if (!correct_version) {
+ DEBUG
+ ("FT1000:download:Download error: Got Code Segment request before image offset request.\n");
+ status = STATUS_FAILURE;
+ break;
+ }
+
+ word_length =
+ get_request_value(ft1000dev);
+ //DEBUG("FT1000:download:word_length = %d\n", (int)word_length);
+ if (word_length > MAX_LENGTH) {
+ DEBUG
+ ("FT1000:download:Download error: Max length exceeded\n");
+ status = STATUS_FAILURE;
+ break;
+ }
+ if ((word_length * 2 + c_file) >
+ code_end) {
+ /*
+ * Error, beyond boot code range.
+ */
+ DEBUG
+ ("FT1000:download:Download error: Requested len=%d exceeds DSP code boundary.\n",
+ (int)word_length);
+ status = STATUS_FAILURE;
+ break;
+ }
+ /*
+ * Position ASIC DPRAM auto-increment pointer.
+ */
+ dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
+ if (word_length & 0x1)
+ word_length++;
+ word_length = word_length / 2;
+
+ write_blk_fifo(ft1000dev, &s_file,
+ &c_file, word_length);
+ if (ft1000dev->usbboot == 0)
+ ft1000dev->usbboot++;
+ if (ft1000dev->usbboot == 1) {
+ tempword = 0;
+ ft1000_write_dpram16(ft1000dev,
+ DWNLD_MAG1_PS_HDR_LOC,
+ tempword,
+ 0);
+ }
+
+ break;
+
+ case REQUEST_MAILBOX_DATA:
+ DEBUG
+ ("FT1000:download: REQUEST_MAILBOX_DATA\n");
+ // Convert length from byte count to word count. Make sure we round up.
+ word_length =
+ (long)(pft1000info->DSPInfoBlklen +
+ 1) / 2;
+ put_request_value(ft1000dev,
+ word_length);
+ mailbox_data =
+ (struct drv_msg *)&(pft1000info->
+ DSPInfoBlk[0]);
+ /*
+ * Position ASIC DPRAM auto-increment pointer.
+ */
+
+ data = (u16 *) & mailbox_data->data[0];
+ dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
+ if (word_length & 0x1)
+ word_length++;
+
+ word_length = (word_length / 2);
+
+ for (; word_length > 0; word_length--) { /* In words */
+
+ templong = *data++;
+ templong |= (*data++ << 16);
+ status =
+ fix_ft1000_write_dpram32
+ (ft1000dev, dpram++,
+ (u8 *) & templong);
+
+ }
+ break;
+
+ case REQUEST_VERSION_INFO:
+ DEBUG
+ ("FT1000:download:REQUEST_VERSION_INFO\n");
+ word_length =
+ file_hdr->version_data_size;
+ put_request_value(ft1000dev,
+ word_length);
+ /*
+ * Position ASIC DPRAM auto-increment pointer.
+ */
+
+ s_file =
+ (u16 *) (pFileStart +
+ file_hdr->
+ version_data_offset);
+
+ dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
+ if (word_length & 0x1)
+ word_length++;
+
+ word_length = (word_length / 2);
+
+ for (; word_length > 0; word_length--) { /* In words */
+
+ templong = ntohs(*s_file++);
+ temp = ntohs(*s_file++);
+ templong |= (temp << 16);
+ status =
+ fix_ft1000_write_dpram32
+ (ft1000dev, dpram++,
+ (u8 *) & templong);
+
+ }
+ break;
+
+ case REQUEST_CODE_BY_VERSION:
+ DEBUG
+ ("FT1000:download:REQUEST_CODE_BY_VERSION\n");
+ correct_version = FALSE;
+ requested_version =
+ get_request_value(ft1000dev);
+
+ dsp_img_info =
+ (struct dsp_image_info *)(pFileStart
+ +
+ sizeof
+ (struct
+ dsp_file_hdr));
+
+ for (image = 0;
+ image < file_hdr->nDspImages;
+ image++) {
+
+ if (dsp_img_info->version ==
+ requested_version) {
+ correct_version = TRUE;
+ DEBUG
+ ("FT1000:download: correct_version is TRUE\n");
+ s_file =
+ (u16 *) (pFileStart
+ +
+ dsp_img_info->
+ begin_offset);
+ c_file =
+ (u8 *) (pFileStart +
+ dsp_img_info->
+ begin_offset);
+ code_end =
+ (u8 *) (pFileStart +
+ dsp_img_info->
+ end_offset);
+ run_address =
+ dsp_img_info->
+ run_address;
+ run_size =
+ dsp_img_info->
+ image_size;
+ image_chksum =
+ (u32) dsp_img_info->
+ checksum;
+ break;
+ }
+ dsp_img_info++;
+
+ } //end of for
+
+ if (!correct_version) {
+ /*
+ * Error, beyond boot code range.
+ */
+ DEBUG
+ ("FT1000:download:Download error: Bad Version Request = 0x%x.\n",
+ (int)requested_version);
+ status = STATUS_FAILURE;
+ break;
+ }
+ break;
+
+ default:
+ DEBUG
+ ("FT1000:download:Download error: Bad request type=%d in CODE download state.\n",
+ request);
+ status = STATUS_FAILURE;
+ break;
+ }
+ if (ft1000dev->usbboot)
+ put_handshake_usb(ft1000dev,
+ HANDSHAKE_RESPONSE);
+ else
+ put_handshake(ft1000dev,
+ HANDSHAKE_RESPONSE);
+ } else {
+ DEBUG
+ ("FT1000:download:Download error: Handshake failed\n");
+ status = STATUS_FAILURE;
+ }
+
+ break;
+
+ case STATE_DONE_DWNLD:
+ DEBUG("FT1000:download:Code loader is done...\n");
+ state = STATE_SECTION_PROV;
+ break;
+
+ case STATE_SECTION_PROV:
+ DEBUG("FT1000:download:STATE_SECTION_PROV\n");
+ pseudo_header = (struct pseudo_hdr *)c_file;
+
+ if (pseudo_header->checksum ==
+ hdr_checksum(pseudo_header)) {
+ if (pseudo_header->portdest !=
+ 0x80 /* Dsp OAM */ ) {
+ state = STATE_DONE_PROV;
+ break;
+ }
+ pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */
+
+ // Get buffer for provisioning data
+ pbuffer =
+ kmalloc((pseudo_header_len +
+ sizeof(struct pseudo_hdr)),
+ GFP_ATOMIC);
+ if (pbuffer) {
+ memcpy(pbuffer, (void *)c_file,
+ (u32) (pseudo_header_len +
+ sizeof(struct
+ pseudo_hdr)));
+ // link provisioning data
+ pprov_record =
+ kmalloc(sizeof(struct prov_record),
+ GFP_ATOMIC);
+ if (pprov_record) {
+ pprov_record->pprov_data =
+ pbuffer;
+ list_add_tail(&pprov_record->
+ list,
+ &pft1000info->
+ prov_list);
+ // Move to next entry if available
+ c_file =
+ (u8 *) ((unsigned long)
+ c_file +
+ (u32) ((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
+ if ((unsigned long)(c_file) -
+ (unsigned long)(pFileStart)
+ >=
+ (unsigned long)FileLength) {
+ state = STATE_DONE_FILE;
+ }
+ } else {
+ kfree(pbuffer);
+ status = STATUS_FAILURE;
+ }
+ } else {
+ status = STATUS_FAILURE;
+ }
+ } else {
+ /* Checksum did not compute */
+ status = STATUS_FAILURE;
+ }
+ DEBUG
+ ("ft1000:download: after STATE_SECTION_PROV, state = %d, status= %d\n",
+ state, status);
+ break;
+
+ case STATE_DONE_PROV:
+ DEBUG("FT1000:download:STATE_DONE_PROV\n");
+ state = STATE_DONE_FILE;
+ break;
+
+ default:
+ status = STATUS_FAILURE;
+ break;
+ } /* End Switch */
+
+ if (status != STATUS_SUCCESS) {
+ break;
+ }
+
+/****
+ // Check if Card is present
+ status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK);
+ if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) {
+ break;
+ }
+
+ status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID);
+ if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) {
+ break;
+ }
+****/
+
+ } /* End while */
+
+ DEBUG("Download exiting with status = 0x%8x\n", status);
+ ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX,
+ FT1000_REG_DOORBELL);
+
+ return status;
+}
+
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
new file mode 100644
index 00000000..9b8fed7b
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -0,0 +1,1948 @@
+//=====================================================
+// CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved.
+//
+//
+// This file is part of Express Card USB Driver
+//
+// $Id:
+//====================================================
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include "ft1000_usb.h"
+#include <linux/types.h>
+
+#define HARLEY_READ_REGISTER 0x0
+#define HARLEY_WRITE_REGISTER 0x01
+#define HARLEY_READ_DPRAM_32 0x02
+#define HARLEY_READ_DPRAM_LOW 0x03
+#define HARLEY_READ_DPRAM_HIGH 0x04
+#define HARLEY_WRITE_DPRAM_32 0x05
+#define HARLEY_WRITE_DPRAM_LOW 0x06
+#define HARLEY_WRITE_DPRAM_HIGH 0x07
+
+#define HARLEY_READ_OPERATION 0xc1
+#define HARLEY_WRITE_OPERATION 0x41
+
+//#define JDEBUG
+
+static int ft1000_reset(void *ft1000dev);
+static int ft1000_submit_rx_urb(struct ft1000_info *info);
+static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int ft1000_open (struct net_device *dev);
+static struct net_device_stats *ft1000_netdev_stats(struct net_device *dev);
+static int ft1000_chkcard (struct ft1000_usb *dev);
+
+static u8 tempbuffer[1600];
+
+#define MAX_RCV_LOOP 100
+
+//---------------------------------------------------------------------------
+// Function: ft1000_control
+//
+// Parameters: ft1000_usb - device structure
+// pipe - usb control message pipe
+// request - control request
+// requesttype - control message request type
+// value - value to be written or 0
+// index - register index
+// data - data buffer to hold the read/write values
+// size - data size
+// timeout - control message time out value
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function sends a control message via USB interface synchronously
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static int ft1000_control(struct ft1000_usb *ft1000dev, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size, int timeout)
+{
+ u16 ret;
+
+ if ((ft1000dev == NULL) || (ft1000dev->dev == NULL)) {
+ DEBUG("ft1000dev or ft1000dev->dev == NULL, failure\n");
+ return -ENODEV;
+ }
+
+ ret = usb_control_msg(ft1000dev->dev, pipe, request, requesttype,
+ value, index, data, size, timeout);
+
+ if (ret > 0)
+ ret = 0;
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_read_register
+//
+// Parameters: ft1000_usb - device structure
+// Data - data buffer to hold the value read
+// nRegIndex - register index
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function returns the value in a register
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+
+int ft1000_read_register(struct ft1000_usb *ft1000dev, u16* Data,
+ u16 nRegIndx)
+{
+ int ret = STATUS_SUCCESS;
+
+ ret = ft1000_control(ft1000dev,
+ usb_rcvctrlpipe(ft1000dev->dev, 0),
+ HARLEY_READ_REGISTER,
+ HARLEY_READ_OPERATION,
+ 0,
+ nRegIndx,
+ Data,
+ 2,
+ USB_CTRL_GET_TIMEOUT);
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_write_register
+//
+// Parameters: ft1000_usb - device structure
+// value - value to write into a register
+// nRegIndex - register index
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function writes the value in a register
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int ft1000_write_register(struct ft1000_usb *ft1000dev, u16 value,
+ u16 nRegIndx)
+{
+ int ret = STATUS_SUCCESS;
+
+ ret = ft1000_control(ft1000dev,
+ usb_sndctrlpipe(ft1000dev->dev, 0),
+ HARLEY_WRITE_REGISTER,
+ HARLEY_WRITE_OPERATION,
+ value,
+ nRegIndx,
+ NULL,
+ 0,
+ USB_CTRL_SET_TIMEOUT);
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_read_dpram32
+//
+// Parameters: ft1000_usb - device structure
+// indx - starting address to read
+// buffer - data buffer to hold the data read
+// cnt - number of byte read from DPRAM
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function read a number of bytes from DPRAM
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+
+int ft1000_read_dpram32(struct ft1000_usb *ft1000dev, u16 indx, u8 *buffer,
+ u16 cnt)
+{
+ int ret = STATUS_SUCCESS;
+
+ ret = ft1000_control(ft1000dev,
+ usb_rcvctrlpipe(ft1000dev->dev, 0),
+ HARLEY_READ_DPRAM_32,
+ HARLEY_READ_OPERATION,
+ 0,
+ indx,
+ buffer,
+ cnt,
+ USB_CTRL_GET_TIMEOUT);
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_write_dpram32
+//
+// Parameters: ft1000_usb - device structure
+// indx - starting address to write the data
+// buffer - data buffer to write into DPRAM
+// cnt - number of bytes to write
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function writes into DPRAM a number of bytes
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int ft1000_write_dpram32(struct ft1000_usb *ft1000dev, u16 indx, u8 *buffer,
+ u16 cnt)
+{
+ int ret = STATUS_SUCCESS;
+
+ if (cnt % 4)
+ cnt += cnt - (cnt % 4);
+
+ ret = ft1000_control(ft1000dev,
+ usb_sndctrlpipe(ft1000dev->dev, 0),
+ HARLEY_WRITE_DPRAM_32,
+ HARLEY_WRITE_OPERATION,
+ 0,
+ indx,
+ buffer,
+ cnt,
+ USB_CTRL_SET_TIMEOUT);
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_read_dpram16
+//
+// Parameters: ft1000_usb - device structure
+// indx - starting address to read
+// buffer - data buffer to hold the data read
+// hightlow - high or low 16 bit word
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function read 16 bits from DPRAM
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int ft1000_read_dpram16(struct ft1000_usb *ft1000dev, u16 indx, u8 *buffer,
+ u8 highlow)
+{
+ int ret = STATUS_SUCCESS;
+ u8 request;
+
+ if (highlow == 0)
+ request = HARLEY_READ_DPRAM_LOW;
+ else
+ request = HARLEY_READ_DPRAM_HIGH;
+
+ ret = ft1000_control(ft1000dev,
+ usb_rcvctrlpipe(ft1000dev->dev, 0),
+ request,
+ HARLEY_READ_OPERATION,
+ 0,
+ indx,
+ buffer,
+ 2,
+ USB_CTRL_GET_TIMEOUT);
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_write_dpram16
+//
+// Parameters: ft1000_usb - device structure
+// indx - starting address to write the data
+// value - 16bits value to write
+// hightlow - high or low 16 bit word
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function writes into DPRAM a number of bytes
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int ft1000_write_dpram16(struct ft1000_usb *ft1000dev, u16 indx, u16 value, u8 highlow)
+{
+ int ret = STATUS_SUCCESS;
+ u8 request;
+
+ if (highlow == 0)
+ request = HARLEY_WRITE_DPRAM_LOW;
+ else
+ request = HARLEY_WRITE_DPRAM_HIGH;
+
+ ret = ft1000_control(ft1000dev,
+ usb_sndctrlpipe(ft1000dev->dev, 0),
+ request,
+ HARLEY_WRITE_OPERATION,
+ value,
+ indx,
+ NULL,
+ 0,
+ USB_CTRL_SET_TIMEOUT);
+
+ return ret;
+}
+
+//---------------------------------------------------------------------------
+// Function: fix_ft1000_read_dpram32
+//
+// Parameters: ft1000_usb - device structure
+// indx - starting address to read
+// buffer - data buffer to hold the data read
+//
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function read DPRAM 4 words at a time
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int fix_ft1000_read_dpram32(struct ft1000_usb *ft1000dev, u16 indx,
+ u8 *buffer)
+{
+ u8 buf[16];
+ u16 pos;
+ int ret = STATUS_SUCCESS;
+
+ pos = (indx / 4) * 4;
+ ret = ft1000_read_dpram32(ft1000dev, pos, buf, 16);
+
+ if (ret == STATUS_SUCCESS) {
+ pos = (indx % 4) * 4;
+ *buffer++ = buf[pos++];
+ *buffer++ = buf[pos++];
+ *buffer++ = buf[pos++];
+ *buffer++ = buf[pos++];
+ } else {
+ DEBUG("fix_ft1000_read_dpram32: DPRAM32 Read failed\n");
+ *buffer++ = 0;
+ *buffer++ = 0;
+ *buffer++ = 0;
+ *buffer++ = 0;
+ }
+
+ return ret;
+}
+
+
+//---------------------------------------------------------------------------
+// Function: fix_ft1000_write_dpram32
+//
+// Parameters: ft1000_usb - device structure
+// indx - starting address to write
+// buffer - data buffer to write
+//
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function write to DPRAM 4 words at a time
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int fix_ft1000_write_dpram32(struct ft1000_usb *ft1000dev, u16 indx, u8 *buffer)
+{
+ u16 pos1;
+ u16 pos2;
+ u16 i;
+ u8 buf[32];
+ u8 resultbuffer[32];
+ u8 *pdata;
+ int ret = STATUS_SUCCESS;
+
+ pos1 = (indx / 4) * 4;
+ pdata = buffer;
+ ret = ft1000_read_dpram32(ft1000dev, pos1, buf, 16);
+
+ if (ret == STATUS_SUCCESS) {
+ pos2 = (indx % 4)*4;
+ buf[pos2++] = *buffer++;
+ buf[pos2++] = *buffer++;
+ buf[pos2++] = *buffer++;
+ buf[pos2++] = *buffer++;
+ ret = ft1000_write_dpram32(ft1000dev, pos1, buf, 16);
+ } else {
+ DEBUG("fix_ft1000_write_dpram32: DPRAM32 Read failed\n");
+ return ret;
+ }
+
+ ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16);
+
+ if (ret == STATUS_SUCCESS) {
+ buffer = pdata;
+ for (i = 0; i < 16; i++) {
+ if (buf[i] != resultbuffer[i])
+ ret = STATUS_FAILURE;
+ }
+ }
+
+ if (ret == STATUS_FAILURE) {
+ ret = ft1000_write_dpram32(ft1000dev, pos1,
+ (u8 *)&tempbuffer[0], 16);
+ ret = ft1000_read_dpram32(ft1000dev, pos1,
+ (u8 *)&resultbuffer[0], 16);
+ if (ret == STATUS_SUCCESS) {
+ buffer = pdata;
+ for (i = 0; i < 16; i++) {
+ if (tempbuffer[i] != resultbuffer[i]) {
+ ret = STATUS_FAILURE;
+ DEBUG("%s Failed to write\n",
+ __func__);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+//------------------------------------------------------------------------
+//
+// Function: card_reset_dsp
+//
+// Synopsis: This function is called to reset or activate the DSP
+//
+// Arguments: value - reset or activate
+//
+// Returns: None
+//-----------------------------------------------------------------------
+static void card_reset_dsp(struct ft1000_usb *ft1000dev, bool value)
+{
+ u16 status = STATUS_SUCCESS;
+ u16 tempword;
+
+ status = ft1000_write_register(ft1000dev, HOST_INTF_BE,
+ FT1000_REG_SUP_CTRL);
+ status = ft1000_read_register(ft1000dev, &tempword,
+ FT1000_REG_SUP_CTRL);
+
+ if (value) {
+ DEBUG("Reset DSP\n");
+ status = ft1000_read_register(ft1000dev, &tempword,
+ FT1000_REG_RESET);
+ tempword |= DSP_RESET_BIT;
+ status = ft1000_write_register(ft1000dev, tempword,
+ FT1000_REG_RESET);
+ } else {
+ DEBUG("Activate DSP\n");
+ status = ft1000_read_register(ft1000dev, &tempword,
+ FT1000_REG_RESET);
+ tempword |= DSP_ENCRYPTED;
+ tempword &= ~DSP_UNENCRYPTED;
+ status = ft1000_write_register(ft1000dev, tempword,
+ FT1000_REG_RESET);
+ status = ft1000_read_register(ft1000dev, &tempword,
+ FT1000_REG_RESET);
+ tempword &= ~EFUSE_MEM_DISABLE;
+ tempword &= ~DSP_RESET_BIT;
+ status = ft1000_write_register(ft1000dev, tempword,
+ FT1000_REG_RESET);
+ status = ft1000_read_register(ft1000dev, &tempword,
+ FT1000_REG_RESET);
+ }
+}
+
+//---------------------------------------------------------------------------
+// Function: card_send_command
+//
+// Parameters: ft1000_usb - device structure
+// ptempbuffer - command buffer
+// size - command buffer size
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function sends a command to ASIC
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+void card_send_command(struct ft1000_usb *ft1000dev, void *ptempbuffer,
+ int size)
+{
+ unsigned short temp;
+ unsigned char *commandbuf;
+
+ DEBUG("card_send_command: enter card_send_command... size=%d\n", size);
+
+ commandbuf = kmalloc(size + 2, GFP_KERNEL);
+ memcpy((void *)commandbuf + 2, (void *)ptempbuffer, size);
+
+ ft1000_read_register(ft1000dev, &temp, FT1000_REG_DOORBELL);
+
+ if (temp & 0x0100)
+ msleep(10);
+
+ /* check for odd word */
+ size = size + 2;
+
+ /* Must force to be 32 bit aligned */
+ if (size % 4)
+ size += 4 - (size % 4);
+
+ ft1000_write_dpram32(ft1000dev, 0, commandbuf, size);
+ msleep(1);
+ ft1000_write_register(ft1000dev, FT1000_DB_DPRAM_TX,
+ FT1000_REG_DOORBELL);
+ msleep(1);
+
+ ft1000_read_register(ft1000dev, &temp, FT1000_REG_DOORBELL);
+
+ if ((temp & 0x0100) == 0) {
+ //DEBUG("card_send_command: Message sent\n");
+ }
+
+}
+
+//--------------------------------------------------------------------------
+//
+// Function: dsp_reload
+//
+// Synopsis: This function is called to load or reload the DSP
+//
+// Arguments: ft1000dev - device structure
+//
+// Returns: None
+//-----------------------------------------------------------------------
+int dsp_reload(struct ft1000_usb *ft1000dev)
+{
+ u16 status;
+ u16 tempword;
+ u32 templong;
+
+ struct ft1000_info *pft1000info;
+
+ pft1000info = netdev_priv(ft1000dev->net);
+
+ pft1000info->CardReady = 0;
+
+ /* Program Interrupt Mask register */
+ status = ft1000_write_register(ft1000dev, 0xffff, FT1000_REG_SUP_IMASK);
+
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_RESET);
+ tempword |= ASIC_RESET_BIT;
+ status = ft1000_write_register(ft1000dev, tempword, FT1000_REG_RESET);
+ msleep(1000);
+ status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_RESET);
+ DEBUG("Reset Register = 0x%x\n", tempword);
+
+ /* Toggle DSP reset */
+ card_reset_dsp(ft1000dev, 1);
+ msleep(1000);
+ card_reset_dsp(ft1000dev, 0);
+ msleep(1000);
+
+ status =
+ ft1000_write_register(ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
+
+ /* Let's check for FEFE */
+ status =
+ ft1000_read_dpram32(ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX,
+ (u8 *) &templong, 4);
+ DEBUG("templong (fefe) = 0x%8x\n", templong);
+
+ /* call codeloader */
+ status = scram_dnldr(ft1000dev, pFileStart, FileLength);
+
+ if (status != STATUS_SUCCESS)
+ return -EIO;
+
+ msleep(1000);
+
+ DEBUG("dsp_reload returned\n");
+
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_reset_asic
+// Description: This function will call the Card Service function to reset the
+// ASIC.
+// Input:
+// dev - device structure
+// Output:
+// none
+//
+//---------------------------------------------------------------------------
+static void ft1000_reset_asic(struct net_device *dev)
+{
+ struct ft1000_info *info = netdev_priv(dev);
+ struct ft1000_usb *ft1000dev = info->priv;
+ u16 tempword;
+
+ DEBUG("ft1000_hw:ft1000_reset_asic called\n");
+
+ /* Let's use the register provided by the Magnemite ASIC to reset the
+ * ASIC and DSP.
+ */
+ ft1000_write_register(ft1000dev, (DSP_RESET_BIT | ASIC_RESET_BIT),
+ FT1000_REG_RESET);
+
+ mdelay(1);
+
+ /* set watermark to -1 in order to not generate an interrupt */
+ ft1000_write_register(ft1000dev, 0xffff, FT1000_REG_MAG_WATERMARK);
+
+ /* clear interrupts */
+ ft1000_read_register(ft1000dev, &tempword, FT1000_REG_SUP_ISR);
+ DEBUG("ft1000_hw: interrupt status register = 0x%x\n", tempword);
+ ft1000_write_register(ft1000dev, tempword, FT1000_REG_SUP_ISR);
+ ft1000_read_register(ft1000dev, &tempword, FT1000_REG_SUP_ISR);
+ DEBUG("ft1000_hw: interrupt status register = 0x%x\n", tempword);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_reset_card
+// Description: This function will reset the card
+// Input:
+// dev - device structure
+// Output:
+// status - FALSE (card reset fail)
+// TRUE (card reset successful)
+//
+//---------------------------------------------------------------------------
+static int ft1000_reset_card(struct net_device *dev)
+{
+ struct ft1000_info *info = netdev_priv(dev);
+ struct ft1000_usb *ft1000dev = info->priv;
+ u16 tempword;
+ struct prov_record *ptr;
+
+ DEBUG("ft1000_hw:ft1000_reset_card called.....\n");
+
+ ft1000dev->fCondResetPend = 1;
+ info->CardReady = 0;
+ ft1000dev->fProvComplete = 0;
+
+ /* Make sure we free any memory reserve for provisioning */
+ while (list_empty(&info->prov_list) == 0) {
+ DEBUG("ft1000_reset_card:deleting provisioning record\n");
+ ptr =
+ list_entry(info->prov_list.next, struct prov_record, list);
+ list_del(&ptr->list);
+ kfree(ptr->pprov_data);
+ kfree(ptr);
+ }
+
+ DEBUG("ft1000_hw:ft1000_reset_card: reset asic\n");
+ ft1000_reset_asic(dev);
+
+ DEBUG("ft1000_hw:ft1000_reset_card: call dsp_reload\n");
+ dsp_reload(ft1000dev);
+
+ DEBUG("dsp reload successful\n");
+
+ mdelay(10);
+
+ /* Initialize DSP heartbeat area */
+ ft1000_write_dpram16(ft1000dev, FT1000_MAG_HI_HO, ho_mag,
+ FT1000_MAG_HI_HO_INDX);
+ ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (u8 *) &tempword,
+ FT1000_MAG_HI_HO_INDX);
+ DEBUG("ft1000_hw:ft1000_reset_card:hi_ho value = 0x%x\n", tempword);
+
+ info->CardReady = 1;
+
+ ft1000dev->fCondResetPend = 0;
+
+ return TRUE;
+}
+
+static const struct net_device_ops ftnet_ops =
+{
+ .ndo_open = &ft1000_open,
+ .ndo_stop = &ft1000_close,
+ .ndo_start_xmit = &ft1000_start_xmit,
+ .ndo_get_stats = &ft1000_netdev_stats,
+};
+
+
+//---------------------------------------------------------------------------
+// Function: init_ft1000_netdev
+//
+// Parameters: ft1000dev - device structure
+//
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function initialize the network device
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int init_ft1000_netdev(struct ft1000_usb *ft1000dev)
+{
+ struct net_device *netdev;
+ struct ft1000_info *pInfo = NULL;
+ struct dpram_blk *pdpram_blk;
+ int i, ret_val;
+ struct list_head *cur, *tmp;
+ char card_nr[2];
+ u8 gCardIndex = 0;
+
+ DEBUG("Enter init_ft1000_netdev...\n");
+
+ netdev = alloc_etherdev(sizeof(struct ft1000_info));
+ if (!netdev) {
+ DEBUG("init_ft1000_netdev: can not allocate network device\n");
+ return -ENOMEM;
+ }
+
+ pInfo = netdev_priv(netdev);
+
+ memset(pInfo, 0, sizeof(struct ft1000_info));
+
+ dev_alloc_name(netdev, netdev->name);
+
+ DEBUG("init_ft1000_netdev: network device name is %s\n", netdev->name);
+
+ if (strncmp(netdev->name, "eth", 3) == 0) {
+ card_nr[0] = netdev->name[3];
+ card_nr[1] = '\0';
+ ret_val = kstrtou8(card_nr, 10, &gCardIndex);
+ if (ret_val) {
+ printk(KERN_ERR "Can't parse netdev\n");
+ goto err_net;
+ }
+
+ ft1000dev->CardNumber = gCardIndex;
+ DEBUG("card number = %d\n", ft1000dev->CardNumber);
+ } else {
+ printk(KERN_ERR "ft1000: Invalid device name\n");
+ ret_val = -ENXIO;
+ goto err_net;
+ }
+
+ memset(&pInfo->stats, 0, sizeof(struct net_device_stats));
+
+ spin_lock_init(&pInfo->dpram_lock);
+ pInfo->priv = ft1000dev;
+ pInfo->DrvErrNum = 0;
+ pInfo->registered = 1;
+ pInfo->ft1000_reset = ft1000_reset;
+ pInfo->mediastate = 0;
+ pInfo->fifo_cnt = 0;
+ ft1000dev->DeviceCreated = FALSE;
+ pInfo->CardReady = 0;
+ pInfo->DSP_TIME[0] = 0;
+ pInfo->DSP_TIME[1] = 0;
+ pInfo->DSP_TIME[2] = 0;
+ pInfo->DSP_TIME[3] = 0;
+ ft1000dev->fAppMsgPend = 0;
+ ft1000dev->fCondResetPend = 0;
+ ft1000dev->usbboot = 0;
+ ft1000dev->dspalive = 0;
+ memset(&ft1000dev->tempbuf[0], 0, sizeof(ft1000dev->tempbuf));
+
+ INIT_LIST_HEAD(&pInfo->prov_list);
+
+ INIT_LIST_HEAD(&ft1000dev->nodes.list);
+
+ netdev->netdev_ops = &ftnet_ops;
+
+ ft1000dev->net = netdev;
+
+ DEBUG("Initialize free_buff_lock and freercvpool\n");
+ spin_lock_init(&free_buff_lock);
+
+ /* initialize a list of buffers to be use for queuing
+ * up receive command data
+ */
+ INIT_LIST_HEAD(&freercvpool);
+
+ /* create list of free buffers */
+ for (i = 0; i < NUM_OF_FREE_BUFFERS; i++) {
+ /* Get memory for DPRAM_DATA link list */
+ pdpram_blk = kmalloc(sizeof(struct dpram_blk), GFP_KERNEL);
+ if (pdpram_blk == NULL) {
+ ret_val = -ENOMEM;
+ goto err_free;
+ }
+ /* Get a block of memory to store command data */
+ pdpram_blk->pbuffer = kmalloc(MAX_CMD_SQSIZE, GFP_KERNEL);
+ if (pdpram_blk->pbuffer == NULL) {
+ ret_val = -ENOMEM;
+ kfree(pdpram_blk);
+ goto err_free;
+ }
+ /* link provisioning data */
+ list_add_tail(&pdpram_blk->list, &freercvpool);
+ }
+ numofmsgbuf = NUM_OF_FREE_BUFFERS;
+
+ return 0;
+
+err_free:
+ list_for_each_safe(cur, tmp, &freercvpool) {
+ pdpram_blk = list_entry(cur, struct dpram_blk, list);
+ list_del(&pdpram_blk->list);
+ kfree(pdpram_blk->pbuffer);
+ kfree(pdpram_blk);
+ }
+err_net:
+ free_netdev(netdev);
+ return ret_val;
+}
+
+//---------------------------------------------------------------------------
+// Function: reg_ft1000_netdev
+//
+// Parameters: ft1000dev - device structure
+//
+//
+// Returns: STATUS_SUCCESS - success
+// STATUS_FAILURE - failure
+//
+// Description: This function register the network driver
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int reg_ft1000_netdev(struct ft1000_usb *ft1000dev,
+ struct usb_interface *intf)
+{
+ struct net_device *netdev;
+ struct ft1000_info *pInfo;
+ int rc;
+
+ netdev = ft1000dev->net;
+ pInfo = netdev_priv(ft1000dev->net);
+ DEBUG("Enter reg_ft1000_netdev...\n");
+
+ ft1000_read_register(ft1000dev, &pInfo->AsicID, FT1000_REG_ASIC_ID);
+
+ usb_set_intfdata(intf, pInfo);
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ rc = register_netdev(netdev);
+ if (rc) {
+ DEBUG("reg_ft1000_netdev: could not register network device\n");
+ free_netdev(netdev);
+ return rc;
+ }
+
+ ft1000_create_dev(ft1000dev);
+
+ DEBUG("reg_ft1000_netdev returned\n");
+
+ pInfo->CardReady = 1;
+
+ return 0;
+}
+
+int ft1000_reset(void *dev)
+{
+ ft1000_reset_card(dev);
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_usb_transmit_complete
+//
+// Parameters: urb - transmitted usb urb
+//
+//
+// Returns: none
+//
+// Description: This is the callback function when a urb is transmitted
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static void ft1000_usb_transmit_complete(struct urb *urb)
+{
+
+ struct ft1000_usb *ft1000dev = urb->context;
+
+ if (urb->status)
+ pr_err("%s: TX status %d\n", ft1000dev->net->name, urb->status);
+
+ netif_wake_queue(ft1000dev->net);
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_copy_down_pkt
+// Description: This function will take an ethernet packet and convert it to
+// a Flarion packet prior to sending it to the ASIC Downlink
+// FIFO.
+// Input:
+// dev - device structure
+// packet - address of ethernet packet
+// len - length of IP packet
+// Output:
+// status - FAILURE
+// SUCCESS
+//
+//---------------------------------------------------------------------------
+static int ft1000_copy_down_pkt(struct net_device *netdev, u8 * packet, u16 len)
+{
+ struct ft1000_info *pInfo = netdev_priv(netdev);
+ struct ft1000_usb *pFt1000Dev = pInfo->priv;
+
+ int count, ret;
+ u8 *t;
+ struct pseudo_hdr hdr;
+
+ if (!pInfo->CardReady) {
+ DEBUG("ft1000_copy_down_pkt::Card Not Ready\n");
+ return -ENODEV;
+ }
+
+ count = sizeof(struct pseudo_hdr) + len;
+ if (count > MAX_BUF_SIZE) {
+ DEBUG("Error:ft1000_copy_down_pkt:Message Size Overflow!\n");
+ DEBUG("size = %d\n", count);
+ return -EINVAL;
+ }
+
+ if (count % 4)
+ count = count + (4 - (count % 4));
+
+ memset(&hdr, 0, sizeof(struct pseudo_hdr));
+
+ hdr.length = ntohs(count);
+ hdr.source = 0x10;
+ hdr.destination = 0x20;
+ hdr.portdest = 0x20;
+ hdr.portsrc = 0x10;
+ hdr.sh_str_id = 0x91;
+ hdr.control = 0x00;
+
+ hdr.checksum = hdr.length ^ hdr.source ^ hdr.destination ^
+ hdr.portdest ^ hdr.portsrc ^ hdr.sh_str_id ^ hdr.control;
+
+ memcpy(&pFt1000Dev->tx_buf[0], &hdr, sizeof(hdr));
+ memcpy(&(pFt1000Dev->tx_buf[sizeof(struct pseudo_hdr)]), packet, len);
+
+ netif_stop_queue(netdev);
+
+ usb_fill_bulk_urb(pFt1000Dev->tx_urb,
+ pFt1000Dev->dev,
+ usb_sndbulkpipe(pFt1000Dev->dev,
+ pFt1000Dev->bulk_out_endpointAddr),
+ pFt1000Dev->tx_buf, count,
+ ft1000_usb_transmit_complete, (void *)pFt1000Dev);
+
+ t = (u8 *) pFt1000Dev->tx_urb->transfer_buffer;
+
+ ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC);
+
+ if (ret) {
+ DEBUG("ft1000 failed tx_urb %d\n", ret);
+ return ret;
+ } else {
+ pInfo->stats.tx_packets++;
+ pInfo->stats.tx_bytes += (len + 14);
+ }
+
+ return 0;
+}
+
+
+//---------------------------------------------------------------------------
+// Function: ft1000_start_xmit
+//
+// Parameters: skb - socket buffer to be sent
+// dev - network device
+//
+//
+// Returns: none
+//
+// Description: transmit a ethernet packet
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ft1000_info *pInfo = netdev_priv(dev);
+ struct ft1000_usb *pFt1000Dev = pInfo->priv;
+ u8 *pdata;
+ int maxlen, pipe;
+
+ if (skb == NULL) {
+ DEBUG("ft1000_hw: ft1000_start_xmit:skb == NULL!!!\n");
+ return NETDEV_TX_OK;
+ }
+
+ if (pFt1000Dev->status & FT1000_STATUS_CLOSING) {
+ DEBUG("network driver is closed, return\n");
+ goto err;
+ }
+
+ pipe =
+ usb_sndbulkpipe(pFt1000Dev->dev, pFt1000Dev->bulk_out_endpointAddr);
+ maxlen = usb_maxpacket(pFt1000Dev->dev, pipe, usb_pipeout(pipe));
+
+ pdata = (u8 *) skb->data;
+
+ if (pInfo->mediastate == 0) {
+ /* Drop packet is mediastate is down */
+ DEBUG("ft1000_hw:ft1000_start_xmit:mediastate is down\n");
+ goto err;
+ }
+
+ if ((skb->len < ENET_HEADER_SIZE) || (skb->len > ENET_MAX_SIZE)) {
+ /* Drop packet which has invalid size */
+ DEBUG("ft1000_hw:ft1000_start_xmit:invalid ethernet length\n");
+ goto err;
+ }
+
+ ft1000_copy_down_pkt(dev, (pdata + ENET_HEADER_SIZE - 2),
+ skb->len - ENET_HEADER_SIZE + 2);
+
+err:
+ dev_kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_copy_up_pkt
+// Description: This function will take a packet from the FIFO up link and
+// convert it into an ethernet packet and deliver it to the IP stack
+// Input:
+// urb - the receiving usb urb
+//
+// Output:
+// status - FAILURE
+// SUCCESS
+//
+//---------------------------------------------------------------------------
+static int ft1000_copy_up_pkt(struct urb *urb)
+{
+ struct ft1000_info *info = urb->context;
+ struct ft1000_usb *ft1000dev = info->priv;
+ struct net_device *net = ft1000dev->net;
+
+ u16 tempword;
+ u16 len;
+ u16 lena;
+ struct sk_buff *skb;
+ u16 i;
+ u8 *pbuffer = NULL;
+ u8 *ptemp = NULL;
+ u16 *chksum;
+
+ if (ft1000dev->status & FT1000_STATUS_CLOSING) {
+ DEBUG("network driver is closed, return\n");
+ return STATUS_SUCCESS;
+ }
+ // Read length
+ len = urb->transfer_buffer_length;
+ lena = urb->actual_length;
+
+ chksum = (u16 *) ft1000dev->rx_buf;
+
+ tempword = *chksum++;
+ for (i = 1; i < 7; i++)
+ tempword ^= *chksum++;
+
+ if (tempword != *chksum) {
+ info->stats.rx_errors++;
+ ft1000_submit_rx_urb(info);
+ return STATUS_FAILURE;
+ }
+
+ skb = dev_alloc_skb(len + 12 + 2);
+
+ if (skb == NULL) {
+ DEBUG("ft1000_copy_up_pkt: No Network buffers available\n");
+ info->stats.rx_errors++;
+ ft1000_submit_rx_urb(info);
+ return STATUS_FAILURE;
+ }
+
+ pbuffer = (u8 *) skb_put(skb, len + 12);
+
+ /* subtract the number of bytes read already */
+ ptemp = pbuffer;
+
+ /* fake MAC address */
+ *pbuffer++ = net->dev_addr[0];
+ *pbuffer++ = net->dev_addr[1];
+ *pbuffer++ = net->dev_addr[2];
+ *pbuffer++ = net->dev_addr[3];
+ *pbuffer++ = net->dev_addr[4];
+ *pbuffer++ = net->dev_addr[5];
+ *pbuffer++ = 0x00;
+ *pbuffer++ = 0x07;
+ *pbuffer++ = 0x35;
+ *pbuffer++ = 0xff;
+ *pbuffer++ = 0xff;
+ *pbuffer++ = 0xfe;
+
+ memcpy(pbuffer, ft1000dev->rx_buf + sizeof(struct pseudo_hdr),
+ len - sizeof(struct pseudo_hdr));
+
+ skb->dev = net;
+
+ skb->protocol = eth_type_trans(skb, net);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_rx(skb);
+
+ info->stats.rx_packets++;
+ /* Add on 12 bytes for MAC address which was removed */
+ info->stats.rx_bytes += (lena + 12);
+
+ ft1000_submit_rx_urb(info);
+
+ return SUCCESS;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_submit_rx_urb
+// Description: the receiving function of the network driver
+//
+// Input:
+// info - a private structure contains the device information
+//
+// Output:
+// status - FAILURE
+// SUCCESS
+//
+//---------------------------------------------------------------------------
+static int ft1000_submit_rx_urb(struct ft1000_info *info)
+{
+ int result;
+ struct ft1000_usb *pFt1000Dev = info->priv;
+
+ if (pFt1000Dev->status & FT1000_STATUS_CLOSING) {
+ DEBUG("network driver is closed, return\n");
+ return -ENODEV;
+ }
+
+ usb_fill_bulk_urb(pFt1000Dev->rx_urb,
+ pFt1000Dev->dev,
+ usb_rcvbulkpipe(pFt1000Dev->dev,
+ pFt1000Dev->bulk_in_endpointAddr),
+ pFt1000Dev->rx_buf, MAX_BUF_SIZE,
+ (usb_complete_t) ft1000_copy_up_pkt, info);
+
+ result = usb_submit_urb(pFt1000Dev->rx_urb, GFP_ATOMIC);
+
+ if (result) {
+ pr_err("ft1000_submit_rx_urb: submitting rx_urb %d failed\n",
+ result);
+ return result;
+ }
+
+ return 0;
+}
+
+
+//---------------------------------------------------------------------------
+// Function: ft1000_open
+//
+// Parameters:
+// dev - network device
+//
+//
+// Returns: none
+//
+// Description: open the network driver
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+static int ft1000_open(struct net_device *dev)
+{
+ struct ft1000_info *pInfo = netdev_priv(dev);
+ struct ft1000_usb *pFt1000Dev = pInfo->priv;
+ struct timeval tv;
+
+ DEBUG("ft1000_open is called for card %d\n", pFt1000Dev->CardNumber);
+
+ pInfo->stats.rx_bytes = 0;
+ pInfo->stats.tx_bytes = 0;
+ pInfo->stats.rx_packets = 0;
+ pInfo->stats.tx_packets = 0;
+ do_gettimeofday(&tv);
+ pInfo->ConTm = tv.tv_sec;
+ pInfo->ProgConStat = 0;
+
+ netif_start_queue(dev);
+
+ netif_carrier_on(dev);
+
+ return ft1000_submit_rx_urb(pInfo);
+}
+
+//---------------------------------------------------------------------------
+// Function: ft1000_close
+//
+// Parameters:
+// net - network device
+//
+//
+// Returns: none
+//
+// Description: close the network driver
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+int ft1000_close(struct net_device *net)
+{
+ struct ft1000_info *pInfo = netdev_priv(net);
+ struct ft1000_usb *ft1000dev = pInfo->priv;
+
+ ft1000dev->status |= FT1000_STATUS_CLOSING;
+
+ DEBUG("ft1000_close: pInfo=%p, ft1000dev=%p\n", pInfo, ft1000dev);
+ netif_carrier_off(net);
+ netif_stop_queue(net);
+ ft1000dev->status &= ~FT1000_STATUS_CLOSING;
+
+ pInfo->ProgConStat = 0xff;
+
+ return 0;
+}
+
+static struct net_device_stats *ft1000_netdev_stats(struct net_device *dev)
+{
+ struct ft1000_info *info = netdev_priv(dev);
+
+ return &(info->stats);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_chkcard
+// Description: This function will check if the device is presently available on
+// the system.
+// Input:
+// dev - device structure
+// Output:
+// status - FALSE (device is not present)
+// TRUE (device is present)
+//
+//---------------------------------------------------------------------------
+static int ft1000_chkcard(struct ft1000_usb *dev)
+{
+ u16 tempword;
+ u16 status;
+
+ if (dev->fCondResetPend) {
+ DEBUG
+ ("ft1000_hw:ft1000_chkcard:Card is being reset, return FALSE\n");
+ return TRUE;
+ }
+ /* Mask register is used to check for device presence since it is never
+ * set to zero.
+ */
+ status = ft1000_read_register(dev, &tempword, FT1000_REG_SUP_IMASK);
+ if (tempword == 0) {
+ DEBUG
+ ("ft1000_hw:ft1000_chkcard: IMASK = 0 Card not detected\n");
+ return FALSE;
+ }
+ /* The system will return the value of 0xffff for the version register
+ * if the device is not present.
+ */
+ status = ft1000_read_register(dev, &tempword, FT1000_REG_ASIC_ID);
+ if (tempword != 0x1b01) {
+ dev->status |= FT1000_STATUS_CLOSING;
+ DEBUG
+ ("ft1000_hw:ft1000_chkcard: Version = 0xffff Card not detected\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: ft1000_receive_cmd
+// Description: This function will read a message from the dpram area.
+// Input:
+// dev - network device structure
+// pbuffer - caller supply address to buffer
+// pnxtph - pointer to next pseudo header
+// Output:
+// Status = 0 (unsuccessful)
+// = 1 (successful)
+//
+//---------------------------------------------------------------------------
+static bool ft1000_receive_cmd(struct ft1000_usb *dev, u16 *pbuffer,
+ int maxsz, u16 *pnxtph)
+{
+ u16 size, ret;
+ u16 *ppseudohdr;
+ int i;
+ u16 tempword;
+
+ ret =
+ ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (u8 *) &size,
+ FT1000_MAG_PH_LEN_INDX);
+ size = ntohs(size) + PSEUDOSZ;
+ if (size > maxsz) {
+ DEBUG("FT1000:ft1000_receive_cmd:Invalid command length = %d\n",
+ size);
+ return FALSE;
+ } else {
+ ppseudohdr = (u16 *) pbuffer;
+ ft1000_write_register(dev, FT1000_DPRAM_MAG_RX_BASE,
+ FT1000_REG_DPRAM_ADDR);
+ ret =
+ ft1000_read_register(dev, pbuffer, FT1000_REG_MAG_DPDATAH);
+ pbuffer++;
+ ft1000_write_register(dev, FT1000_DPRAM_MAG_RX_BASE + 1,
+ FT1000_REG_DPRAM_ADDR);
+ for (i = 0; i <= (size >> 2); i++) {
+ ret =
+ ft1000_read_register(dev, pbuffer,
+ FT1000_REG_MAG_DPDATAL);
+ pbuffer++;
+ ret =
+ ft1000_read_register(dev, pbuffer,
+ FT1000_REG_MAG_DPDATAH);
+ pbuffer++;
+ }
+ /* copy odd aligned word */
+ ret =
+ ft1000_read_register(dev, pbuffer, FT1000_REG_MAG_DPDATAL);
+
+ pbuffer++;
+ ret =
+ ft1000_read_register(dev, pbuffer, FT1000_REG_MAG_DPDATAH);
+
+ pbuffer++;
+ if (size & 0x0001) {
+ /* copy odd byte from fifo */
+ ret =
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DPRAM_DATA);
+ *pbuffer = ntohs(tempword);
+ }
+ /* Check if pseudo header checksum is good
+ * Calculate pseudo header checksum
+ */
+ tempword = *ppseudohdr++;
+ for (i = 1; i < 7; i++)
+ tempword ^= *ppseudohdr++;
+
+ if ((tempword != *ppseudohdr))
+ return FALSE;
+
+ return TRUE;
+ }
+}
+
+static int ft1000_dsp_prov(void *arg)
+{
+ struct ft1000_usb *dev = (struct ft1000_usb *)arg;
+ struct ft1000_info *info = netdev_priv(dev->net);
+ u16 tempword;
+ u16 len;
+ u16 i = 0;
+ struct prov_record *ptr;
+ struct pseudo_hdr *ppseudo_hdr;
+ u16 *pmsg;
+ u16 status;
+ u16 TempShortBuf[256];
+
+ DEBUG("*** DspProv Entered\n");
+
+ while (list_empty(&info->prov_list) == 0) {
+ DEBUG("DSP Provisioning List Entry\n");
+
+ /* Check if doorbell is available */
+ DEBUG("check if doorbell is cleared\n");
+ status =
+ ft1000_read_register(dev, &tempword, FT1000_REG_DOORBELL);
+ if (status) {
+ DEBUG("ft1000_dsp_prov::ft1000_read_register error\n");
+ break;
+ }
+
+ while (tempword & FT1000_DB_DPRAM_TX) {
+ mdelay(10);
+ i++;
+ if (i == 10) {
+ DEBUG("FT1000:ft1000_dsp_prov:message drop\n");
+ return STATUS_FAILURE;
+ }
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DOORBELL);
+ }
+
+ if (!(tempword & FT1000_DB_DPRAM_TX)) {
+ DEBUG("*** Provision Data Sent to DSP\n");
+
+ /* Send provisioning data */
+ ptr =
+ list_entry(info->prov_list.next, struct prov_record,
+ list);
+ len = *(u16 *) ptr->pprov_data;
+ len = htons(len);
+ len += PSEUDOSZ;
+
+ pmsg = (u16 *) ptr->pprov_data;
+ ppseudo_hdr = (struct pseudo_hdr *)pmsg;
+ /* Insert slow queue sequence number */
+ ppseudo_hdr->seq_num = info->squeseqnum++;
+ ppseudo_hdr->portsrc = 0;
+ /* Calculate new checksum */
+ ppseudo_hdr->checksum = *pmsg++;
+ for (i = 1; i < 7; i++) {
+ ppseudo_hdr->checksum ^= *pmsg++;
+ }
+
+ TempShortBuf[0] = 0;
+ TempShortBuf[1] = htons(len);
+ memcpy(&TempShortBuf[2], ppseudo_hdr, len);
+
+ status =
+ ft1000_write_dpram32(dev, 0,
+ (u8 *) &TempShortBuf[0],
+ (unsigned short)(len + 2));
+ status =
+ ft1000_write_register(dev, FT1000_DB_DPRAM_TX,
+ FT1000_REG_DOORBELL);
+
+ list_del(&ptr->list);
+ kfree(ptr->pprov_data);
+ kfree(ptr);
+ }
+ msleep(10);
+ }
+
+ DEBUG("DSP Provisioning List Entry finished\n");
+
+ msleep(100);
+
+ dev->fProvComplete = 1;
+ info->CardReady = 1;
+
+ return STATUS_SUCCESS;
+}
+
+static int ft1000_proc_drvmsg(struct ft1000_usb *dev, u16 size)
+{
+ struct ft1000_info *info = netdev_priv(dev->net);
+ u16 msgtype;
+ u16 tempword;
+ struct media_msg *pmediamsg;
+ struct dsp_init_msg *pdspinitmsg;
+ struct drv_msg *pdrvmsg;
+ u16 i;
+ struct pseudo_hdr *ppseudo_hdr;
+ u16 *pmsg;
+ u16 status;
+ union {
+ u8 byte[2];
+ u16 wrd;
+ } convert;
+
+ char *cmdbuffer = kmalloc(1600, GFP_KERNEL);
+ if (!cmdbuffer)
+ return STATUS_FAILURE;
+
+ status = ft1000_read_dpram32(dev, 0x200, cmdbuffer, size);
+
+#ifdef JDEBUG
+ DEBUG("ft1000_proc_drvmsg:cmdbuffer\n");
+ for (i = 0; i < size; i += 5) {
+ if ((i + 5) < size)
+ DEBUG("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", cmdbuffer[i],
+ cmdbuffer[i + 1], cmdbuffer[i + 2],
+ cmdbuffer[i + 3], cmdbuffer[i + 4]);
+ else {
+ for (j = i; j < size; j++)
+ DEBUG("0x%x ", cmdbuffer[j]);
+ DEBUG("\n");
+ break;
+ }
+ }
+#endif
+ pdrvmsg = (struct drv_msg *)&cmdbuffer[2];
+ msgtype = ntohs(pdrvmsg->type);
+ DEBUG("ft1000_proc_drvmsg:Command message type = 0x%x\n", msgtype);
+ switch (msgtype) {
+ case MEDIA_STATE:{
+ DEBUG
+ ("ft1000_proc_drvmsg:Command message type = MEDIA_STATE");
+
+ pmediamsg = (struct media_msg *)&cmdbuffer[0];
+ if (info->ProgConStat != 0xFF) {
+ if (pmediamsg->state) {
+ DEBUG("Media is up\n");
+ if (info->mediastate == 0) {
+ if (dev->NetDevRegDone) {
+ netif_wake_queue(dev->
+ net);
+ }
+ info->mediastate = 1;
+ }
+ } else {
+ DEBUG("Media is down\n");
+ if (info->mediastate == 1) {
+ info->mediastate = 0;
+ if (dev->NetDevRegDone) {
+ }
+ info->ConTm = 0;
+ }
+ }
+ } else {
+ DEBUG("Media is down\n");
+ if (info->mediastate == 1) {
+ info->mediastate = 0;
+ info->ConTm = 0;
+ }
+ }
+ break;
+ }
+ case DSP_INIT_MSG:{
+ DEBUG
+ ("ft1000_proc_drvmsg:Command message type = DSP_INIT_MSG");
+
+ pdspinitmsg = (struct dsp_init_msg *)&cmdbuffer[2];
+ memcpy(info->DspVer, pdspinitmsg->DspVer, DSPVERSZ);
+ DEBUG("DSPVER = 0x%2x 0x%2x 0x%2x 0x%2x\n",
+ info->DspVer[0], info->DspVer[1], info->DspVer[2],
+ info->DspVer[3]);
+ memcpy(info->HwSerNum, pdspinitmsg->HwSerNum,
+ HWSERNUMSZ);
+ memcpy(info->Sku, pdspinitmsg->Sku, SKUSZ);
+ memcpy(info->eui64, pdspinitmsg->eui64, EUISZ);
+ DEBUG("EUI64=%2x.%2x.%2x.%2x.%2x.%2x.%2x.%2x\n",
+ info->eui64[0], info->eui64[1], info->eui64[2],
+ info->eui64[3], info->eui64[4], info->eui64[5],
+ info->eui64[6], info->eui64[7]);
+ dev->net->dev_addr[0] = info->eui64[0];
+ dev->net->dev_addr[1] = info->eui64[1];
+ dev->net->dev_addr[2] = info->eui64[2];
+ dev->net->dev_addr[3] = info->eui64[5];
+ dev->net->dev_addr[4] = info->eui64[6];
+ dev->net->dev_addr[5] = info->eui64[7];
+
+ if (ntohs(pdspinitmsg->length) ==
+ (sizeof(struct dsp_init_msg) - 20)) {
+ memcpy(info->ProductMode,
+ pdspinitmsg->ProductMode, MODESZ);
+ memcpy(info->RfCalVer, pdspinitmsg->RfCalVer,
+ CALVERSZ);
+ memcpy(info->RfCalDate, pdspinitmsg->RfCalDate,
+ CALDATESZ);
+ DEBUG("RFCalVer = 0x%2x 0x%2x\n",
+ info->RfCalVer[0], info->RfCalVer[1]);
+ }
+ break;
+ }
+ case DSP_PROVISION:{
+ DEBUG
+ ("ft1000_proc_drvmsg:Command message type = DSP_PROVISION\n");
+
+ /* kick off dspprov routine to start provisioning
+ * Send provisioning data to DSP
+ */
+ if (list_empty(&info->prov_list) == 0) {
+ dev->fProvComplete = 0;
+ status = ft1000_dsp_prov(dev);
+ if (status != STATUS_SUCCESS)
+ goto out;
+ } else {
+ dev->fProvComplete = 1;
+ status =
+ ft1000_write_register(dev, FT1000_DB_HB,
+ FT1000_REG_DOORBELL);
+ DEBUG
+ ("FT1000:drivermsg:No more DSP provisioning data in dsp image\n");
+ }
+ DEBUG("ft1000_proc_drvmsg:DSP PROVISION is done\n");
+ break;
+ }
+ case DSP_STORE_INFO:{
+ DEBUG
+ ("ft1000_proc_drvmsg:Command message type = DSP_STORE_INFO");
+
+ DEBUG("FT1000:drivermsg:Got DSP_STORE_INFO\n");
+ tempword = ntohs(pdrvmsg->length);
+ info->DSPInfoBlklen = tempword;
+ if (tempword < (MAX_DSP_SESS_REC - 4)) {
+ pmsg = (u16 *) &pdrvmsg->data[0];
+ for (i = 0; i < ((tempword + 1) / 2); i++) {
+ DEBUG
+ ("FT1000:drivermsg:dsp info data = 0x%x\n",
+ *pmsg);
+ info->DSPInfoBlk[i + 10] = *pmsg++;
+ }
+ } else {
+ info->DSPInfoBlklen = 0;
+ }
+ break;
+ }
+ case DSP_GET_INFO:{
+ DEBUG("FT1000:drivermsg:Got DSP_GET_INFO\n");
+ /* copy dsp info block to dsp */
+ dev->DrvMsgPend = 1;
+ /* allow any outstanding ioctl to finish */
+ mdelay(10);
+ status =
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ mdelay(10);
+ status =
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ mdelay(10);
+ status =
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX)
+ break;
+ }
+ }
+ /* Put message into Slow Queue
+ * Form Pseudo header
+ */
+ pmsg = (u16 *) info->DSPInfoBlk;
+ *pmsg++ = 0;
+ *pmsg++ =
+ htons(info->DSPInfoBlklen + 20 +
+ info->DSPInfoBlklen);
+ ppseudo_hdr =
+ (struct pseudo_hdr *)(u16 *) &info->DSPInfoBlk[2];
+ ppseudo_hdr->length =
+ htons(info->DSPInfoBlklen + 4 +
+ info->DSPInfoBlklen);
+ ppseudo_hdr->source = 0x10;
+ ppseudo_hdr->destination = 0x20;
+ ppseudo_hdr->portdest = 0;
+ ppseudo_hdr->portsrc = 0;
+ ppseudo_hdr->sh_str_id = 0;
+ ppseudo_hdr->control = 0;
+ ppseudo_hdr->rsvd1 = 0;
+ ppseudo_hdr->rsvd2 = 0;
+ ppseudo_hdr->qos_class = 0;
+ /* Insert slow queue sequence number */
+ ppseudo_hdr->seq_num = info->squeseqnum++;
+ /* Insert application id */
+ ppseudo_hdr->portsrc = 0;
+ /* Calculate new checksum */
+ ppseudo_hdr->checksum = *pmsg++;
+ for (i = 1; i < 7; i++)
+ ppseudo_hdr->checksum ^= *pmsg++;
+
+ info->DSPInfoBlk[10] = 0x7200;
+ info->DSPInfoBlk[11] = htons(info->DSPInfoBlklen);
+ status =
+ ft1000_write_dpram32(dev, 0,
+ (u8 *) &info->DSPInfoBlk[0],
+ (unsigned short)(info->
+ DSPInfoBlklen
+ + 22));
+ status =
+ ft1000_write_register(dev, FT1000_DB_DPRAM_TX,
+ FT1000_REG_DOORBELL);
+ dev->DrvMsgPend = 0;
+
+ break;
+ }
+
+ case GET_DRV_ERR_RPT_MSG:{
+ DEBUG("FT1000:drivermsg:Got GET_DRV_ERR_RPT_MSG\n");
+ /* copy driver error message to dsp */
+ dev->DrvMsgPend = 1;
+ /* allow any outstanding ioctl to finish */
+ mdelay(10);
+ status =
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX) {
+ mdelay(10);
+ status =
+ ft1000_read_register(dev, &tempword,
+ FT1000_REG_DOORBELL);
+ if (tempword & FT1000_DB_DPRAM_TX)
+ mdelay(10);
+ }
+
+ if ((tempword & FT1000_DB_DPRAM_TX) == 0) {
+ /* Put message into Slow Queue
+ * Form Pseudo header
+ */
+ pmsg = (u16 *) &tempbuffer[0];
+ ppseudo_hdr = (struct pseudo_hdr *)pmsg;
+ ppseudo_hdr->length = htons(0x0012);
+ ppseudo_hdr->source = 0x10;
+ ppseudo_hdr->destination = 0x20;
+ ppseudo_hdr->portdest = 0;
+ ppseudo_hdr->portsrc = 0;
+ ppseudo_hdr->sh_str_id = 0;
+ ppseudo_hdr->control = 0;
+ ppseudo_hdr->rsvd1 = 0;
+ ppseudo_hdr->rsvd2 = 0;
+ ppseudo_hdr->qos_class = 0;
+ /* Insert slow queue sequence number */
+ ppseudo_hdr->seq_num = info->squeseqnum++;
+ /* Insert application id */
+ ppseudo_hdr->portsrc = 0;
+ /* Calculate new checksum */
+ ppseudo_hdr->checksum = *pmsg++;
+ for (i = 1; i < 7; i++)
+ ppseudo_hdr->checksum ^= *pmsg++;
+
+ pmsg = (u16 *) &tempbuffer[16];
+ *pmsg++ = htons(RSP_DRV_ERR_RPT_MSG);
+ *pmsg++ = htons(0x000e);
+ *pmsg++ = htons(info->DSP_TIME[0]);
+ *pmsg++ = htons(info->DSP_TIME[1]);
+ *pmsg++ = htons(info->DSP_TIME[2]);
+ *pmsg++ = htons(info->DSP_TIME[3]);
+ convert.byte[0] = info->DspVer[0];
+ convert.byte[1] = info->DspVer[1];
+ *pmsg++ = convert.wrd;
+ convert.byte[0] = info->DspVer[2];
+ convert.byte[1] = info->DspVer[3];
+ *pmsg++ = convert.wrd;
+ *pmsg++ = htons(info->DrvErrNum);
+
+ card_send_command(dev,
+ (unsigned char *)&tempbuffer[0],
+ (u16) (0x0012 + PSEUDOSZ));
+ info->DrvErrNum = 0;
+ }
+ dev->DrvMsgPend = 0;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ status = STATUS_SUCCESS;
+out:
+ kfree(cmdbuffer);
+ DEBUG("return from ft1000_proc_drvmsg\n");
+ return status;
+}
+
+int ft1000_poll(void* dev_id)
+{
+ struct ft1000_usb *dev = (struct ft1000_usb *)dev_id;
+ struct ft1000_info *info = netdev_priv(dev->net);
+
+ u16 tempword;
+ u16 status;
+ u16 size;
+ int i;
+ u16 data;
+ u16 modulo;
+ u16 portid;
+ u16 nxtph;
+ struct dpram_blk *pdpram_blk;
+ struct pseudo_hdr *ppseudo_hdr;
+ unsigned long flags;
+
+ if (ft1000_chkcard(dev) == FALSE) {
+ DEBUG("ft1000_poll::ft1000_chkcard: failed\n");
+ return STATUS_FAILURE;
+ }
+
+ status = ft1000_read_register (dev, &tempword, FT1000_REG_DOORBELL);
+
+ if ( !status )
+ {
+
+ if (tempword & FT1000_DB_DPRAM_RX) {
+
+ status = ft1000_read_dpram16(dev, 0x200, (u8 *)&data, 0);
+ size = ntohs(data) + 16 + 2;
+ if (size % 4) {
+ modulo = 4 - (size % 4);
+ size = size + modulo;
+ }
+ status = ft1000_read_dpram16(dev, 0x201, (u8 *)&portid, 1);
+ portid &= 0xff;
+
+ if (size < MAX_CMD_SQSIZE) {
+ switch (portid)
+ {
+ case DRIVERID:
+ DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_DPRAM_RX : portid DRIVERID\n");
+
+ status = ft1000_proc_drvmsg (dev, size);
+ if (status != STATUS_SUCCESS )
+ return status;
+ break;
+ case DSPBCMSGID:
+ // This is a dsp broadcast message
+ // Check which application has registered for dsp broadcast messages
+
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if ( (dev->app_info[i].DspBCMsgFlag) && (dev->app_info[i].fileobject) &&
+ (dev->app_info[i].NumOfMsg < MAX_MSG_LIMIT) )
+ {
+ nxtph = FT1000_DPRAM_RX_BASE + 2;
+ pdpram_blk = ft1000_get_buffer (&freercvpool);
+ if (pdpram_blk != NULL) {
+ if ( ft1000_receive_cmd(dev, pdpram_blk->pbuffer, MAX_CMD_SQSIZE, &nxtph) ) {
+ ppseudo_hdr = (struct pseudo_hdr *)pdpram_blk->pbuffer;
+ // Put message into the appropriate application block
+ dev->app_info[i].nRxMsg++;
+ spin_lock_irqsave(&free_buff_lock, flags);
+ list_add_tail(&pdpram_blk->list, &dev->app_info[i].app_sqlist);
+ dev->app_info[i].NumOfMsg++;
+ spin_unlock_irqrestore(&free_buff_lock, flags);
+ wake_up_interruptible(&dev->app_info[i].wait_dpram_msg);
+ }
+ else {
+ dev->app_info[i].nRxMsgMiss++;
+ // Put memory back to free pool
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+ DEBUG("pdpram_blk::ft1000_get_buffer NULL\n");
+ }
+ }
+ else {
+ DEBUG("Out of memory in free receive command pool\n");
+ dev->app_info[i].nRxMsgMiss++;
+ }
+ }
+ }
+ break;
+ default:
+ pdpram_blk = ft1000_get_buffer (&freercvpool);
+
+ if (pdpram_blk != NULL) {
+ if ( ft1000_receive_cmd(dev, pdpram_blk->pbuffer, MAX_CMD_SQSIZE, &nxtph) ) {
+ ppseudo_hdr = (struct pseudo_hdr *)pdpram_blk->pbuffer;
+ // Search for correct application block
+ for (i=0; i<MAX_NUM_APP; i++) {
+ if (dev->app_info[i].app_id == ppseudo_hdr->portdest) {
+ break;
+ }
+ }
+
+ if (i == MAX_NUM_APP) {
+ DEBUG("FT1000:ft1000_parse_dpram_msg: No application matching id = %d\n", ppseudo_hdr->portdest);
+ // Put memory back to free pool
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+ }
+ else {
+ if (dev->app_info[i].NumOfMsg > MAX_MSG_LIMIT) {
+ // Put memory back to free pool
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+ }
+ else {
+ dev->app_info[i].nRxMsg++;
+ // Put message into the appropriate application block
+ list_add_tail(&pdpram_blk->list, &dev->app_info[i].app_sqlist);
+ dev->app_info[i].NumOfMsg++;
+ }
+ }
+ }
+ else {
+ // Put memory back to free pool
+ ft1000_free_buffer(pdpram_blk, &freercvpool);
+ }
+ }
+ else {
+ DEBUG("Out of memory in free receive command pool\n");
+ }
+ break;
+ }
+ }
+ else {
+ DEBUG("FT1000:dpc:Invalid total length for SlowQ = %d\n", size);
+ }
+ status = ft1000_write_register (dev, FT1000_DB_DPRAM_RX, FT1000_REG_DOORBELL);
+ }
+ else if (tempword & FT1000_DSP_ASIC_RESET) {
+
+ // Let's reset the ASIC from the Host side as well
+ status = ft1000_write_register (dev, ASIC_RESET_BIT, FT1000_REG_RESET);
+ status = ft1000_read_register (dev, &tempword, FT1000_REG_RESET);
+ i = 0;
+ while (tempword & ASIC_RESET_BIT) {
+ status = ft1000_read_register (dev, &tempword, FT1000_REG_RESET);
+ msleep(10);
+ i++;
+ if (i==100)
+ break;
+ }
+ if (i==100) {
+ DEBUG("Unable to reset ASIC\n");
+ return STATUS_SUCCESS;
+ }
+ msleep(10);
+ // Program WMARK register
+ status = ft1000_write_register (dev, 0x600, FT1000_REG_MAG_WATERMARK);
+ // clear ASIC reset doorbell
+ status = ft1000_write_register (dev, FT1000_DSP_ASIC_RESET, FT1000_REG_DOORBELL);
+ msleep(10);
+ }
+ else if (tempword & FT1000_ASIC_RESET_REQ) {
+ DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_ASIC_RESET_REQ\n");
+
+ // clear ASIC reset request from DSP
+ status = ft1000_write_register (dev, FT1000_ASIC_RESET_REQ, FT1000_REG_DOORBELL);
+ status = ft1000_write_register (dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
+ // copy dsp session record from Adapter block
+ status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPSess.Rec[0], 1024);
+ // Program WMARK register
+ status = ft1000_write_register (dev, 0x600, FT1000_REG_MAG_WATERMARK);
+ // ring doorbell to tell DSP that ASIC is out of reset
+ status = ft1000_write_register (dev, FT1000_ASIC_RESET_DSP, FT1000_REG_DOORBELL);
+ }
+ else if (tempword & FT1000_DB_COND_RESET) {
+ DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_COND_RESET\n");
+
+ if (dev->fAppMsgPend == 0) {
+ // Reset ASIC and DSP
+
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (u8 *)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (u8 *)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (u8 *)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX);
+ status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (u8 *)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX);
+ info->CardReady = 0;
+ info->DrvErrNum = DSP_CONDRESET_INFO;
+ DEBUG("ft1000_hw:DSP conditional reset requested\n");
+ info->ft1000_reset(dev->net);
+ }
+ else {
+ dev->fProvComplete = 0;
+ dev->fCondResetPend = 1;
+ }
+
+ ft1000_write_register(dev, FT1000_DB_COND_RESET, FT1000_REG_DOORBELL);
+ }
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h
new file mode 100644
index 00000000..3f4207fd
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h
@@ -0,0 +1,107 @@
+//---------------------------------------------------------------------------
+// FT1000 driver for Flarion Flash OFDM NIC Device
+//
+// Copyright (C) 2002 Flarion Technologies, All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 of the License, or (at your option) any
+// later version. This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details. You should have received a copy of the GNU General Public
+// License along with this program; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place -
+// Suite 330, Boston, MA 02111-1307, USA.
+//---------------------------------------------------------------------------
+//
+// File: ft1000_ioctl.h
+//
+// Description: Common structures and defines relating to IOCTL
+//
+// History:
+// 11/5/02 Whc Created.
+//
+//---------------------------------------------------------------------------//---------------------------------------------------------------------------
+#ifndef _FT1000IOCTLH_
+#define _FT1000IOCTLH_
+
+typedef struct _IOCTL_GET_VER
+{
+ unsigned long drv_ver;
+} __attribute__ ((packed)) IOCTL_GET_VER, *PIOCTL_GET_VER;
+
+//Data structure for Dsp statistics
+typedef struct _IOCTL_GET_DSP_STAT
+{
+ unsigned char DspVer[DSPVERSZ]; // DSP version number
+ unsigned char HwSerNum[HWSERNUMSZ]; // Hardware Serial Number
+ unsigned char Sku[SKUSZ]; // SKU
+ unsigned char eui64[EUISZ]; // EUI64
+ unsigned short ConStat; // Connection Status
+ // Bits 0-3 = Connection Status Field
+ // 0000=Idle (Disconnect)
+ // 0001=Searching
+ // 0010=Active (Connected)
+ // 0011=Waiting for L2 down
+ // 0100=Sleep
+ unsigned short LedStat; // Led Status
+ // Bits 0-3 = Signal Strength Field
+ // 0000 = -105dBm to -92dBm
+ // 0001 = -92dBm to -85dBm
+ // 0011 = -85dBm to -75dBm
+ // 0111 = -75dBm to -50dBm
+ // 1111 = -50dBm to 0dBm
+ // Bits 4-7 = Reserved
+ // Bits 8-11 = SNR Field
+ // 0000 = <2dB
+ // 0001 = 2dB to 8dB
+ // 0011 = 8dB to 15dB
+ // 0111 = 15dB to 22dB
+ // 1111 = >22dB
+ // Bits 12-15 = Reserved
+ unsigned long nTxPkts; // Number of packets transmitted from host to dsp
+ unsigned long nRxPkts; // Number of packets received from dsp to host
+ unsigned long nTxBytes; // Number of bytes transmitted from host to dsp
+ unsigned long nRxBytes; // Number of bytes received from dsp to host
+ unsigned long ConTm; // Current session connection time in seconds
+ unsigned char CalVer[CALVERSZ]; // Proprietary Calibration Version
+ unsigned char CalDate[CALDATESZ]; // Proprietary Calibration Date
+} __attribute__ ((packed)) IOCTL_GET_DSP_STAT, *PIOCTL_GET_DSP_STAT;
+
+//Data structure for Dual Ported RAM messaging between Host and Dsp
+typedef struct _IOCTL_DPRAM_BLK
+{
+ unsigned short total_len;
+ struct pseudo_hdr pseudohdr;
+ unsigned char buffer[1780];
+} __attribute__ ((packed)) IOCTL_DPRAM_BLK, *PIOCTL_DPRAM_BLK;
+
+typedef struct _IOCTL_DPRAM_COMMAND
+{
+ unsigned short extra;
+ IOCTL_DPRAM_BLK dpram_blk;
+} __attribute__ ((packed)) IOCTL_DPRAM_COMMAND, *PIOCTL_DPRAM_COMMAND;
+
+//
+// Custom IOCTL command codes
+//
+#define FT1000_MAGIC_CODE 'F'
+
+#define IOCTL_REGISTER_CMD 0
+#define IOCTL_SET_DPRAM_CMD 3
+#define IOCTL_GET_DPRAM_CMD 4
+#define IOCTL_GET_DSP_STAT_CMD 6
+#define IOCTL_GET_VER_CMD 7
+#define IOCTL_CONNECT 10
+#define IOCTL_DISCONNECT 11
+
+#define IOCTL_FT1000_GET_DSP_STAT _IOR (FT1000_MAGIC_CODE, IOCTL_GET_DSP_STAT_CMD, sizeof(IOCTL_GET_DSP_STAT) )
+#define IOCTL_FT1000_GET_VER _IOR (FT1000_MAGIC_CODE, IOCTL_GET_VER_CMD, sizeof(IOCTL_GET_VER) )
+#define IOCTL_FT1000_CONNECT _IOW (FT1000_MAGIC_CODE, IOCTL_CONNECT, 0 )
+#define IOCTL_FT1000_DISCONNECT _IOW (FT1000_MAGIC_CODE, IOCTL_DISCONNECT, 0 )
+#define IOCTL_FT1000_SET_DPRAM _IOW (FT1000_MAGIC_CODE, IOCTL_SET_DPRAM_CMD, sizeof(IOCTL_DPRAM_BLK) )
+#define IOCTL_FT1000_GET_DPRAM _IOR (FT1000_MAGIC_CODE, IOCTL_GET_DPRAM_CMD, sizeof(IOCTL_DPRAM_BLK) )
+#define IOCTL_FT1000_REGISTER _IOW (FT1000_MAGIC_CODE, IOCTL_REGISTER_CMD, sizeof(unsigned short *) )
+#endif // _FT1000IOCTLH_
+
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
new file mode 100644
index 00000000..eca6f029
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
@@ -0,0 +1,238 @@
+/*
+ * ft1000_proc.c - ft1000 proc interface
+ *
+ * Copyright (C) 2009-2010 Quintec
+ * (C) 2010 Open-nandra
+ * <marek.belisko@open-nandra.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/netdevice.h>
+
+
+#include "ft1000_usb.h"
+
+#define FT1000_PROC_DIR "ft1000"
+
+
+#define seq_putx(m, message, size, var) \
+ seq_printf(m, message); \
+ for(i = 0; i < (size - 1); i++) \
+ seq_printf(m, "%02x:", var[i]); \
+ seq_printf(m, "%02x\n", var[i])
+
+#define seq_putd(m, message, size, var) \
+ seq_printf(m, message); \
+ for(i = 0; i < (size - 1); i++) \
+ seq_printf(m, "%d.", var[i]); \
+ seq_printf(m, "%d\n", var[i])
+
+
+#define FTNET_PROC init_net.proc_net
+
+
+int ft1000_read_dpram16 (struct ft1000_usb *ft1000dev, u16 indx,
+ u8 *buffer, u8 highlow);
+
+
+static int ft1000ReadProc(struct seq_file *m, void *v)
+{
+ static const char *status[] = {
+ "Idle (Disconnect)",
+ "Searching",
+ "Active (Connected)",
+ "Waiting for L2",
+ "Sleep",
+ "No Coverage",
+ "",
+ "",
+ };
+ static const char *signal[] = { "", "*", "**", "***", "****" };
+
+ struct net_device *dev = m->private;
+ struct ft1000_info *info = netdev_priv(dev);
+ int i;
+ unsigned short ledStat;
+ unsigned short conStat;
+ int strength;
+ int quality;
+ struct timeval tv;
+ time_t delta;
+
+ if (info->ProgConStat != 0xFF) {
+ ft1000_read_dpram16(info->priv, FT1000_MAG_DSP_LED,
+ (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
+ info->LedStat = ntohs(ledStat);
+
+ ft1000_read_dpram16(info->priv, FT1000_MAG_DSP_CON_STATE,
+ (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
+ info->ConStat = ntohs(conStat);
+ do_gettimeofday(&tv);
+ delta = (tv.tv_sec - info->ConTm);
+ } else {
+ info->ConStat = 0xf;
+ delta = 0;
+ }
+
+ i = (info->LedStat) & 0xf;
+ switch (i) {
+ case 0x1:
+ strength = 1;
+ break;
+ case 0x3:
+ strength = 2;
+ break;
+ case 0x7:
+ strength = 3;
+ break;
+ case 0xf:
+ strength = 4;
+ break;
+ default:
+ strength = 0;
+ }
+
+ i = (info->LedStat >> 8) & 0xf;
+ switch (i) {
+ case 0x1:
+ quality = 1;
+ break;
+ case 0x3:
+ quality = 2;
+ break;
+ case 0x7:
+ quality = 3;
+ break;
+ case 0xf:
+ quality = 4;
+ break;
+ default:
+ quality = 0;
+ }
+
+ seq_printf(m, "Connection Time: %02ld:%02ld:%02ld\n",
+ ((delta / 3600) % 24), ((delta / 60) % 60), (delta % 60));
+ seq_printf(m, "Connection Time[s]: %ld\n", delta);
+ seq_printf(m, "Asic ID: %s\n",
+ (info->AsicID) == ELECTRABUZZ_ID ? "ELECTRABUZZ ASIC" : "MAGNEMITE ASIC");
+ seq_putx(m, "SKU: ", SKUSZ, info->Sku);
+ seq_putx(m, "EUI64: ", EUISZ, info->eui64);
+ seq_putd(m, "DSP version number: ", DSPVERSZ, info->DspVer);
+ seq_putx(m, "Hardware Serial Number: ", HWSERNUMSZ, info->HwSerNum);
+ seq_putx(m, "Caliberation Version: ", CALVERSZ, info->RfCalVer);
+ seq_putd(m, "Caliberation Date: ", CALDATESZ, info->RfCalDate);
+ seq_printf(m, "Media State: %s\n", (info->mediastate) ? "link" : "no link");
+ seq_printf(m, "Connection Status: %s\n", status[info->ConStat & 0x7]);
+ seq_printf(m, "RX packets: %ld\n", info->stats.rx_packets);
+ seq_printf(m, "TX packets: %ld\n", info->stats.tx_packets);
+ seq_printf(m, "RX bytes: %ld\n", info->stats.rx_bytes);
+ seq_printf(m, "TX bytes: %ld\n", info->stats.tx_bytes);
+ seq_printf(m, "Signal Strength: %s\n", signal[strength]);
+ seq_printf(m, "Signal Quality: %s\n", signal[quality]);
+ return 0;
+}
+
+/*
+ * seq_file wrappers for procfile show routines.
+ */
+static int ft1000_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ft1000ReadProc, PDE_DATA(inode));
+}
+
+static const struct file_operations ft1000_proc_fops = {
+ .open = ft1000_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+ft1000NotifyProc(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct ft1000_info *info;
+ struct proc_dir_entry *ft1000_proc_file;
+
+ info = netdev_priv(dev);
+
+ switch (event) {
+ case NETDEV_CHANGENAME:
+ remove_proc_entry(info->netdevname, info->ft1000_proc_dir);
+ ft1000_proc_file =
+ proc_create_data(dev->name, 0644, info->ft1000_proc_dir,
+ &ft1000_proc_fops, dev);
+ snprintf(info->netdevname, IFNAMSIZ, "%s", dev->name);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ft1000_netdev_notifier = {
+ .notifier_call = ft1000NotifyProc,
+};
+
+
+int ft1000_init_proc(struct net_device *dev)
+{
+ struct ft1000_info *info;
+ struct proc_dir_entry *ft1000_proc_file;
+ int ret = -EINVAL;
+
+ info = netdev_priv(dev);
+
+ info->ft1000_proc_dir = proc_mkdir(FT1000_PROC_DIR, FTNET_PROC);
+ if (info->ft1000_proc_dir == NULL) {
+ printk(KERN_WARNING "Unable to create %s dir.\n",
+ FT1000_PROC_DIR);
+ goto fail;
+ }
+
+ ft1000_proc_file =
+ proc_create_data(dev->name, 0644, info->ft1000_proc_dir,
+ &ft1000_proc_fops, dev);
+
+ if (!ft1000_proc_file) {
+ printk(KERN_WARNING "Unable to create /proc entry.\n");
+ goto fail_entry;
+ }
+
+ snprintf(info->netdevname, IFNAMSIZ, "%s", dev->name);
+
+ ret = register_netdevice_notifier(&ft1000_netdev_notifier);
+ if (ret)
+ goto fail_notif;
+
+ return 0;
+
+fail_notif:
+ remove_proc_entry(info->netdevname, info->ft1000_proc_dir);
+fail_entry:
+ remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC);
+fail:
+ return ret;
+}
+
+void ft1000_cleanup_proc(struct ft1000_info *info)
+{
+ remove_proc_entry(info->netdevname, info->ft1000_proc_dir);
+ remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC);
+ unregister_netdevice_notifier(&ft1000_netdev_notifier);
+}
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
new file mode 100644
index 00000000..614db55a
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
@@ -0,0 +1,263 @@
+/*=====================================================
+ * CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved.
+ *
+ *
+ * This file is part of Express Card USB Driver
+ *
+ * $Id:
+ *====================================================
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#include "ft1000_usb.h"
+
+#include <linux/kthread.h>
+
+MODULE_DESCRIPTION("FT1000 EXPRESS CARD DRIVER");
+MODULE_LICENSE("Dual MPL/GPL");
+MODULE_SUPPORTED_DEVICE("QFT FT1000 Express Cards");
+
+void *pFileStart;
+size_t FileLength;
+
+#define VENDOR_ID 0x1291 /* Qualcomm vendor id */
+#define PRODUCT_ID 0x11 /* fake product id */
+
+/* table of devices that work with this driver */
+static struct usb_device_id id_table[] = {
+ {USB_DEVICE(VENDOR_ID, PRODUCT_ID)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static bool gPollingfailed = FALSE;
+static int ft1000_poll_thread(void *arg)
+{
+ int ret;
+
+ while (!kthread_should_stop()) {
+ msleep(10);
+ if (!gPollingfailed) {
+ ret = ft1000_poll(arg);
+ if (ret != STATUS_SUCCESS) {
+ DEBUG("ft1000_poll_thread: polling failed\n");
+ gPollingfailed = TRUE;
+ }
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+static int ft1000_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *dev;
+ unsigned numaltsetting;
+ int i, ret = 0, size;
+
+ struct ft1000_usb *ft1000dev;
+ struct ft1000_info *pft1000info = NULL;
+ const struct firmware *dsp_fw;
+
+ ft1000dev = kzalloc(sizeof(struct ft1000_usb), GFP_KERNEL);
+ if (!ft1000dev)
+ return -ENOMEM;
+
+ dev = interface_to_usbdev(interface);
+ DEBUG("ft1000_probe: usb device descriptor info:\n");
+ DEBUG("ft1000_probe: number of configuration is %d\n",
+ dev->descriptor.bNumConfigurations);
+
+ ft1000dev->dev = dev;
+ ft1000dev->status = 0;
+ ft1000dev->net = NULL;
+ ft1000dev->tx_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ ft1000dev->rx_urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ DEBUG("ft1000_probe is called\n");
+ numaltsetting = interface->num_altsetting;
+ DEBUG("ft1000_probe: number of alt settings is :%d\n", numaltsetting);
+ iface_desc = interface->cur_altsetting;
+ DEBUG("ft1000_probe: number of endpoints is %d\n",
+ iface_desc->desc.bNumEndpoints);
+ DEBUG("ft1000_probe: descriptor type is %d\n",
+ iface_desc->desc.bDescriptorType);
+ DEBUG("ft1000_probe: interface number is %d\n",
+ iface_desc->desc.bInterfaceNumber);
+ DEBUG("ft1000_probe: alternatesetting is %d\n",
+ iface_desc->desc.bAlternateSetting);
+ DEBUG("ft1000_probe: interface class is %d\n",
+ iface_desc->desc.bInterfaceClass);
+ DEBUG("ft1000_probe: control endpoint info:\n");
+ DEBUG("ft1000_probe: descriptor0 type -- %d\n",
+ iface_desc->endpoint[0].desc.bmAttributes);
+ DEBUG("ft1000_probe: descriptor1 type -- %d\n",
+ iface_desc->endpoint[1].desc.bmAttributes);
+ DEBUG("ft1000_probe: descriptor2 type -- %d\n",
+ iface_desc->endpoint[2].desc.bmAttributes);
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint =
+ (struct usb_endpoint_descriptor *)&iface_desc->
+ endpoint[i].desc;
+ DEBUG("endpoint %d\n", i);
+ DEBUG("bEndpointAddress=%x, bmAttributes=%x\n",
+ endpoint->bEndpointAddress, endpoint->bmAttributes);
+ if ((endpoint->bEndpointAddress & USB_DIR_IN)
+ && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ ft1000dev->bulk_in_endpointAddr =
+ endpoint->bEndpointAddress;
+ DEBUG("ft1000_probe: in: %d\n",
+ endpoint->bEndpointAddress);
+ }
+
+ if (!(endpoint->bEndpointAddress & USB_DIR_IN)
+ && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ ft1000dev->bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ DEBUG("ft1000_probe: out: %d\n",
+ endpoint->bEndpointAddress);
+ }
+ }
+
+ DEBUG("bulk_in=%d, bulk_out=%d\n", ft1000dev->bulk_in_endpointAddr,
+ ft1000dev->bulk_out_endpointAddr);
+
+ ret = request_firmware(&dsp_fw, "ft3000.img", &dev->dev);
+ if (ret < 0) {
+ pr_err("Error request_firmware().\n");
+ goto err_fw;
+ }
+
+ size = max_t(uint, dsp_fw->size, 4096);
+ pFileStart = kmalloc(size, GFP_KERNEL);
+
+ if (!pFileStart) {
+ release_firmware(dsp_fw);
+ ret = -ENOMEM;
+ goto err_fw;
+ }
+
+ memcpy(pFileStart, dsp_fw->data, dsp_fw->size);
+ FileLength = dsp_fw->size;
+ release_firmware(dsp_fw);
+
+ DEBUG("ft1000_probe: start downloading dsp image...\n");
+
+ ret = init_ft1000_netdev(ft1000dev);
+ if (ret)
+ goto err_load;
+
+ pft1000info = netdev_priv(ft1000dev->net);
+
+ DEBUG("In probe: pft1000info=%p\n", pft1000info);
+ ret = dsp_reload(ft1000dev);
+ if (ret) {
+ pr_err("Problem with DSP image loading\n");
+ goto err_load;
+ }
+
+ gPollingfailed = FALSE;
+ ft1000dev->pPollThread =
+ kthread_run(ft1000_poll_thread, ft1000dev, "ft1000_poll");
+
+ if (IS_ERR(ft1000dev->pPollThread)) {
+ ret = PTR_ERR(ft1000dev->pPollThread);
+ goto err_load;
+ }
+
+ msleep(500);
+
+ while (!pft1000info->CardReady) {
+ if (gPollingfailed) {
+ ret = -EIO;
+ goto err_thread;
+ }
+ msleep(100);
+ DEBUG("ft1000_probe::Waiting for Card Ready\n");
+ }
+
+ DEBUG("ft1000_probe::Card Ready!!!! Registering network device\n");
+
+ ret = reg_ft1000_netdev(ft1000dev, interface);
+ if (ret)
+ goto err_thread;
+
+ ret = ft1000_init_proc(ft1000dev->net);
+ if (ret)
+ goto err_proc;
+
+ ft1000dev->NetDevRegDone = 1;
+
+ return 0;
+
+err_proc:
+ unregister_netdev(ft1000dev->net);
+ free_netdev(ft1000dev->net);
+err_thread:
+ kthread_stop(ft1000dev->pPollThread);
+err_load:
+ kfree(pFileStart);
+err_fw:
+ kfree(ft1000dev);
+ return ret;
+}
+
+static void ft1000_disconnect(struct usb_interface *interface)
+{
+ struct ft1000_info *pft1000info;
+ struct ft1000_usb *ft1000dev;
+
+ DEBUG("ft1000_disconnect is called\n");
+
+ pft1000info = (struct ft1000_info *) usb_get_intfdata(interface);
+ DEBUG("In disconnect pft1000info=%p\n", pft1000info);
+
+ if (pft1000info) {
+ ft1000dev = pft1000info->priv;
+ ft1000_cleanup_proc(pft1000info);
+ if (ft1000dev->pPollThread)
+ kthread_stop(ft1000dev->pPollThread);
+
+ DEBUG("ft1000_disconnect: threads are terminated\n");
+
+ if (ft1000dev->net) {
+ DEBUG("ft1000_disconnect: destroy char driver\n");
+ ft1000_destroy_dev(ft1000dev->net);
+ unregister_netdev(ft1000dev->net);
+ DEBUG
+ ("ft1000_disconnect: network device unregistered\n");
+ free_netdev(ft1000dev->net);
+
+ }
+
+ usb_free_urb(ft1000dev->rx_urb);
+ usb_free_urb(ft1000dev->tx_urb);
+
+ DEBUG("ft1000_disconnect: urb freed\n");
+
+ kfree(ft1000dev);
+ }
+ kfree(pFileStart);
+
+ return;
+}
+
+static struct usb_driver ft1000_usb_driver = {
+ .name = "ft1000usb",
+ .probe = ft1000_probe,
+ .disconnect = ft1000_disconnect,
+ .id_table = id_table,
+};
+
+module_usb_driver(ft1000_usb_driver);
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
new file mode 100644
index 00000000..bd1da1f1
--- /dev/null
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
@@ -0,0 +1,155 @@
+#ifndef _FT1000_USB_H_
+#define _FT1000_USB_H_
+
+#include "../ft1000.h"
+#include "ft1000_ioctl.h"
+#define FT1000_DRV_VER 0x01010403
+
+#define MAX_NUM_APP 6
+#define MAX_MSG_LIMIT 200
+#define NUM_OF_FREE_BUFFERS 1500
+
+#define PSEUDOSZ 16
+
+#define SUCCESS 0x00
+
+struct app_info_block {
+ u32 nTxMsg; /* DPRAM msg sent to DSP with app_id */
+ u32 nRxMsg; /* DPRAM msg rcv from dsp with app_id */
+ u32 nTxMsgReject; /* DPRAM msg rejected due to DSP doorbell set */
+ u32 nRxMsgMiss; /* DPRAM msg dropped due to overflow */
+ struct fown_struct *fileobject;/* Application's file object */
+ u16 app_id; /* Application id */
+ int DspBCMsgFlag;
+ int NumOfMsg; /* number of messages queued up */
+ wait_queue_head_t wait_dpram_msg;
+ struct list_head app_sqlist; /* link list of msgs for applicaton on slow queue */
+} __packed;
+
+#define DEBUG(args...) printk(KERN_INFO args)
+
+#define FALSE 0
+#define TRUE 1
+
+#define STATUS_SUCCESS 0
+#define STATUS_FAILURE 0x1001
+
+#define FT1000_STATUS_CLOSING 0x01
+
+#define DSPBCMSGID 0x10
+
+/* Electrabuzz specific DPRAM mapping */
+/* this is used by ft1000_usb driver - isn't that a bug? */
+#undef FT1000_DPRAM_RX_BASE
+#define FT1000_DPRAM_RX_BASE 0x1800 /* RX AREA (SlowQ) */
+
+/* MEMORY MAP FOR MAGNEMITE */
+/* the indexes are swapped comparing to PCMCIA - is it OK or a bug? */
+#undef FT1000_MAG_DSP_LED_INDX
+#define FT1000_MAG_DSP_LED_INDX 0x1 /* dsp led status for PAD device */
+#undef FT1000_MAG_DSP_CON_STATE_INDX
+#define FT1000_MAG_DSP_CON_STATE_INDX 0x0 /* DSP Connection Status Info */
+
+/* Maximum times trying to get ASIC out of reset */
+#define MAX_ASIC_RESET_CNT 20
+
+#define MAX_BUF_SIZE 4096
+
+struct ft1000_debug_dirs {
+ struct list_head list;
+ struct dentry *dent;
+ struct dentry *file;
+ int int_number;
+};
+
+struct ft1000_usb {
+ struct usb_device *dev;
+ struct net_device *net;
+
+ u32 status;
+
+ struct urb *rx_urb;
+ struct urb *tx_urb;
+
+ u8 tx_buf[MAX_BUF_SIZE];
+ u8 rx_buf[MAX_BUF_SIZE];
+
+ u8 bulk_in_endpointAddr;
+ u8 bulk_out_endpointAddr;
+
+ struct task_struct *pPollThread;
+ unsigned char fcodeldr;
+ unsigned char bootmode;
+ unsigned char usbboot;
+ unsigned short dspalive;
+ bool fProvComplete;
+ bool fCondResetPend;
+ bool fAppMsgPend;
+ int DeviceCreated;
+ int NetDevRegDone;
+ u8 CardNumber;
+ u8 DeviceName[15];
+ struct ft1000_debug_dirs nodes;
+ spinlock_t fifo_lock;
+ int appcnt;
+ struct app_info_block app_info[MAX_NUM_APP];
+ u16 DrvMsgPend;
+ unsigned short tempbuf[32];
+} __packed;
+
+
+struct dpram_blk {
+ struct list_head list;
+ u16 *pbuffer;
+} __packed;
+
+int ft1000_read_register(struct ft1000_usb *ft1000dev,
+ u16 *Data, u16 nRegIndx);
+int ft1000_write_register(struct ft1000_usb *ft1000dev,
+ u16 value, u16 nRegIndx);
+int ft1000_read_dpram32(struct ft1000_usb *ft1000dev,
+ u16 indx, u8 *buffer, u16 cnt);
+int ft1000_write_dpram32(struct ft1000_usb *ft1000dev,
+ u16 indx, u8 *buffer, u16 cnt);
+int ft1000_read_dpram16(struct ft1000_usb *ft1000dev,
+ u16 indx, u8 *buffer, u8 highlow);
+int ft1000_write_dpram16(struct ft1000_usb *ft1000dev,
+ u16 indx, u16 value, u8 highlow);
+int fix_ft1000_read_dpram32(struct ft1000_usb *ft1000dev,
+ u16 indx, u8 *buffer);
+int fix_ft1000_write_dpram32(struct ft1000_usb *ft1000dev,
+ u16 indx, u8 *buffer);
+
+extern void *pFileStart;
+extern size_t FileLength;
+extern int numofmsgbuf;
+
+int ft1000_close(struct net_device *dev);
+u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart,
+ u32 FileLength);
+
+extern struct list_head freercvpool;
+
+extern spinlock_t free_buff_lock; /* lock to arbitrate free buffer list for receive command data */
+
+int ft1000_create_dev(struct ft1000_usb *dev);
+void ft1000_destroy_dev(struct net_device *dev);
+extern void card_send_command(struct ft1000_usb *ft1000dev,
+ void *ptempbuffer, int size);
+
+struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist);
+void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist);
+
+int dsp_reload(struct ft1000_usb *ft1000dev);
+int init_ft1000_netdev(struct ft1000_usb *ft1000dev);
+struct usb_interface;
+int reg_ft1000_netdev(struct ft1000_usb *ft1000dev,
+ struct usb_interface *intf);
+int ft1000_poll(void *dev_id);
+
+int ft1000_init_proc(struct net_device *dev);
+void ft1000_cleanup_proc(struct ft1000_info *info);
+
+
+
+#endif