Staging: add w35und wifi driver
This is driver for w35und usb wifi -- also in kohjinsha
subnotebook. It should work well enough to associate and ping, but it
obviously needs to be rewritten two more times...
OTOH worst horrors (like embedded wifi stack) should have been fixed
already...
Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/winbond/linux/common.h b/drivers/staging/winbond/linux/common.h
new file mode 100644
index 0000000..6b00bad
--- /dev/null
+++ b/drivers/staging/winbond/linux/common.h
@@ -0,0 +1,143 @@
+//
+// common.h
+//
+// This file contains the OS dependant definition and function.
+// Every OS has this file individual.
+//
+
+#define DebugUsbdStatusInformation( _A )
+
+#ifndef COMMON_DEF
+#define COMMON_DEF
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/kernel.h> //need for kernel alert
+#include <linux/autoconf.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h> //memory allocate
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>//need for init and exit modules marco
+#include <linux/ctype.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+#include <net/iw_handler.h>
+#include <linux/skbuff.h>
+
+
+//#define DEBUG_ENABLED 1
+
+
+
+//===============================================================
+// Common type definition
+//===============================================================
+
+typedef u8* PUCHAR;
+typedef s8* PCHAR;
+typedef u8* PBOOLEAN;
+typedef u16* PUSHORT;
+typedef u32* PULONG;
+typedef s16* PSHORT;
+
+
+//===========================================
+#define IGNORE 2
+#define SUCCESS 1
+#define FAILURE 0
+
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+// PD43 20021108
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define STATUS_MEDIA_CONNECT 1
+#define STATUS_MEDIA_DISCONNECT 0
+
+#ifndef BIT
+#define BIT(x) (1 << (x))
+#endif
+
+typedef struct urb * PURB;
+
+
+
+//==================================================================================================
+// Common function definition
+//==================================================================================================
+#ifndef abs
+#define abs(_T) ((_T) < 0 ? -_T : _T)
+#endif
+#define DEBUG_ENABLED
+#define ETH_LENGTH_OF_ADDRESS 6
+#ifdef DEBUG_ENABLED
+#define WBDEBUG( _M ) printk _M
+#else
+#define WBDEBUG( _M ) 0
+#endif
+
+#define OS_DISCONNECTED 0
+#define OS_CONNECTED 1
+
+
+#define OS_EVENT_INDICATE( _A, _B, _F )
+#define OS_PMKID_STATUS_EVENT( _A )
+
+
+/* Uff, no, longs are not atomic on all architectures Linux
+ * supports. This should really use atomic_t */
+
+#define OS_ATOMIC u32
+#define OS_ATOMIC_READ( _A, _V ) _V
+#define OS_ATOMIC_INC( _A, _V ) EncapAtomicInc( _A, (void*)_V )
+#define OS_ATOMIC_DEC( _A, _V ) EncapAtomicDec( _A, (void*)_V )
+#define OS_MEMORY_CLEAR( _A, _S ) memset( (PUCHAR)_A,0,_S)
+#define OS_MEMORY_COMPARE( _A, _B, _S ) (memcmp(_A,_B,_S)? 0 : 1) // Definition is reverse with Ndis 1: the same 0: different
+
+
+#define OS_SPIN_LOCK spinlock_t
+#define OS_SPIN_LOCK_ALLOCATE( _S ) spin_lock_init( _S );
+#define OS_SPIN_LOCK_FREE( _S )
+#define OS_SPIN_LOCK_ACQUIRED( _S ) spin_lock_irq( _S )
+#define OS_SPIN_LOCK_RELEASED( _S ) spin_unlock_irq( _S );
+
+#define OS_TIMER struct timer_list
+#define OS_TIMER_INITIAL( _T, _F, _P ) \
+{ \
+ init_timer( _T ); \
+ (_T)->function = (void *)_F##_1a; \
+ (_T)->data = (unsigned long)_P; \
+}
+
+// _S : Millisecond
+// 20060420 At least 1 large than jiffies
+#define OS_TIMER_SET( _T, _S ) \
+{ \
+ (_T)->expires = jiffies + ((_S*HZ+999)/1000);\
+ add_timer( _T ); \
+}
+#define OS_TIMER_CANCEL( _T, _B ) del_timer_sync( _T )
+#define OS_TIMER_GET_SYS_TIME( _T ) (*_T=jiffies)
+
+
+#endif // COMMON_DEF
+
diff --git a/drivers/staging/winbond/linux/sysdef.h b/drivers/staging/winbond/linux/sysdef.h
new file mode 100644
index 0000000..d46d63e
--- /dev/null
+++ b/drivers/staging/winbond/linux/sysdef.h
@@ -0,0 +1,73 @@
+
+
+//
+// Winbond WLAN System Configuration defines
+//
+
+//=====================================================================
+// Current directory is Linux
+// The definition WB_LINUX is a keyword for this OS
+//=====================================================================
+#ifndef SYS_DEF_H
+#define SYS_DEF_H
+#define WB_LINUX
+#define WB_LINUX_WPA_PSK
+
+
+//#define _IBSS_BEACON_SEQ_STICK_
+#define _USE_FALLBACK_RATE_
+//#define ANTDIV_DEFAULT_ON
+
+#define _WPA2_ // 20061122 It's needed for current Linux driver
+
+
+#ifndef _WPA_PSK_DEBUG
+#undef _WPA_PSK_DEBUG
+#endif
+
+// debug print options, mark what debug you don't need
+
+#ifdef FULL_DEBUG
+#define _PE_STATE_DUMP_
+#define _PE_TX_DUMP_
+#define _PE_RX_DUMP_
+#define _PE_OID_DUMP_
+#define _PE_DTO_DUMP_
+#define _PE_REG_DUMP_
+#define _PE_USB_INI_DUMP_
+#endif
+
+
+
+#include "common.h" // Individual file depends on OS
+
+#include "../wb35_ver.h"
+#include "../mac_structures.h"
+#include "../ds_tkip.h"
+#include "../localpara.h"
+#include "../sme_s.h"
+#include "../scan_s.h"
+#include "../mds_s.h"
+#include "../mlme_s.h"
+#include "../bssdscpt.h"
+#include "../sme_api.h"
+#include "../gl_80211.h"
+#include "../mto.h"
+#include "../wblinux_s.h"
+#include "../wbhal_s.h"
+
+
+#include "../adapter.h"
+
+#include "../mlme_mib.h"
+#include "../mds_f.h"
+#include "../bss_f.h"
+#include "../mlmetxrx_f.h"
+#include "../mto_f.h"
+#include "../wbhal_f.h"
+#include "../wblinux_f.h"
+// Kernel Timer resolution, NDIS is 10ms, 10000us
+#define MIN_TIMEOUT_VAL (10) //ms
+
+
+#endif
diff --git a/drivers/staging/winbond/linux/wb35reg.c b/drivers/staging/winbond/linux/wb35reg.c
new file mode 100644
index 0000000..2c0b454
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35reg.c
@@ -0,0 +1,747 @@
+#include "sysdef.h"
+
+extern void phy_calibration_winbond(hw_data_t *phw_data, u32 frequency);
+
+// TRUE : read command process successfully
+// FALSE : register not support
+// RegisterNo : start base
+// pRegisterData : data point
+// NumberOfData : number of register data
+// Flag : AUTO_INCREMENT - RegisterNo will auto increment 4
+// NO_INCREMENT - Function will write data into the same register
+unsigned char
+Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PURB pUrb = NULL;
+ PREG_QUEUE pRegQueue = NULL;
+ u16 UrbSize;
+ struct usb_ctrlrequest *dr;
+ u16 i, DataSize = NumberOfData*4;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // Trying to use burst write function if use new hardware
+ UrbSize = sizeof(REG_QUEUE) + DataSize + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if( pUrb && pRegQueue ) {
+ pRegQueue->DIRECT = 2;// burst write register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->pBuffer = (PULONG)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ memcpy( pRegQueue->pBuffer, pRegisterData, DataSize );
+ //the function for reversing register data from little endian to big endian
+ for( i=0; i<NumberOfData ; i++ )
+ pRegQueue->pBuffer[i] = cpu_to_le32( pRegQueue->pBuffer[i] );
+
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE) + DataSize);
+ dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE;
+ dr->bRequest = 0x04; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16( Flag ); // 0: Register number auto-increment, 1: No auto increment
+ dr->wIndex = cpu_to_le16( RegisterNo );
+ dr->wLength = cpu_to_le16( DataSize );
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ if (pWb35Reg->pRegFirst == NULL)
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start(pHwData);
+
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb(pUrb);
+ if (pRegQueue)
+ kfree(pRegQueue);
+ return FALSE;
+ }
+ return FALSE;
+}
+
+void
+Wb35Reg_Update(phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ switch (RegisterNo) {
+ case 0x3b0: pWb35Reg->U1B0 = RegisterValue; break;
+ case 0x3bc: pWb35Reg->U1BC_LEDConfigure = RegisterValue; break;
+ case 0x400: pWb35Reg->D00_DmaControl = RegisterValue; break;
+ case 0x800: pWb35Reg->M00_MacControl = RegisterValue; break;
+ case 0x804: pWb35Reg->M04_MulticastAddress1 = RegisterValue; break;
+ case 0x808: pWb35Reg->M08_MulticastAddress2 = RegisterValue; break;
+ case 0x824: pWb35Reg->M24_MacControl = RegisterValue; break;
+ case 0x828: pWb35Reg->M28_MacControl = RegisterValue; break;
+ case 0x82c: pWb35Reg->M2C_MacControl = RegisterValue; break;
+ case 0x838: pWb35Reg->M38_MacControl = RegisterValue; break;
+ case 0x840: pWb35Reg->M40_MacControl = RegisterValue; break;
+ case 0x844: pWb35Reg->M44_MacControl = RegisterValue; break;
+ case 0x848: pWb35Reg->M48_MacControl = RegisterValue; break;
+ case 0x84c: pWb35Reg->M4C_MacStatus = RegisterValue; break;
+ case 0x860: pWb35Reg->M60_MacControl = RegisterValue; break;
+ case 0x868: pWb35Reg->M68_MacControl = RegisterValue; break;
+ case 0x870: pWb35Reg->M70_MacControl = RegisterValue; break;
+ case 0x874: pWb35Reg->M74_MacControl = RegisterValue; break;
+ case 0x878: pWb35Reg->M78_ERPInformation = RegisterValue; break;
+ case 0x87C: pWb35Reg->M7C_MacControl = RegisterValue; break;
+ case 0x880: pWb35Reg->M80_MacControl = RegisterValue; break;
+ case 0x884: pWb35Reg->M84_MacControl = RegisterValue; break;
+ case 0x888: pWb35Reg->M88_MacControl = RegisterValue; break;
+ case 0x898: pWb35Reg->M98_MacControl = RegisterValue; break;
+ case 0x100c: pWb35Reg->BB0C = RegisterValue; break;
+ case 0x102c: pWb35Reg->BB2C = RegisterValue; break;
+ case 0x1030: pWb35Reg->BB30 = RegisterValue; break;
+ case 0x103c: pWb35Reg->BB3C = RegisterValue; break;
+ case 0x1048: pWb35Reg->BB48 = RegisterValue; break;
+ case 0x104c: pWb35Reg->BB4C = RegisterValue; break;
+ case 0x1050: pWb35Reg->BB50 = RegisterValue; break;
+ case 0x1054: pWb35Reg->BB54 = RegisterValue; break;
+ case 0x1058: pWb35Reg->BB58 = RegisterValue; break;
+ case 0x105c: pWb35Reg->BB5C = RegisterValue; break;
+ case 0x1060: pWb35Reg->BB60 = RegisterValue; break;
+ }
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+unsigned char
+Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ int ret = -1;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ RegisterValue = cpu_to_le32(RegisterValue);
+
+ // update the register by send usb message------------------------------------
+ pWb35Reg->SyncIoPause = 1;
+
+ // 20060717.5 Wait until EP0VM stop
+ while (pWb35Reg->EP0vm_state != VM_STOP)
+ OS_SLEEP(10000);
+
+ // Sync IoCallDriver
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+ ret = usb_control_msg( pHwData->WbUsb.udev,
+ usb_sndctrlpipe( pHwData->WbUsb.udev, 0 ),
+ 0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x0,RegisterNo, &RegisterValue, 4, HZ*100 );
+ pWb35Reg->EP0vm_state = VM_STOP;
+ pWb35Reg->SyncIoPause = 0;
+
+ Wb35Reg_EP0VM_start(pHwData);
+
+ if (ret < 0) {
+ #ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 Write register usb message sending error\n"));
+ #endif
+
+ pHwData->SurpriseRemove = 1; // 20060704.2
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+unsigned char
+Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ struct usb_ctrlrequest *dr;
+ PURB pUrb = NULL;
+ PREG_QUEUE pRegQueue = NULL;
+ u16 UrbSize;
+
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // update the register by send urb request------------------------------------
+ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if (pUrb && pRegQueue) {
+ pRegQueue->DIRECT = 1;// burst write register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->VALUE = cpu_to_le32(RegisterValue);
+ pRegQueue->RESERVED_VALID = FALSE;
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE;
+ dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16(0x0);
+ dr->wIndex = cpu_to_le16(RegisterNo);
+ dr->wLength = cpu_to_le16(4);
+
+ // Enter the sending queue
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+
+ OS_SPIN_LOCK_ACQUIRED(&pWb35Reg->EP0VM_spin_lock );
+ if (pWb35Reg->pRegFirst == NULL)
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start(pHwData);
+
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb(pUrb);
+ kfree(pRegQueue);
+ return FALSE;
+ }
+}
+
+//This command will be executed with a user defined value. When it completes,
+//this value is useful. For example, hal_set_current_channel will use it.
+// TRUE : read command process successfully
+// FALSE : register not support
+unsigned char
+Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue,
+ PCHAR pValue, s8 Len)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ struct usb_ctrlrequest *dr;
+ PURB pUrb = NULL;
+ PREG_QUEUE pRegQueue = NULL;
+ u16 UrbSize;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // update the register by send urb request------------------------------------
+ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC((void* *) &pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if (pUrb && pRegQueue) {
+ pRegQueue->DIRECT = 1;// burst write register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->VALUE = cpu_to_le32(RegisterValue);
+ //NOTE : Users must guarantee the size of value will not exceed the buffer size.
+ memcpy(pRegQueue->RESERVED, pValue, Len);
+ pRegQueue->RESERVED_VALID = TRUE;
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE;
+ dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16(0x0);
+ dr->wIndex = cpu_to_le16(RegisterNo);
+ dr->wLength = cpu_to_le16(4);
+
+ // Enter the sending queue
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+ OS_SPIN_LOCK_ACQUIRED (&pWb35Reg->EP0VM_spin_lock );
+ if( pWb35Reg->pRegFirst == NULL )
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED ( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start(pHwData);
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb(pUrb);
+ kfree(pRegQueue);
+ return FALSE;
+ }
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+// pRegisterValue : It must be a resident buffer due to asynchronous read register.
+unsigned char
+Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PULONG pltmp = pRegisterValue;
+ int ret = -1;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // Read the register by send usb message------------------------------------
+
+ pWb35Reg->SyncIoPause = 1;
+
+ // 20060717.5 Wait until EP0VM stop
+ while (pWb35Reg->EP0vm_state != VM_STOP)
+ OS_SLEEP(10000);
+
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+ ret = usb_control_msg( pHwData->WbUsb.udev,
+ usb_rcvctrlpipe(pHwData->WbUsb.udev, 0),
+ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
+ 0x0, RegisterNo, pltmp, 4, HZ*100 );
+
+ *pRegisterValue = cpu_to_le32(*pltmp);
+
+ pWb35Reg->EP0vm_state = VM_STOP;
+
+ Wb35Reg_Update( pHwData, RegisterNo, *pRegisterValue );
+ pWb35Reg->SyncIoPause = 0;
+
+ Wb35Reg_EP0VM_start( pHwData );
+
+ if (ret < 0) {
+ #ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 Read register usb message sending error\n"));
+ #endif
+
+ pHwData->SurpriseRemove = 1; // 20060704.2
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+// pRegisterValue : It must be a resident buffer due to asynchronous read register.
+unsigned char
+Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ struct usb_ctrlrequest * dr;
+ PURB pUrb;
+ PREG_QUEUE pRegQueue;
+ u16 UrbSize;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // update the variable by send Urb to read register ------------------------------------
+ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if( pUrb && pRegQueue )
+ {
+ pRegQueue->DIRECT = 0;// read register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->pBuffer = pRegisterValue;
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr->bRequestType = USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN;
+ dr->bRequest = 0x01; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16(0x0);
+ dr->wIndex = cpu_to_le16 (RegisterNo);
+ dr->wLength = cpu_to_le16 (4);
+
+ // Enter the sending queue
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+ OS_SPIN_LOCK_ACQUIRED ( &pWb35Reg->EP0VM_spin_lock );
+ if( pWb35Reg->pRegFirst == NULL )
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start( pHwData );
+
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb( pUrb );
+ kfree(pRegQueue);
+ return FALSE;
+ }
+}
+
+
+void
+Wb35Reg_EP0VM_start( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Reg->RegFireCount) == 1) {
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+ Wb35Reg_EP0VM(pHwData);
+ } else
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
+}
+
+void
+Wb35Reg_EP0VM(phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PURB pUrb;
+ struct usb_ctrlrequest *dr;
+ PULONG pBuffer;
+ int ret = -1;
+ PREG_QUEUE pRegQueue;
+
+
+ if (pWb35Reg->SyncIoPause)
+ goto cleanup;
+
+ if (pHwData->SurpriseRemove)
+ goto cleanup;
+
+ // Get the register data and send to USB through Irp
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ pRegQueue = pWb35Reg->pRegFirst;
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ if (!pRegQueue)
+ goto cleanup;
+
+ // Get an Urb, send it
+ pUrb = (PURB)pRegQueue->pUrb;
+
+ dr = pRegQueue->pUsbReq;
+ pUrb = pRegQueue->pUrb;
+ pBuffer = pRegQueue->pBuffer;
+ if (pRegQueue->DIRECT == 1) // output
+ pBuffer = &pRegQueue->VALUE;
+
+ usb_fill_control_urb( pUrb, pHwData->WbUsb.udev,
+ REG_DIRECTION(pHwData->WbUsb.udev,pRegQueue),
+ (PUCHAR)dr,pBuffer,cpu_to_le16(dr->wLength),
+ Wb35Reg_EP0VM_complete, (void*)pHwData);
+
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+
+ ret = wb_usb_submit_urb( pUrb );
+
+ if (ret < 0) {
+#ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 Irp sending error\n"));
+#endif
+ goto cleanup;
+ }
+
+ return;
+
+ cleanup:
+ pWb35Reg->EP0vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
+}
+
+
+void
+Wb35Reg_EP0VM_complete(PURB pUrb)
+{
+ phw_data_t pHwData = (phw_data_t)pUrb->context;
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PREG_QUEUE pRegQueue;
+
+
+ // Variable setting
+ pWb35Reg->EP0vm_state = VM_COMPLETED;
+ pWb35Reg->EP0VM_status = pUrb->status;
+
+ if (pHwData->SurpriseRemove) { // Let WbWlanHalt to handle surprise remove
+ pWb35Reg->EP0vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
+ } else {
+ // Complete to send, remove the URB from the first
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ pRegQueue = pWb35Reg->pRegFirst;
+ if (pRegQueue == pWb35Reg->pRegLast)
+ pWb35Reg->pRegLast = NULL;
+ pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next;
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ if (pWb35Reg->EP0VM_status) {
+#ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 IoCompleteRoutine return error\n"));
+ DebugUsbdStatusInformation( pWb35Reg->EP0VM_status );
+#endif
+ pWb35Reg->EP0vm_state = VM_STOP;
+ pHwData->SurpriseRemove = 1;
+ } else {
+ // Success. Update the result
+
+ // Start the next send
+ Wb35Reg_EP0VM(pHwData);
+ }
+
+ kfree(pRegQueue);
+ }
+
+ usb_free_urb(pUrb);
+}
+
+
+void
+Wb35Reg_destroy(phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PURB pUrb;
+ PREG_QUEUE pRegQueue;
+
+
+ Uxx_power_off_procedure(pHwData);
+
+ // Wait for Reg operation completed
+ do {
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
+ } while (pWb35Reg->EP0vm_state != VM_STOP);
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
+
+ // Release all the data in RegQueue
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ pRegQueue = pWb35Reg->pRegFirst;
+ while (pRegQueue) {
+ if (pRegQueue == pWb35Reg->pRegLast)
+ pWb35Reg->pRegLast = NULL;
+ pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next;
+
+ pUrb = pRegQueue->pUrb;
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ if (pUrb) {
+ usb_free_urb(pUrb);
+ kfree(pRegQueue);
+ } else {
+ #ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 queue release error\n"));
+ #endif
+ }
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+
+ pRegQueue = pWb35Reg->pRegFirst;
+ }
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Free resource
+ OS_SPIN_LOCK_FREE( &pWb35Reg->EP0VM_spin_lock );
+}
+
+//====================================================================================
+// The function can be run in passive-level only.
+//====================================================================================
+unsigned char Wb35Reg_initial(phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg=&pHwData->Wb35Reg;
+ u32 ltmp;
+ u32 SoftwareSet, VCO_trim, TxVga, Region_ScanInterval;
+
+ // Spin lock is acquired for read and write IRP command
+ OS_SPIN_LOCK_ALLOCATE( &pWb35Reg->EP0VM_spin_lock );
+
+ // Getting RF module type from EEPROM ------------------------------------
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x080d0000 ); // Start EEPROM access + Read + address(0x0d)
+ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp );
+
+ //Update RF module type and determine the PHY type by inf or EEPROM
+ pWb35Reg->EEPROMPhyType = (u8)( ltmp & 0xff );
+ // 0 V MAX2825, 1 V MAX2827, 2 V MAX2828, 3 V MAX2829
+ // 16V AL2230, 17 - AL7230, 18 - AL2230S
+ // 32 Reserved
+ // 33 - W89RF242(TxVGA 0~19), 34 - W89RF242(TxVGA 0~34)
+ if (pWb35Reg->EEPROMPhyType != RF_DECIDE_BY_INF) {
+ if( (pWb35Reg->EEPROMPhyType == RF_MAXIM_2825) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2827) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2828) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2829) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_V1) ||
+ (pWb35Reg->EEPROMPhyType == RF_AIROHA_2230) ||
+ (pWb35Reg->EEPROMPhyType == RF_AIROHA_2230S) ||
+ (pWb35Reg->EEPROMPhyType == RF_AIROHA_7230) ||
+ (pWb35Reg->EEPROMPhyType == RF_WB_242) ||
+ (pWb35Reg->EEPROMPhyType == RF_WB_242_1))
+ pHwData->phy_type = pWb35Reg->EEPROMPhyType;
+ }
+
+ // Power On procedure running. The relative parameter will be set according to phy_type
+ Uxx_power_on_procedure( pHwData );
+
+ // Reading MAC address
+ Uxx_ReadEthernetAddress( pHwData );
+
+ // Read VCO trim for RF parameter
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08200000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &VCO_trim );
+
+ // Read Antenna On/Off of software flag
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08210000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &SoftwareSet );
+
+ // Read TXVGA
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08100000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &TxVga );
+
+ // Get Scan interval setting from EEPROM offset 0x1c
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x081d0000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &Region_ScanInterval );
+
+ // Update Ethernet address
+ memcpy( pHwData->CurrentMacAddress, pHwData->PermanentMacAddress, ETH_LENGTH_OF_ADDRESS );
+
+ // Update software variable
+ pHwData->SoftwareSet = (u16)(SoftwareSet & 0xffff);
+ TxVga &= 0x000000ff;
+ pHwData->PowerIndexFromEEPROM = (u8)TxVga;
+ pHwData->VCO_trim = (u8)VCO_trim & 0xff;
+ if (pHwData->VCO_trim == 0xff)
+ pHwData->VCO_trim = 0x28;
+
+ pWb35Reg->EEPROMRegion = (u8)(Region_ScanInterval>>8); // 20060720
+ if( pWb35Reg->EEPROMRegion<1 || pWb35Reg->EEPROMRegion>6 )
+ pWb35Reg->EEPROMRegion = REGION_AUTO;
+
+ //For Get Tx VGA from EEPROM 20060315.5 move here
+ GetTxVgaFromEEPROM( pHwData );
+
+ // Set Scan Interval
+ pHwData->Scan_Interval = (u8)(Region_ScanInterval & 0xff) * 10;
+ if ((pHwData->Scan_Interval == 2550) || (pHwData->Scan_Interval < 10)) // Is default setting 0xff * 10
+ pHwData->Scan_Interval = SCAN_MAX_CHNL_TIME;
+
+ // Initial register
+ RFSynthesizer_initial(pHwData);
+
+ BBProcessor_initial(pHwData); // Async write, must wait until complete
+
+ Wb35Reg_phy_calibration(pHwData);
+
+ Mxx_initial(pHwData);
+ Dxx_initial(pHwData);
+
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+ else
+ return TRUE; // Initial fail
+}
+
+//===================================================================================
+// CardComputeCrc --
+//
+// Description:
+// Runs the AUTODIN II CRC algorithm on buffer Buffer of length, Length.
+//
+// Arguments:
+// Buffer - the input buffer
+// Length - the length of Buffer
+//
+// Return Value:
+// The 32-bit CRC value.
+//
+// Note:
+// This is adapted from the comments in the assembly language
+// version in _GENREQ.ASM of the DWB NE1000/2000 driver.
+//==================================================================================
+u32
+CardComputeCrc(PUCHAR Buffer, u32 Length)
+{
+ u32 Crc, Carry;
+ u32 i, j;
+ u8 CurByte;
+
+ Crc = 0xffffffff;
+
+ for (i = 0; i < Length; i++) {
+
+ CurByte = Buffer[i];
+
+ for (j = 0; j < 8; j++) {
+
+ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
+ Crc <<= 1;
+ CurByte >>= 1;
+
+ if (Carry) {
+ Crc =(Crc ^ 0x04c11db6) | Carry;
+ }
+ }
+ }
+
+ return Crc;
+}
+
+
+//==================================================================
+// BitReverse --
+// Reverse the bits in the input argument, dwData, which is
+// regarded as a string of bits with the length, DataLength.
+//
+// Arguments:
+// dwData :
+// DataLength :
+//
+// Return:
+// The converted value.
+//==================================================================
+u32 BitReverse( u32 dwData, u32 DataLength)
+{
+ u32 HalfLength, i, j;
+ u32 BitA, BitB;
+
+ if ( DataLength <= 0) return 0; // No conversion is done.
+ dwData = dwData & (0xffffffff >> (32 - DataLength));
+
+ HalfLength = DataLength / 2;
+ for ( i = 0, j = DataLength-1 ; i < HalfLength; i++, j--)
+ {
+ BitA = GetBit( dwData, i);
+ BitB = GetBit( dwData, j);
+ if (BitA && !BitB) {
+ dwData = ClearBit( dwData, i);
+ dwData = SetBit( dwData, j);
+ } else if (!BitA && BitB) {
+ dwData = SetBit( dwData, i);
+ dwData = ClearBit( dwData, j);
+ } else
+ {
+ // Do nothing since these two bits are of the save values.
+ }
+ }
+
+ return dwData;
+}
+
+void Wb35Reg_phy_calibration( phw_data_t pHwData )
+{
+ u32 BB3c, BB54;
+
+ if ((pHwData->phy_type == RF_WB_242) ||
+ (pHwData->phy_type == RF_WB_242_1)) {
+ phy_calibration_winbond ( pHwData, 2412 ); // Sync operation
+ Wb35Reg_ReadSync( pHwData, 0x103c, &BB3c );
+ Wb35Reg_ReadSync( pHwData, 0x1054, &BB54 );
+
+ pHwData->BB3c_cal = BB3c;
+ pHwData->BB54_cal = BB54;
+
+ RFSynthesizer_initial(pHwData);
+ BBProcessor_initial(pHwData); // Async operation
+
+ Wb35Reg_WriteSync( pHwData, 0x103c, BB3c );
+ Wb35Reg_WriteSync( pHwData, 0x1054, BB54 );
+ }
+}
+
+
diff --git a/drivers/staging/winbond/linux/wb35reg_f.h b/drivers/staging/winbond/linux/wb35reg_f.h
new file mode 100644
index 0000000..38e2906
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35reg_f.h
@@ -0,0 +1,56 @@
+//====================================
+// Interface function declare
+//====================================
+unsigned char Wb35Reg_initial( phw_data_t pHwData );
+void Uxx_power_on_procedure( phw_data_t pHwData );
+void Uxx_power_off_procedure( phw_data_t pHwData );
+void Uxx_ReadEthernetAddress( phw_data_t pHwData );
+void Dxx_initial( phw_data_t pHwData );
+void Mxx_initial( phw_data_t pHwData );
+void RFSynthesizer_initial( phw_data_t pHwData );
+//void RFSynthesizer_SwitchingChannel( phw_data_t pHwData, s8 Channel );
+void RFSynthesizer_SwitchingChannel( phw_data_t pHwData, ChanInfo Channel );
+void BBProcessor_initial( phw_data_t pHwData );
+void BBProcessor_RateChanging( phw_data_t pHwData, u8 rate ); // 20060613.1
+//void RF_RateChanging( phw_data_t pHwData, u8 rate ); // 20060626.5.c Add
+u8 RFSynthesizer_SetPowerIndex( phw_data_t pHwData, u8 PowerIndex );
+u8 RFSynthesizer_SetMaxim2828_24Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2828_50Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2827_24Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2827_50Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2825Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetAiroha2230Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetAiroha7230Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetWinbond242Power( phw_data_t, u8 index );
+void GetTxVgaFromEEPROM( phw_data_t pHwData );
+void EEPROMTxVgaAdjust( phw_data_t pHwData ); // 20060619.5 Add
+
+#define RFWriteControlData( _A, _V ) Wb35Reg_Write( _A, 0x0864, _V )
+
+void Wb35Reg_destroy( phw_data_t pHwData );
+
+unsigned char Wb35Reg_Read( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue );
+unsigned char Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue );
+unsigned char Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
+unsigned char Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
+unsigned char Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData,
+ u16 RegisterNo,
+ u32 RegisterValue,
+ PCHAR pValue,
+ s8 Len);
+unsigned char Wb35Reg_BurstWrite( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag );
+
+void Wb35Reg_EP0VM( phw_data_t pHwData );
+void Wb35Reg_EP0VM_start( phw_data_t pHwData );
+void Wb35Reg_EP0VM_complete( PURB pUrb );
+
+u32 BitReverse( u32 dwData, u32 DataLength);
+
+void CardGetMulticastBit( u8 Address[MAC_ADDR_LENGTH], u8 *Byte, u8 *Value );
+u32 CardComputeCrc( PUCHAR Buffer, u32 Length );
+
+void Wb35Reg_phy_calibration( phw_data_t pHwData );
+void Wb35Reg_Update( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
+unsigned char adjust_TXVGA_for_iq_mag( phw_data_t pHwData );
+
+
diff --git a/drivers/staging/winbond/linux/wb35reg_s.h b/drivers/staging/winbond/linux/wb35reg_s.h
new file mode 100644
index 0000000..a7595b1
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35reg_s.h
@@ -0,0 +1,170 @@
+//=======================================================================================
+/*
+ HAL setting function
+
+ ========================================
+ |Uxx| |Dxx| |Mxx| |BB| |RF|
+ ========================================
+ | |
+ Wb35Reg_Read Wb35Reg_Write
+
+ ----------------------------------------
+ WbUsb_CallUSBDASync supplied By WbUsb module
+*/
+//=======================================================================================
+
+#define GetBit( dwData, i) ( dwData & (0x00000001 << i))
+#define SetBit( dwData, i) ( dwData | (0x00000001 << i))
+#define ClearBit( dwData, i) ( dwData & ~(0x00000001 << i))
+
+#define IGNORE_INCREMENT 0
+#define AUTO_INCREMENT 0
+#define NO_INCREMENT 1
+#define REG_DIRECTION(_x,_y) ((_y)->DIRECT ==0 ? usb_rcvctrlpipe(_x,0) : usb_sndctrlpipe(_x,0))
+#define REG_BUF_SIZE(_x) ((_x)->bRequest== 0x04 ? cpu_to_le16((_x)->wLength) : 4)
+
+// 20060613.2 Add the follow definition
+#define BB48_DEFAULT_AL2230_11B 0x0033447c
+#define BB4C_DEFAULT_AL2230_11B 0x0A00FEFF
+#define BB48_DEFAULT_AL2230_11G 0x00332C1B
+#define BB4C_DEFAULT_AL2230_11G 0x0A00FEFF
+
+
+#define BB48_DEFAULT_WB242_11B 0x00292315 //backoff 2dB
+#define BB4C_DEFAULT_WB242_11B 0x0800FEFF //backoff 2dB
+//#define BB48_DEFAULT_WB242_11B 0x00201B11 //backoff 4dB
+//#define BB4C_DEFAULT_WB242_11B 0x0600FF00 //backoff 4dB
+#define BB48_DEFAULT_WB242_11G 0x00453B24
+#define BB4C_DEFAULT_WB242_11G 0x0E00FEFF
+
+//====================================
+// Default setting for Mxx
+//====================================
+#define DEFAULT_CWMIN 31 //(M2C) CWmin. Its value is in the range 0-31.
+#define DEFAULT_CWMAX 1023 //(M2C) CWmax. Its value is in the range 0-1023.
+#define DEFAULT_AID 1 //(M34) AID. Its value is in the range 1-2007.
+
+#ifdef _USE_FALLBACK_RATE_
+#define DEFAULT_RATE_RETRY_LIMIT 2 //(M38) as named
+#else
+#define DEFAULT_RATE_RETRY_LIMIT 7 //(M38) as named
+#endif
+
+#define DEFAULT_LONG_RETRY_LIMIT 7 //(M38) LongRetryLimit. Its value is in the range 0-15.
+#define DEFAULT_SHORT_RETRY_LIMIT 7 //(M38) ShortRetryLimit. Its value is in the range 0-15.
+#define DEFAULT_PIFST 25 //(M3C) PIFS Time. Its value is in the range 0-65535.
+#define DEFAULT_EIFST 354 //(M3C) EIFS Time. Its value is in the range 0-1048575.
+#define DEFAULT_DIFST 45 //(M3C) DIFS Time. Its value is in the range 0-65535.
+#define DEFAULT_SIFST 5 //(M3C) SIFS Time. Its value is in the range 0-65535.
+#define DEFAULT_OSIFST 10 //(M3C) Original SIFS Time. Its value is in the range 0-15.
+#define DEFAULT_ATIMWD 0 //(M40) ATIM Window. Its value is in the range 0-65535.
+#define DEFAULT_SLOT_TIME 20 //(M40) ($) SlotTime. Its value is in the range 0-255.
+#define DEFAULT_MAX_TX_MSDU_LIFE_TIME 512 //(M44) MaxTxMSDULifeTime. Its value is in the range 0-4294967295.
+#define DEFAULT_BEACON_INTERVAL 500 //(M48) Beacon Interval. Its value is in the range 0-65535.
+#define DEFAULT_PROBE_DELAY_TIME 200 //(M48) Probe Delay Time. Its value is in the range 0-65535.
+#define DEFAULT_PROTOCOL_VERSION 0 //(M4C)
+#define DEFAULT_MAC_POWER_STATE 2 //(M4C) 2: MAC at power active
+#define DEFAULT_DTIM_ALERT_TIME 0
+
+
+typedef struct _REG_QUEUE
+{
+ struct urb *pUrb;
+ void* pUsbReq;
+ void* Next;
+ union
+ {
+ u32 VALUE;
+ PULONG pBuffer;
+ };
+ u8 RESERVED[4];// space reserved for communication
+
+ u16 INDEX; // For storing the register index
+ u8 RESERVED_VALID; //Indicate whether the RESERVED space is valid at this command.
+ u8 DIRECT; // 0:In 1:Out
+
+} REG_QUEUE, *PREG_QUEUE;
+
+//====================================
+// Internal variable for module
+//====================================
+#define MAX_SQ3_FILTER_SIZE 5
+typedef struct _WB35REG
+{
+ //============================
+ // Register Bank backup
+ //============================
+ u32 U1B0; //bit16 record the h/w radio on/off status
+ u32 U1BC_LEDConfigure;
+ u32 D00_DmaControl;
+ u32 M00_MacControl;
+ union {
+ struct {
+ u32 M04_MulticastAddress1;
+ u32 M08_MulticastAddress2;
+ };
+ u8 Multicast[8]; // contents of card multicast registers
+ };
+
+ u32 M24_MacControl;
+ u32 M28_MacControl;
+ u32 M2C_MacControl;
+ u32 M38_MacControl;
+ u32 M3C_MacControl; // 20060214 backup only
+ u32 M40_MacControl;
+ u32 M44_MacControl; // 20060214 backup only
+ u32 M48_MacControl; // 20060214 backup only
+ u32 M4C_MacStatus;
+ u32 M60_MacControl; // 20060214 backup only
+ u32 M68_MacControl; // 20060214 backup only
+ u32 M70_MacControl; // 20060214 backup only
+ u32 M74_MacControl; // 20060214 backup only
+ u32 M78_ERPInformation;//930206.2.b
+ u32 M7C_MacControl; // 20060214 backup only
+ u32 M80_MacControl; // 20060214 backup only
+ u32 M84_MacControl; // 20060214 backup only
+ u32 M88_MacControl; // 20060214 backup only
+ u32 M98_MacControl; // 20060214 backup only
+
+ //[20040722 WK]
+ //Baseband register
+ u32 BB0C; // Used for LNA calculation
+ u32 BB2C; //
+ u32 BB30; //11b acquisition control register
+ u32 BB3C;
+ u32 BB48; // 20051221.1.a 20060613.1 Fix OBW issue of 11b/11g rate
+ u32 BB4C; // 20060613.1 Fix OBW issue of 11b/11g rate
+ u32 BB50; //mode control register
+ u32 BB54;
+ u32 BB58; //IQ_ALPHA
+ u32 BB5C; // For test
+ u32 BB60; // for WTO read value
+
+ //-------------------
+ // VM
+ //-------------------
+ OS_SPIN_LOCK EP0VM_spin_lock; // 4B
+ u32 EP0VM_status;//$$
+ PREG_QUEUE pRegFirst;
+ PREG_QUEUE pRegLast;
+ OS_ATOMIC RegFireCount;
+
+ // Hardware status
+ u8 EP0vm_state;
+ u8 mac_power_save;
+ u8 EEPROMPhyType; // 0 ~ 15 for Maxim (0 Ä„V MAX2825, 1 Ä„V MAX2827, 2 Ä„V MAX2828, 3 Ä„V MAX2829),
+ // 16 ~ 31 for Airoha (16 Ä„V AL2230, 11 - AL7230)
+ // 32 ~ Reserved
+ // 33 ~ 47 For WB242 ( 33 - WB242, 34 - WB242 with new Txvga 0.5 db step)
+ // 48 ~ 255 ARE RESERVED.
+ u8 EEPROMRegion; //Region setting in EEPROM
+
+ u32 SyncIoPause; // If user use the Sync Io to access Hw, then pause the async access
+
+ u8 LNAValue[4]; //Table for speed up running
+ u32 SQ3_filter[MAX_SQ3_FILTER_SIZE];
+ u32 SQ3_index;
+
+} WB35REG, *PWB35REG;
+
+
diff --git a/drivers/staging/winbond/linux/wb35rx.c b/drivers/staging/winbond/linux/wb35rx.c
new file mode 100644
index 0000000..26157eb
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35rx.c
@@ -0,0 +1,337 @@
+//============================================================================
+// Copyright (c) 1996-2002 Winbond Electronic Corporation
+//
+// Module Name:
+// Wb35Rx.c
+//
+// Abstract:
+// Processing the Rx message from down layer
+//
+//============================================================================
+#include "sysdef.h"
+
+
+void Wb35Rx_start(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ // Allow only one thread to run into the Wb35Rx() function
+ if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Rx->RxFireCounter) == 1) {
+ pWb35Rx->EP3vm_state = VM_RUNNING;
+ Wb35Rx(pHwData);
+ } else
+ OS_ATOMIC_DEC(pHwData->Adapter, &pWb35Rx->RxFireCounter);
+}
+
+// This function cannot reentrain
+void Wb35Rx( phw_data_t pHwData )
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ PUCHAR pRxBufferAddress;
+ PURB pUrb = (PURB)pWb35Rx->RxUrb;
+ int retv;
+ u32 RxBufferId;
+
+ //
+ // Issuing URB
+ //
+ do {
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ break;
+
+ if (pWb35Rx->rx_halt)
+ break;
+
+ // Get RxBuffer's ID
+ RxBufferId = pWb35Rx->RxBufferId;
+ if (!pWb35Rx->RxOwner[RxBufferId]) {
+ // It's impossible to run here.
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Rx driver fifo unavailable\n"));
+ #endif
+ break;
+ }
+
+ // Update buffer point, then start to bulkin the data from USB
+ pWb35Rx->RxBufferId++;
+ pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER;
+
+ pWb35Rx->CurrentRxBufferId = RxBufferId;
+
+ if (1 != OS_MEMORY_ALLOC((void* *)&pWb35Rx->pDRx, MAX_USB_RX_BUFFER)) {
+ printk("w35und: Rx memory alloc failed\n");
+ break;
+ }
+ pRxBufferAddress = pWb35Rx->pDRx;
+
+ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
+ usb_rcvbulkpipe(pHwData->WbUsb.udev, 3),
+ pRxBufferAddress, MAX_USB_RX_BUFFER,
+ Wb35Rx_Complete, pHwData);
+
+ pWb35Rx->EP3vm_state = VM_RUNNING;
+
+ retv = wb_usb_submit_urb(pUrb);
+
+ if (retv != 0) {
+ printk("Rx URB sending error\n");
+ break;
+ }
+ return;
+ } while(FALSE);
+
+ // VM stop
+ pWb35Rx->EP3vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter );
+}
+
+void Wb35Rx_Complete(PURB pUrb)
+{
+ phw_data_t pHwData = pUrb->context;
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ PUCHAR pRxBufferAddress;
+ u32 SizeCheck;
+ u16 BulkLength;
+ u32 RxBufferId;
+ R00_DESCRIPTOR R00;
+
+ // Variable setting
+ pWb35Rx->EP3vm_state = VM_COMPLETED;
+ pWb35Rx->EP3VM_status = pUrb->status;//Store the last result of Irp
+
+ do {
+ RxBufferId = pWb35Rx->CurrentRxBufferId;
+
+ pRxBufferAddress = pWb35Rx->pDRx;
+ BulkLength = (u16)pUrb->actual_length;
+
+ // The IRP is completed
+ pWb35Rx->EP3vm_state = VM_COMPLETED;
+
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Must be here, or RxBufferId is invalid
+ break;
+
+ if (pWb35Rx->rx_halt)
+ break;
+
+ // Start to process the data only in successful condition
+ pWb35Rx->RxOwner[ RxBufferId ] = 0; // Set the owner to driver
+ R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress);
+
+ // The URB is completed, check the result
+ if (pWb35Rx->EP3VM_status != 0) {
+ #ifdef _PE_USB_STATE_DUMP_
+ WBDEBUG(("EP3 IoCompleteRoutine return error\n"));
+ DebugUsbdStatusInformation( pWb35Rx->EP3VM_status );
+ #endif
+ pWb35Rx->EP3vm_state = VM_STOP;
+ break;
+ }
+
+ // 20060220 For recovering. check if operating in single USB mode
+ if (!HAL_USB_MODE_BURST(pHwData)) {
+ SizeCheck = R00.R00_receive_byte_count; //20060926 anson's endian
+ if ((SizeCheck & 0x03) > 0)
+ SizeCheck -= 4;
+ SizeCheck = (SizeCheck + 3) & ~0x03;
+ SizeCheck += 12; // 8 + 4 badbeef
+ if ((BulkLength > 1600) ||
+ (SizeCheck > 1600) ||
+ (BulkLength != SizeCheck) ||
+ (BulkLength == 0)) { // Add for fail Urb
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->Ep3ErrorCount2++;
+ }
+ }
+
+ // Indicating the receiving data
+ pWb35Rx->ByteReceived += BulkLength;
+ pWb35Rx->RxBufferSize[ RxBufferId ] = BulkLength;
+
+ if (!pWb35Rx->RxOwner[ RxBufferId ])
+ Wb35Rx_indicate(pHwData);
+
+ kfree(pWb35Rx->pDRx);
+ // Do the next receive
+ Wb35Rx(pHwData);
+ return;
+
+ } while(FALSE);
+
+ pWb35Rx->RxOwner[ RxBufferId ] = 1; // Set the owner to hardware
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter );
+ pWb35Rx->EP3vm_state = VM_STOP;
+}
+
+//=====================================================================================
+unsigned char Wb35Rx_initial(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ // Initial the Buffer Queue
+ Wb35Rx_reset_descriptor( pHwData );
+
+ pWb35Rx->RxUrb = wb_usb_alloc_urb(0);
+ return (!!pWb35Rx->RxUrb);
+}
+
+void Wb35Rx_stop(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ // Canceling the Irp if already sends it out.
+ if (pWb35Rx->EP3vm_state == VM_RUNNING) {
+ usb_unlink_urb( pWb35Rx->RxUrb ); // Only use unlink, let Wb35Rx_destroy to free them
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("EP3 Rx stop\n"));
+ #endif
+ }
+}
+
+// Needs process context
+void Wb35Rx_destroy(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ do {
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
+ } while (pWb35Rx->EP3vm_state != VM_STOP);
+ OS_SLEEP(10000); // Delay for waiting function exit 940623.1.b
+
+ if (pWb35Rx->RxUrb)
+ usb_free_urb( pWb35Rx->RxUrb );
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Wb35Rx_destroy OK\n"));
+ #endif
+}
+
+void Wb35Rx_reset_descriptor( phw_data_t pHwData )
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ u32 i;
+
+ pWb35Rx->ByteReceived = 0;
+ pWb35Rx->RxProcessIndex = 0;
+ pWb35Rx->RxBufferId = 0;
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->rx_halt = 0;
+
+ // Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable.
+ for( i=0; i<MAX_USB_RX_BUFFER_NUMBER; i++ )
+ pWb35Rx->RxOwner[i] = 1;
+}
+
+void Wb35Rx_adjust(PDESCRIPTOR pRxDes)
+{
+ PULONG pRxBufferAddress;
+ u32 DecryptionMethod;
+ u32 i;
+ u16 BufferSize;
+
+ DecryptionMethod = pRxDes->R01.R01_decryption_method;
+ pRxBufferAddress = pRxDes->buffer_address[0];
+ BufferSize = pRxDes->buffer_size[0];
+
+ // Adjust the last part of data. Only data left
+ BufferSize -= 4; // For CRC-32
+ if (DecryptionMethod)
+ BufferSize -= 4;
+ if (DecryptionMethod == 3) // For CCMP
+ BufferSize -= 4;
+
+ // Adjust the IV field which after 802.11 header and ICV field.
+ if (DecryptionMethod == 1) // For WEP
+ {
+ for( i=6; i>0; i-- )
+ pRxBufferAddress[i] = pRxBufferAddress[i-1];
+ pRxDes->buffer_address[0] = pRxBufferAddress + 1;
+ BufferSize -= 4; // 4 byte for IV
+ }
+ else if( DecryptionMethod ) // For TKIP and CCMP
+ {
+ for (i=7; i>1; i--)
+ pRxBufferAddress[i] = pRxBufferAddress[i-2];
+ pRxDes->buffer_address[0] = pRxBufferAddress + 2;//Update the descriptor, shift 8 byte
+ BufferSize -= 8; // 8 byte for IV + ICV
+ }
+ pRxDes->buffer_size[0] = BufferSize;
+}
+
+extern void packet_came(char *pRxBufferAddress, int PacketSize);
+
+
+u16 Wb35Rx_indicate(phw_data_t pHwData)
+{
+ DESCRIPTOR RxDes;
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ PUCHAR pRxBufferAddress;
+ u16 PacketSize;
+ u16 stmp, BufferSize, stmp2 = 0;
+ u32 RxBufferId;
+
+ // Only one thread be allowed to run into the following
+ do {
+ RxBufferId = pWb35Rx->RxProcessIndex;
+ if (pWb35Rx->RxOwner[ RxBufferId ]) //Owner by VM
+ break;
+
+ pWb35Rx->RxProcessIndex++;
+ pWb35Rx->RxProcessIndex %= MAX_USB_RX_BUFFER_NUMBER;
+
+ pRxBufferAddress = pWb35Rx->pDRx;
+ BufferSize = pWb35Rx->RxBufferSize[ RxBufferId ];
+
+ // Parse the bulkin buffer
+ while (BufferSize >= 4) {
+ if ((cpu_to_le32(*(PULONG)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) //Is ending? 921002.9.a
+ break;
+
+ // Get the R00 R01 first
+ RxDes.R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress);
+ PacketSize = (u16)RxDes.R00.R00_receive_byte_count;
+ RxDes.R01.value = le32_to_cpu(*((PULONG)(pRxBufferAddress+4)));
+ // For new DMA 4k
+ if ((PacketSize & 0x03) > 0)
+ PacketSize -= 4;
+
+ // Basic check for Rx length. Is length valid?
+ if (PacketSize > MAX_PACKET_SIZE) {
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Serious ERROR : Rx data size too long, size =%d\n", PacketSize));
+ #endif
+
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->Ep3ErrorCount2++;
+ break;
+ }
+
+ // Start to process Rx buffer
+// RxDes.Descriptor_ID = RxBufferId; // Due to synchronous indicate, the field doesn't necessary to use.
+ BufferSize -= 8; //subtract 8 byte for 35's USB header length
+ pRxBufferAddress += 8;
+
+ RxDes.buffer_address[0] = pRxBufferAddress;
+ RxDes.buffer_size[0] = PacketSize;
+ RxDes.buffer_number = 1;
+ RxDes.buffer_start_index = 0;
+ RxDes.buffer_total_size = RxDes.buffer_size[0];
+ Wb35Rx_adjust(&RxDes);
+
+ packet_came(pRxBufferAddress, PacketSize);
+
+ // Move RxBuffer point to the next
+ stmp = PacketSize + 3;
+ stmp &= ~0x03; // 4n alignment
+ pRxBufferAddress += stmp;
+ BufferSize -= stmp;
+ stmp2 += stmp;
+ }
+
+ // Reclaim resource
+ pWb35Rx->RxOwner[ RxBufferId ] = 1;
+ } while(TRUE);
+
+ return stmp2;
+}
+
+
diff --git a/drivers/staging/winbond/linux/wb35rx_f.h b/drivers/staging/winbond/linux/wb35rx_f.h
new file mode 100644
index 0000000..daa3e73
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35rx_f.h
@@ -0,0 +1,17 @@
+//====================================
+// Interface function declare
+//====================================
+void Wb35Rx_reset_descriptor( phw_data_t pHwData );
+unsigned char Wb35Rx_initial( phw_data_t pHwData );
+void Wb35Rx_destroy( phw_data_t pHwData );
+void Wb35Rx_stop( phw_data_t pHwData );
+u16 Wb35Rx_indicate( phw_data_t pHwData );
+void Wb35Rx_adjust( PDESCRIPTOR pRxDes );
+void Wb35Rx_start( phw_data_t pHwData );
+
+void Wb35Rx( phw_data_t pHwData );
+void Wb35Rx_Complete( PURB pUrb );
+
+
+
+
diff --git a/drivers/staging/winbond/linux/wb35rx_s.h b/drivers/staging/winbond/linux/wb35rx_s.h
new file mode 100644
index 0000000..53b831f
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35rx_s.h
@@ -0,0 +1,48 @@
+//============================================================================
+// wb35rx.h --
+//============================================================================
+
+// Definition for this module used
+#define MAX_USB_RX_BUFFER 4096 // This parameter must be 4096 931130.4.f
+
+#define MAX_USB_RX_BUFFER_NUMBER ETHERNET_RX_DESCRIPTORS // Maximum 254, 255 is RESERVED ID
+#define RX_INTERFACE 0 // Interface 1
+#define RX_PIPE 2 // Pipe 3
+#define MAX_PACKET_SIZE 1600 //1568 // 8 + 1532 + 4 + 24(IV EIV MIC ICV CRC) for check DMA data 931130.4.g
+#define RX_END_TAG 0x0badbeef
+
+
+//====================================
+// Internal variable for module
+//====================================
+typedef struct _WB35RX
+{
+ u32 ByteReceived;// For calculating throughput of BulkIn
+ OS_ATOMIC RxFireCounter;// Does Wb35Rx module fire?
+
+ u8 RxBuffer[ MAX_USB_RX_BUFFER_NUMBER ][ ((MAX_USB_RX_BUFFER+3) & ~0x03 ) ];
+ u16 RxBufferSize[ ((MAX_USB_RX_BUFFER_NUMBER+1) & ~0x01) ];
+ u8 RxOwner[ ((MAX_USB_RX_BUFFER_NUMBER+3) & ~0x03 ) ];//Ownership of buffer 0: SW 1:HW
+
+ u32 RxProcessIndex;//The next index to process
+ u32 RxBufferId;
+ u32 EP3vm_state;
+
+ u32 rx_halt; // For VM stopping
+
+ u16 MoreDataSize;
+ u16 PacketSize;
+
+ u32 CurrentRxBufferId; // For complete routine usage
+ u32 Rx3UrbCancel;
+
+ u32 LastR1; // For RSSI reporting
+ struct urb * RxUrb;
+ u32 Ep3ErrorCount2; // 20060625.1 Usbd for Rx DMA error count
+
+ int EP3VM_status;
+ PUCHAR pDRx;
+
+} WB35RX, *PWB35RX;
+
+
diff --git a/drivers/staging/winbond/linux/wb35tx.c b/drivers/staging/winbond/linux/wb35tx.c
new file mode 100644
index 0000000..cf19c3b
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35tx.c
@@ -0,0 +1,313 @@
+//============================================================================
+// Copyright (c) 1996-2002 Winbond Electronic Corporation
+//
+// Module Name:
+// Wb35Tx.c
+//
+// Abstract:
+// Processing the Tx message and put into down layer
+//
+//============================================================================
+#include "sysdef.h"
+
+
+unsigned char
+Wb35Tx_get_tx_buffer(phw_data_t pHwData, PUCHAR *pBuffer )
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ *pBuffer = pWb35Tx->TxBuffer[0];
+ return TRUE;
+}
+
+void Wb35Tx_start(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Allow only one thread to run into function
+ if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Tx->TxFireCounter) == 1) {
+ pWb35Tx->EP4vm_state = VM_RUNNING;
+ Wb35Tx(pHwData);
+ } else
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
+}
+
+
+void Wb35Tx(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ PADAPTER Adapter = pHwData->Adapter;
+ PUCHAR pTxBufferAddress;
+ PMDS pMds = &Adapter->Mds;
+ struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
+ int retv;
+ u32 SendIndex;
+
+
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ goto cleanup;
+
+ if (pWb35Tx->tx_halt)
+ goto cleanup;
+
+ // Ownership checking
+ SendIndex = pWb35Tx->TxSendIndex;
+ if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
+ goto cleanup;
+
+ pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
+ //
+ // Issuing URB
+ //
+ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
+ usb_sndbulkpipe(pHwData->WbUsb.udev, 4),
+ pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
+ Wb35Tx_complete, pHwData);
+
+ pWb35Tx->EP4vm_state = VM_RUNNING;
+ retv = wb_usb_submit_urb( pUrb );
+ if (retv<0) {
+ printk("EP4 Tx Irp sending error\n");
+ goto cleanup;
+ }
+
+ // Check if driver needs issue Irp for EP2
+ pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
+ if (pWb35Tx->TxFillCount > 12)
+ Wb35Tx_EP2VM_start( pHwData );
+
+ pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
+ return;
+
+ cleanup:
+ pWb35Tx->EP4vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
+}
+
+
+void Wb35Tx_complete(struct urb * pUrb)
+{
+ phw_data_t pHwData = pUrb->context;
+ PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ PMDS pMds = &Adapter->Mds;
+
+ printk("wb35: tx complete\n");
+ // Variable setting
+ pWb35Tx->EP4vm_state = VM_COMPLETED;
+ pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp
+ pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
+ pWb35Tx->TxSendIndex++;
+ pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
+
+ do {
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+ break;
+
+ if (pWb35Tx->tx_halt)
+ break;
+
+ // The URB is completed, check the result
+ if (pWb35Tx->EP4VM_status != 0) {
+ printk("URB submission failed\n");
+ pWb35Tx->EP4vm_state = VM_STOP;
+ break; // Exit while(FALSE);
+ }
+
+ Mds_Tx(Adapter);
+ Wb35Tx(pHwData);
+ return;
+ } while(FALSE);
+
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
+ pWb35Tx->EP4vm_state = VM_STOP;
+}
+
+void Wb35Tx_reset_descriptor( phw_data_t pHwData )
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ pWb35Tx->TxSendIndex = 0;
+ pWb35Tx->tx_halt = 0;
+}
+
+unsigned char Wb35Tx_initial(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ pWb35Tx->Tx4Urb = wb_usb_alloc_urb(0);
+ if (!pWb35Tx->Tx4Urb)
+ return FALSE;
+
+ pWb35Tx->Tx2Urb = wb_usb_alloc_urb(0);
+ if (!pWb35Tx->Tx2Urb)
+ {
+ usb_free_urb( pWb35Tx->Tx4Urb );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//======================================================
+void Wb35Tx_stop(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Trying to canceling the Trp of EP2
+ if (pWb35Tx->EP2vm_state == VM_RUNNING)
+ usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP2 Tx stop\n"));
+ #endif
+
+ // Trying to canceling the Irp of EP4
+ if (pWb35Tx->EP4vm_state == VM_RUNNING)
+ usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP4 Tx stop\n"));
+ #endif
+}
+
+//======================================================
+void Wb35Tx_destroy(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Wait for VM stop
+ do {
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
+ } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
+
+ if (pWb35Tx->Tx4Urb)
+ usb_free_urb( pWb35Tx->Tx4Urb );
+
+ if (pWb35Tx->Tx2Urb)
+ usb_free_urb( pWb35Tx->Tx2Urb );
+
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("Wb35Tx_destroy OK\n"));
+ #endif
+}
+
+void Wb35Tx_CurrentTime(phw_data_t pHwData, u32 TimeCount)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ unsigned char Trigger = FALSE;
+
+ if (pWb35Tx->TxTimer > TimeCount)
+ Trigger = TRUE;
+ else if (TimeCount > (pWb35Tx->TxTimer+500))
+ Trigger = TRUE;
+
+ if (Trigger) {
+ pWb35Tx->TxTimer = TimeCount;
+ Wb35Tx_EP2VM_start( pHwData );
+ }
+}
+
+void Wb35Tx_EP2VM_start(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Allow only one thread to run into function
+ if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Tx->TxResultCount ) == 1) {
+ pWb35Tx->EP2vm_state = VM_RUNNING;
+ Wb35Tx_EP2VM( pHwData );
+ }
+ else
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
+}
+
+
+void Wb35Tx_EP2VM(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
+ PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
+ int retv;
+
+ do {
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ break;
+
+ if (pWb35Tx->tx_halt)
+ break;
+
+ //
+ // Issuing URB
+ //
+ usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
+ pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
+
+ pWb35Tx->EP2vm_state = VM_RUNNING;
+ retv = wb_usb_submit_urb( pUrb );
+
+ if(retv < 0) {
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP2 Tx Irp sending error\n"));
+ #endif
+ break;
+ }
+
+ return;
+
+ } while(FALSE);
+
+ pWb35Tx->EP2vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
+}
+
+
+void Wb35Tx_EP2VM_complete(struct urb * pUrb)
+{
+ phw_data_t pHwData = pUrb->context;
+ T02_DESCRIPTOR T02, TSTATUS;
+ PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
+ u32 i;
+ u16 InterruptInLength;
+
+
+ // Variable setting
+ pWb35Tx->EP2vm_state = VM_COMPLETED;
+ pWb35Tx->EP2VM_status = pUrb->status;
+
+ do {
+ // For Linux 2.4. Interrupt will always trigger
+ if( pHwData->SurpriseRemove || pHwData->HwStop ) // Let WbWlanHalt to handle surprise remove
+ break;
+
+ if( pWb35Tx->tx_halt )
+ break;
+
+ //The Urb is completed, check the result
+ if (pWb35Tx->EP2VM_status != 0) {
+ WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
+ pWb35Tx->EP2vm_state= VM_STOP;
+ break; // Exit while(FALSE);
+ }
+
+ // Update the Tx result
+ InterruptInLength = pUrb->actual_length;
+ // Modify for minimum memory access and DWORD alignment.
+ T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
+ InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
+ InterruptInLength >>= 2; // InterruptInLength/4
+ for (i=1; i<=InterruptInLength; i++) {
+ T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
+
+ TSTATUS.value = T02.value; //20061009 anson's endian
+ Mds_SendComplete( Adapter, &TSTATUS );
+ T02.value = cpu_to_le32(pltmp[i]) >> 8;
+ }
+
+ return;
+ } while(FALSE);
+
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
+ pWb35Tx->EP2vm_state = VM_STOP;
+}
+
diff --git a/drivers/staging/winbond/linux/wb35tx_f.h b/drivers/staging/winbond/linux/wb35tx_f.h
new file mode 100644
index 0000000..7705a84
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35tx_f.h
@@ -0,0 +1,20 @@
+//====================================
+// Interface function declare
+//====================================
+unsigned char Wb35Tx_initial( phw_data_t pHwData );
+void Wb35Tx_destroy( phw_data_t pHwData );
+unsigned char Wb35Tx_get_tx_buffer( phw_data_t pHwData, PUCHAR *pBuffer );
+
+void Wb35Tx_EP2VM( phw_data_t pHwData );
+void Wb35Tx_EP2VM_start( phw_data_t pHwData );
+void Wb35Tx_EP2VM_complete( PURB purb );
+
+void Wb35Tx_start( phw_data_t pHwData );
+void Wb35Tx_stop( phw_data_t pHwData );
+void Wb35Tx( phw_data_t pHwData );
+void Wb35Tx_complete( PURB purb );
+void Wb35Tx_reset_descriptor( phw_data_t pHwData );
+
+void Wb35Tx_CurrentTime( phw_data_t pHwData, u32 TimeCount );
+
+
diff --git a/drivers/staging/winbond/linux/wb35tx_s.h b/drivers/staging/winbond/linux/wb35tx_s.h
new file mode 100644
index 0000000..ac43257
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35tx_s.h
@@ -0,0 +1,47 @@
+//====================================
+// IS89C35 Tx related definition
+//====================================
+#define TX_INTERFACE 0 // Interface 1
+#define TX_PIPE 3 // endpoint 4
+#define TX_INTERRUPT 1 // endpoint 2
+#define MAX_INTERRUPT_LENGTH 64 // It must be 64 for EP2 hardware
+
+
+
+//====================================
+// Internal variable for module
+//====================================
+
+
+typedef struct _WB35TX
+{
+ // For Tx buffer
+ u8 TxBuffer[ MAX_USB_TX_BUFFER_NUMBER ][ MAX_USB_TX_BUFFER ];
+
+ // For Interrupt pipe
+ u8 EP2_buf[MAX_INTERRUPT_LENGTH];
+
+ OS_ATOMIC TxResultCount;// For thread control of EP2 931130.4.m
+ OS_ATOMIC TxFireCounter;// For thread control of EP4 931130.4.n
+ u32 ByteTransfer;
+
+ u32 TxSendIndex;// The next index of Mds array to be sent
+ u32 EP2vm_state; // for EP2vm state
+ u32 EP4vm_state; // for EP4vm state
+ u32 tx_halt; // Stopping VM
+
+ struct urb * Tx4Urb;
+ struct urb * Tx2Urb;
+
+ int EP2VM_status;
+ int EP4VM_status;
+
+ u32 TxFillCount; // 20060928
+ u32 TxTimer; // 20060928 Add if sending packet not great than 13
+
+} WB35TX, *PWB35TX;
+
+
+
+
+
diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c
new file mode 100644
index 0000000..cbad5fb
--- /dev/null
+++ b/drivers/staging/winbond/linux/wbusb.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2008 Pavel Machek <pavel@suse.cz>
+ *
+ * Distribute under GPLv2.
+ */
+#include "sysdef.h"
+#include <net/mac80211.h>
+
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+
+//============================================================
+// vendor ID and product ID can into here for others
+//============================================================
+static struct usb_device_id Id_Table[] =
+{
+ {USB_DEVICE( 0x0416, 0x0035 )},
+ {USB_DEVICE( 0x18E8, 0x6201 )},
+ {USB_DEVICE( 0x18E8, 0x6206 )},
+ {USB_DEVICE( 0x18E8, 0x6217 )},
+ {USB_DEVICE( 0x18E8, 0x6230 )},
+ {USB_DEVICE( 0x18E8, 0x6233 )},
+ {USB_DEVICE( 0x1131, 0x2035 )},
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, Id_Table);
+
+static struct usb_driver wb35_driver = {
+ .name = "w35und",
+ .probe = wb35_probe,
+ .disconnect = wb35_disconnect,
+ .id_table = Id_Table,
+};
+
+static const struct ieee80211_rate wbsoft_rates[] = {
+ { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+};
+
+static const struct ieee80211_channel wbsoft_channels[] = {
+ { .center_freq = 2412},
+};
+
+int wbsoft_enabled;
+struct ieee80211_hw *my_dev;
+PADAPTER my_adapter;
+
+static int wbsoft_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ printk("wbsoft_add interface called\n");
+ return 0;
+}
+
+static void wbsoft_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ printk("wbsoft_remove interface called\n");
+}
+
+static int wbsoft_nop(void)
+{
+ printk("wbsoft_nop called\n");
+ return 0;
+}
+
+static void wbsoft_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ unsigned int bit_nr, new_flags;
+ u32 mc_filter[2];
+ int i;
+
+ new_flags = 0;
+
+ if (*total_flags & FIF_PROMISC_IN_BSS) {
+ new_flags |= FIF_PROMISC_IN_BSS;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ new_flags |= FIF_ALLMULTI;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else {
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ printk("Should call ether_crc here\n");
+ //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+ bit_nr = 0;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+ }
+
+ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+ *total_flags = new_flags;
+}
+
+static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ char *buffer = kmalloc(skb->len, GFP_ATOMIC);
+ printk("Sending frame %d bytes\n", skb->len);
+ memcpy(buffer, skb->data, skb->len);
+ if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT))
+ printk("frame sent ok (%d bytes)?\n", skb->len);
+ return NETDEV_TX_OK;
+}
+
+
+static int wbsoft_start(struct ieee80211_hw *dev)
+{
+ wbsoft_enabled = 1;
+ printk("wbsoft_start called\n");
+ return 0;
+}
+
+static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ ChanInfo ch;
+ printk("wbsoft_config called\n");
+
+ ch.band = 1;
+ ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */
+
+
+ hal_set_current_channel(&my_adapter->sHwData, ch);
+ hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int);
+// hal_set_cap_info(&my_adapter->sHwData, ?? );
+// hal_set_ssid(phw_data_t pHwData, PUCHAR pssid, u8 ssid_len); ??
+ hal_set_accept_broadcast(&my_adapter->sHwData, 1);
+ hal_set_accept_promiscuous(&my_adapter->sHwData, 1);
+ hal_set_accept_multicast(&my_adapter->sHwData, 1);
+ hal_set_accept_beacon(&my_adapter->sHwData, 1);
+ hal_set_radio_mode(&my_adapter->sHwData, 0);
+ //hal_set_antenna_number( phw_data_t pHwData, u8 number )
+ //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex)
+
+
+// hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ??
+
+//void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates,
+// u8 length, unsigned char basic_rate_set)
+
+ return 0;
+}
+
+static int wbsoft_config_interface(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ printk("wbsoft_config_interface called\n");
+ return 0;
+}
+
+static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
+{
+ printk("wbsoft_get_tsf called\n");
+ return 0;
+}
+
+static const struct ieee80211_ops wbsoft_ops = {
+ .tx = wbsoft_tx,
+ .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */
+ .stop = wbsoft_nop,
+ .add_interface = wbsoft_add_interface,
+ .remove_interface = wbsoft_remove_interface,
+ .config = wbsoft_config,
+ .config_interface = wbsoft_config_interface,
+ .configure_filter = wbsoft_configure_filter,
+ .get_stats = wbsoft_nop,
+ .get_tx_stats = wbsoft_nop,
+ .get_tsf = wbsoft_get_tsf,
+// conf_tx: hal_set_cwmin()/hal_set_cwmax;
+};
+
+struct wbsoft_priv {
+};
+
+
+int __init wb35_init(void)
+{
+ printk("[w35und]driver init\n");
+ return usb_register(&wb35_driver);
+}
+
+void __exit wb35_exit(void)
+{
+ printk("[w35und]driver exit\n");
+ usb_deregister( &wb35_driver );
+}
+
+module_init(wb35_init);
+module_exit(wb35_exit);
+
+// Usb kernel subsystem will call this function when a new device is plugged into.
+int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table)
+{
+ PADAPTER Adapter;
+ PWBLINUX pWbLinux;
+ PWBUSB pWbUsb;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ int i, ret = -1;
+ u32 ltmp;
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_get_dev(udev);
+
+ printk("[w35und]wb35_probe ->\n");
+
+ do {
+ for (i=0; i<(sizeof(Id_Table)/sizeof(struct usb_device_id)); i++ ) {
+ if ((udev->descriptor.idVendor == Id_Table[i].idVendor) &&
+ (udev->descriptor.idProduct == Id_Table[i].idProduct)) {
+ printk("[w35und]Found supported hardware\n");
+ break;
+ }
+ }
+ if ((i == (sizeof(Id_Table)/sizeof(struct usb_device_id)))) {
+ #ifdef _PE_USB_INI_DUMP_
+ WBDEBUG(("[w35und] This is not the one we are interested about\n"));
+ #endif
+ return -ENODEV;
+ }
+
+ // 20060630.2 Check the device if it already be opened
+ ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
+ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
+ 0x0, 0x400, <mp, 4, HZ*100 );
+ if( ret < 0 )
+ break;
+
+ ltmp = cpu_to_le32(ltmp);
+ if (ltmp) // Is already initialized?
+ break;
+
+
+ Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL);
+
+ my_adapter = Adapter;
+ pWbLinux = &Adapter->WbLinux;
+ pWbUsb = &Adapter->sHwData.WbUsb;
+ pWbUsb->udev = udev;
+
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+
+ if (endpoint[2].wMaxPacketSize == 512) {
+ printk("[w35und] Working on USB 2.0\n");
+ pWbUsb->IsUsb20 = 1;
+ }
+
+ if (!WbWLanInitialize(Adapter)) {
+ printk("[w35und]WbWLanInitialize fail\n");
+ break;
+ }
+
+ {
+ struct wbsoft_priv *priv;
+ struct ieee80211_hw *dev;
+ int res;
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
+
+ if (!dev) {
+ printk("w35und: ieee80211 alloc failed\n" );
+ BUG();
+ }
+
+ my_dev = dev;
+
+ SET_IEEE80211_DEV(dev, &udev->dev);
+ {
+ phw_data_t pHwData = &Adapter->sHwData;
+ unsigned char dev_addr[MAX_ADDR_LEN];
+ hal_get_permanent_address(pHwData, dev_addr);
+ SET_IEEE80211_PERM_ADDR(dev, dev_addr);
+ }
+
+
+ dev->extra_tx_headroom = 12; /* FIXME */
+ dev->flags = 0;
+
+ dev->channel_change_time = 1000;
+// dev->max_rssi = 100;
+
+ dev->queues = 1;
+
+ static struct ieee80211_supported_band band;
+
+ band.channels = wbsoft_channels;
+ band.n_channels = ARRAY_SIZE(wbsoft_channels);
+ band.bitrates = wbsoft_rates;
+ band.n_bitrates = ARRAY_SIZE(wbsoft_rates);
+
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band;
+#if 0
+ wbsoft_modes[0].num_channels = 1;
+ wbsoft_modes[0].channels = wbsoft_channels;
+ wbsoft_modes[0].mode = MODE_IEEE80211B;
+ wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates);
+ wbsoft_modes[0].rates = wbsoft_rates;
+
+ res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]);
+ BUG_ON(res);
+#endif
+
+ res = ieee80211_register_hw(dev);
+ BUG_ON(res);
+ }
+
+ usb_set_intfdata( intf, Adapter );
+
+ printk("[w35und] _probe OK\n");
+ return 0;
+
+ } while(FALSE);
+
+ return -ENOMEM;
+}
+
+void packet_came(char *pRxBufferAddress, int PacketSize)
+{
+ struct sk_buff *skb;
+ struct ieee80211_rx_status rx_status = {0};
+
+ if (!wbsoft_enabled)
+ return;
+
+ skb = dev_alloc_skb(PacketSize);
+ if (!skb) {
+ printk("Not enough memory for packet, FIXME\n");
+ return;
+ }
+
+ memcpy(skb_put(skb, PacketSize),
+ pRxBufferAddress,
+ PacketSize);
+
+/*
+ rx_status.rate = 10;
+ rx_status.channel = 1;
+ rx_status.freq = 12345;
+ rx_status.phymode = MODE_IEEE80211B;
+*/
+
+ ieee80211_rx_irqsafe(my_dev, skb, &rx_status);
+}
+
+unsigned char
+WbUsb_initial(phw_data_t pHwData)
+{
+ return 1;
+}
+
+
+void
+WbUsb_destroy(phw_data_t pHwData)
+{
+}
+
+int wb35_open(struct net_device *netdev)
+{
+ PADAPTER Adapter = (PADAPTER)netdev->priv;
+ phw_data_t pHwData = &Adapter->sHwData;
+
+ netif_start_queue(netdev);
+
+ //TODO : put here temporarily
+ hal_set_accept_broadcast(pHwData, 1); // open accept broadcast
+
+ return 0;
+}
+
+int wb35_close(struct net_device *netdev)
+{
+ netif_stop_queue(netdev);
+ return 0;
+}
+
+void wb35_disconnect(struct usb_interface *intf)
+{
+ PWBLINUX pWbLinux;
+ PADAPTER Adapter = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ pWbLinux = &Adapter->WbLinux;
+
+ // Card remove
+ WbWlanHalt(Adapter);
+
+}
+
+
diff --git a/drivers/staging/winbond/linux/wbusb_f.h b/drivers/staging/winbond/linux/wbusb_f.h
new file mode 100644
index 0000000..cae29e1
--- /dev/null
+++ b/drivers/staging/winbond/linux/wbusb_f.h
@@ -0,0 +1,34 @@
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// Copyright (c) 1996-2004 Winbond Electronic Corporation
+//
+// Module Name:
+// wbusb_f.h
+//
+// Abstract:
+// Linux driver.
+//
+// Author:
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+int wb35_open(struct net_device *netdev);
+int wb35_close(struct net_device *netdev);
+unsigned char WbUsb_initial(phw_data_t pHwData);
+void WbUsb_destroy(phw_data_t pHwData);
+unsigned char WbWLanInitialize(PADAPTER Adapter);
+#define WbUsb_Stop( _A )
+
+int wb35_probe(struct usb_interface *intf,const struct usb_device_id *id_table);
+void wb35_disconnect(struct usb_interface *intf);
+
+
+#define wb_usb_submit_urb(_A) usb_submit_urb(_A, GFP_ATOMIC)
+#define wb_usb_alloc_urb(_A) usb_alloc_urb(_A, GFP_ATOMIC)
+
+#define WbUsb_CheckForHang( _P )
+#define WbUsb_DetectStart( _P, _I )
+
+
+
+
+
diff --git a/drivers/staging/winbond/linux/wbusb_s.h b/drivers/staging/winbond/linux/wbusb_s.h
new file mode 100644
index 0000000..d5c1d53
--- /dev/null
+++ b/drivers/staging/winbond/linux/wbusb_s.h
@@ -0,0 +1,42 @@
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// Copyright (c) 1996-2004 Winbond Electronic Corporation
+//
+// Module Name:
+// wbusb_s.h
+//
+// Abstract:
+// Linux driver.
+//
+// Author:
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+#define OS_SLEEP( _MT ) { set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout( _MT*HZ/1000000 ); }
+
+
+//---------------------------------------------------------------------------
+// RW_CONTEXT --
+//
+// Used to track driver-generated io irps
+//---------------------------------------------------------------------------
+typedef struct _RW_CONTEXT
+{
+ void* pHwData;
+ PURB pUrb;
+ void* pCallBackFunctionParameter;
+} RW_CONTEXT, *PRW_CONTEXT;
+
+
+
+
+#define DRIVER_AUTHOR "Original by: Jeff Lee<YY_Lee@issc.com.tw> Adapted to 2.6.x by Costantino Leandro (Rxart Desktop) <le_costantino@pixartargentina.com.ar>"
+#define DRIVER_DESC "IS89C35 802.11bg WLAN USB Driver"
+
+
+
+typedef struct _WBUSB {
+ u32 IsUsb20;
+ struct usb_device *udev;
+ u32 DetectCount;
+} WBUSB, *PWBUSB;