diff options
author | Pekka Enberg <penberg@cs.helsinki.fi> | 2008-10-30 13:05:42 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 13:51:47 -0800 |
commit | 9ce922fde7fb44a8690aa37d3c7f4f0cf5d921ca (patch) | |
tree | 7b03091ffe4ed1732f982dc44a875e2c5349c6e1 /drivers/staging/winbond/wb35tx.c | |
parent | 8421513d9ab4e510136d0b3042bd838d08129012 (diff) |
Staging: w35und: move source files to one directory
As we're trying to get rid of the "compatability layer" in the driver, move
everything under one directory. Keeping some of the files under
drivers/staging/winbond/linux is a major pain in the ass whenever you're
cleaning up the driver.
Acked-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/winbond/wb35tx.c')
-rw-r--r-- | drivers/staging/winbond/wb35tx.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c new file mode 100644 index 000000000000..af4a61fdc072 --- /dev/null +++ b/drivers/staging/winbond/wb35tx.c @@ -0,0 +1,310 @@ +//============================================================================ +// Copyright (c) 1996-2002 Winbond Electronic Corporation +// +// Module Name: +// Wb35Tx.c +// +// Abstract: +// Processing the Tx message and put into down layer +// +//============================================================================ +#include <linux/usb.h> + +#include "wb35tx_f.h" +#include "mds_f.h" +#include "sysdef.h" + +unsigned char +Wb35Tx_get_tx_buffer(phw_data_t pHwData, u8 **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 (atomic_inc_return(&pWb35Tx->TxFireCounter) == 1) { + pWb35Tx->EP4vm_state = VM_RUNNING; + Wb35Tx(pHwData); + } else + atomic_dec(&pWb35Tx->TxFireCounter); +} + + +void Wb35Tx(phw_data_t pHwData) +{ + PWB35TX pWb35Tx = &pHwData->Wb35Tx; + struct wb35_adapter *adapter = pHwData->adapter; + u8 *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 = usb_submit_urb(pUrb, GFP_ATOMIC); + 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; + atomic_dec(&pWb35Tx->TxFireCounter); +} + + +void Wb35Tx_complete(struct urb * pUrb) +{ + phw_data_t pHwData = pUrb->context; + struct wb35_adapter *adapter = 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; + + if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove + goto error; + + if (pWb35Tx->tx_halt) + goto error; + + // The URB is completed, check the result + if (pWb35Tx->EP4VM_status != 0) { + printk("URB submission failed\n"); + pWb35Tx->EP4vm_state = VM_STOP; + goto error; + } + + Mds_Tx(adapter); + Wb35Tx(pHwData); + return; + +error: + atomic_dec(&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 = usb_alloc_urb(0, GFP_ATOMIC); + if (!pWb35Tx->Tx4Urb) + return false; + + pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC); + 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 { + msleep(10); // Delay for waiting function enter 940623.1.a + } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) ); + msleep(10); // 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 (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) { + pWb35Tx->EP2vm_state = VM_RUNNING; + Wb35Tx_EP2VM( pHwData ); + } + else + atomic_dec(&pWb35Tx->TxResultCount); +} + + +void Wb35Tx_EP2VM(phw_data_t pHwData) +{ + PWB35TX pWb35Tx = &pHwData->Wb35Tx; + struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb; + u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; + int retv; + + if (pHwData->SurpriseRemove || pHwData->HwStop) + goto error; + + if (pWb35Tx->tx_halt) + goto error; + + // + // 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 = usb_submit_urb(pUrb, GFP_ATOMIC); + + if (retv < 0) { + #ifdef _PE_TX_DUMP_ + WBDEBUG(("EP2 Tx Irp sending error\n")); + #endif + goto error; + } + + return; +error: + pWb35Tx->EP2vm_state = VM_STOP; + atomic_dec(&pWb35Tx->TxResultCount); +} + + +void Wb35Tx_EP2VM_complete(struct urb * pUrb) +{ + phw_data_t pHwData = pUrb->context; + T02_DESCRIPTOR T02, TSTATUS; + struct wb35_adapter *adapter = pHwData->adapter; + PWB35TX pWb35Tx = &pHwData->Wb35Tx; + u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; + u32 i; + u16 InterruptInLength; + + + // Variable setting + pWb35Tx->EP2vm_state = VM_COMPLETED; + pWb35Tx->EP2VM_status = pUrb->status; + + // For Linux 2.4. Interrupt will always trigger + if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove + goto error; + + if (pWb35Tx->tx_halt) + goto error; + + //The Urb is completed, check the result + if (pWb35Tx->EP2VM_status != 0) { + WBDEBUG(("EP2 IoCompleteRoutine return error\n")); + pWb35Tx->EP2vm_state= VM_STOP; + goto error; + } + + // 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; +error: + atomic_dec(&pWb35Tx->TxResultCount); + pWb35Tx->EP2vm_state = VM_STOP; +} + |