diff options
author | Pavel Machek <pavel@suse.cz> | 2008-10-01 14:36:56 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-10-10 15:31:09 -0700 |
commit | 66101de10957e07a6fd0365d5af9adf650246d14 (patch) | |
tree | 3a13f4d2ca1d5075523a7c82f8b53b0fc5d1b971 /drivers/staging/winbond/linux/wb35tx.c | |
parent | 4d7b5c7f8ad49b7f01fb8aed83c560ac43cfbda8 (diff) |
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>
Diffstat (limited to 'drivers/staging/winbond/linux/wb35tx.c')
-rw-r--r-- | drivers/staging/winbond/linux/wb35tx.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/drivers/staging/winbond/linux/wb35tx.c b/drivers/staging/winbond/linux/wb35tx.c new file mode 100644 index 00000000000..cf19c3bc524 --- /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; +} + |