Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 1 | //============================================================================ |
| 2 | // Copyright (c) 1996-2002 Winbond Electronic Corporation |
| 3 | // |
| 4 | // Module Name: |
| 5 | // Wb35Tx.c |
| 6 | // |
| 7 | // Abstract: |
| 8 | // Processing the Tx message and put into down layer |
| 9 | // |
| 10 | //============================================================================ |
Pekka Enberg | 80aba53 | 2008-10-30 13:04:29 +0200 | [diff] [blame] | 11 | #include <linux/usb.h> |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 12 | |
Pekka Enberg | 80aba53 | 2008-10-30 13:04:29 +0200 | [diff] [blame] | 13 | #include "wb35tx_f.h" |
Pekka Enberg | 9ce922f | 2008-10-30 13:05:42 +0200 | [diff] [blame] | 14 | #include "mds_f.h" |
Pekka Enberg | 80aba53 | 2008-10-30 13:04:29 +0200 | [diff] [blame] | 15 | #include "sysdef.h" |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 16 | |
| 17 | unsigned char |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 18 | Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 19 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 20 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 21 | |
| 22 | *pBuffer = pWb35Tx->TxBuffer[0]; |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 23 | return true; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 24 | } |
| 25 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 26 | static void Wb35Tx(struct wbsoft_priv *adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 27 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 28 | static void Wb35Tx_complete(struct urb * pUrb) |
| 29 | { |
| 30 | struct wbsoft_priv *adapter = pUrb->context; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 31 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 32 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 33 | PMDS pMds = &adapter->Mds; |
| 34 | |
| 35 | printk("wb35: tx complete\n"); |
| 36 | // Variable setting |
| 37 | pWb35Tx->EP4vm_state = VM_COMPLETED; |
| 38 | pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp |
| 39 | pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always. |
| 40 | pWb35Tx->TxSendIndex++; |
| 41 | pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER; |
| 42 | |
| 43 | if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove |
| 44 | goto error; |
| 45 | |
| 46 | if (pWb35Tx->tx_halt) |
| 47 | goto error; |
| 48 | |
| 49 | // The URB is completed, check the result |
| 50 | if (pWb35Tx->EP4VM_status != 0) { |
| 51 | printk("URB submission failed\n"); |
| 52 | pWb35Tx->EP4vm_state = VM_STOP; |
| 53 | goto error; |
| 54 | } |
| 55 | |
| 56 | Mds_Tx(adapter); |
| 57 | Wb35Tx(adapter); |
| 58 | return; |
| 59 | |
| 60 | error: |
| 61 | atomic_dec(&pWb35Tx->TxFireCounter); |
| 62 | pWb35Tx->EP4vm_state = VM_STOP; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 63 | } |
| 64 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 65 | static void Wb35Tx(struct wbsoft_priv *adapter) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 66 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 67 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 68 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 8b384e0 | 2008-10-21 00:03:41 +0300 | [diff] [blame] | 69 | u8 *pTxBufferAddress; |
Pekka Enberg | 88ebc4b | 2008-10-22 11:03:19 +0300 | [diff] [blame] | 70 | PMDS pMds = &adapter->Mds; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 71 | struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb; |
| 72 | int retv; |
| 73 | u32 SendIndex; |
| 74 | |
| 75 | |
| 76 | if (pHwData->SurpriseRemove || pHwData->HwStop) |
| 77 | goto cleanup; |
| 78 | |
| 79 | if (pWb35Tx->tx_halt) |
| 80 | goto cleanup; |
| 81 | |
| 82 | // Ownership checking |
| 83 | SendIndex = pWb35Tx->TxSendIndex; |
| 84 | if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately |
| 85 | goto cleanup; |
| 86 | |
| 87 | pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex]; |
| 88 | // |
| 89 | // Issuing URB |
| 90 | // |
| 91 | usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev, |
| 92 | usb_sndbulkpipe(pHwData->WbUsb.udev, 4), |
| 93 | pTxBufferAddress, pMds->TxBufferSize[ SendIndex ], |
Pekka Enberg | 42c84bb | 2008-10-30 16:14:36 +0200 | [diff] [blame] | 94 | Wb35Tx_complete, adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 95 | |
| 96 | pWb35Tx->EP4vm_state = VM_RUNNING; |
Greg Kroah-Hartman | 7c12604 | 2008-10-27 14:21:24 -0700 | [diff] [blame] | 97 | retv = usb_submit_urb(pUrb, GFP_ATOMIC); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 98 | if (retv<0) { |
| 99 | printk("EP4 Tx Irp sending error\n"); |
| 100 | goto cleanup; |
| 101 | } |
| 102 | |
| 103 | // Check if driver needs issue Irp for EP2 |
| 104 | pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex]; |
| 105 | if (pWb35Tx->TxFillCount > 12) |
Pekka Enberg | 42c84bb | 2008-10-30 16:14:36 +0200 | [diff] [blame] | 106 | Wb35Tx_EP2VM_start(adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 107 | |
| 108 | pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex]; |
| 109 | return; |
| 110 | |
| 111 | cleanup: |
| 112 | pWb35Tx->EP4vm_state = VM_STOP; |
Pekka Enberg | 44e8541 | 2008-10-29 20:10:32 +0200 | [diff] [blame] | 113 | atomic_dec(&pWb35Tx->TxFireCounter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 114 | } |
| 115 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 116 | void Wb35Tx_start(struct wbsoft_priv *adapter) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 117 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 118 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 119 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 120 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 121 | // Allow only one thread to run into function |
| 122 | if (atomic_inc_return(&pWb35Tx->TxFireCounter) == 1) { |
| 123 | pWb35Tx->EP4vm_state = VM_RUNNING; |
| 124 | Wb35Tx(adapter); |
| 125 | } else |
| 126 | atomic_dec(&pWb35Tx->TxFireCounter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 127 | } |
| 128 | |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 129 | unsigned char Wb35Tx_initial(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 130 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 131 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 132 | |
Greg Kroah-Hartman | f3d2018 | 2008-10-27 14:21:24 -0700 | [diff] [blame] | 133 | pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 134 | if (!pWb35Tx->Tx4Urb) |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 135 | return false; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 136 | |
Greg Kroah-Hartman | f3d2018 | 2008-10-27 14:21:24 -0700 | [diff] [blame] | 137 | pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 138 | if (!pWb35Tx->Tx2Urb) |
| 139 | { |
| 140 | usb_free_urb( pWb35Tx->Tx4Urb ); |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 141 | return false; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 142 | } |
| 143 | |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 144 | return true; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | //====================================================== |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 148 | void Wb35Tx_stop(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 149 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 150 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 151 | |
| 152 | // Trying to canceling the Trp of EP2 |
| 153 | if (pWb35Tx->EP2vm_state == VM_RUNNING) |
| 154 | usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them |
| 155 | #ifdef _PE_TX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 156 | printk("EP2 Tx stop\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 157 | #endif |
| 158 | |
| 159 | // Trying to canceling the Irp of EP4 |
| 160 | if (pWb35Tx->EP4vm_state == VM_RUNNING) |
| 161 | usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them |
| 162 | #ifdef _PE_TX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 163 | printk("EP4 Tx stop\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 164 | #endif |
| 165 | } |
| 166 | |
| 167 | //====================================================== |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 168 | void Wb35Tx_destroy(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 169 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 170 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 171 | |
| 172 | // Wait for VM stop |
| 173 | do { |
Pekka Enberg | 34222e0 | 2008-10-22 19:07:03 +0300 | [diff] [blame] | 174 | msleep(10); // Delay for waiting function enter 940623.1.a |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 175 | } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) ); |
Pekka Enberg | 34222e0 | 2008-10-22 19:07:03 +0300 | [diff] [blame] | 176 | msleep(10); // Delay for waiting function enter 940623.1.b |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 177 | |
| 178 | if (pWb35Tx->Tx4Urb) |
| 179 | usb_free_urb( pWb35Tx->Tx4Urb ); |
| 180 | |
| 181 | if (pWb35Tx->Tx2Urb) |
| 182 | usb_free_urb( pWb35Tx->Tx2Urb ); |
| 183 | |
| 184 | #ifdef _PE_TX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 185 | printk("Wb35Tx_destroy OK\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 186 | #endif |
| 187 | } |
| 188 | |
Pekka Enberg | 1e8a2b6 | 2008-10-30 16:14:38 +0200 | [diff] [blame] | 189 | void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 190 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 191 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 192 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 193 | unsigned char Trigger = false; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 194 | |
| 195 | if (pWb35Tx->TxTimer > TimeCount) |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 196 | Trigger = true; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 197 | else if (TimeCount > (pWb35Tx->TxTimer+500)) |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 198 | Trigger = true; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 199 | |
| 200 | if (Trigger) { |
| 201 | pWb35Tx->TxTimer = TimeCount; |
Pekka Enberg | 42c84bb | 2008-10-30 16:14:36 +0200 | [diff] [blame] | 202 | Wb35Tx_EP2VM_start(adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 203 | } |
| 204 | } |
| 205 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 206 | static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 207 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 208 | static void Wb35Tx_EP2VM_complete(struct urb * pUrb) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 209 | { |
Pekka Enberg | 1e8a2b6 | 2008-10-30 16:14:38 +0200 | [diff] [blame] | 210 | struct wbsoft_priv *adapter = pUrb->context; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 211 | struct hw_data * pHwData = &adapter->sHwData; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 212 | T02_DESCRIPTOR T02, TSTATUS; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 213 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 8b384e0 | 2008-10-21 00:03:41 +0300 | [diff] [blame] | 214 | u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 215 | u32 i; |
| 216 | u16 InterruptInLength; |
| 217 | |
| 218 | |
| 219 | // Variable setting |
| 220 | pWb35Tx->EP2vm_state = VM_COMPLETED; |
| 221 | pWb35Tx->EP2VM_status = pUrb->status; |
| 222 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 223 | // For Linux 2.4. Interrupt will always trigger |
| 224 | if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove |
| 225 | goto error; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 226 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 227 | if (pWb35Tx->tx_halt) |
| 228 | goto error; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 229 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 230 | //The Urb is completed, check the result |
| 231 | if (pWb35Tx->EP2VM_status != 0) { |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 232 | printk("EP2 IoCompleteRoutine return error\n"); |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 233 | pWb35Tx->EP2vm_state= VM_STOP; |
| 234 | goto error; |
| 235 | } |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 236 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 237 | // Update the Tx result |
| 238 | InterruptInLength = pUrb->actual_length; |
| 239 | // Modify for minimum memory access and DWORD alignment. |
| 240 | T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0] |
| 241 | InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable |
| 242 | InterruptInLength >>= 2; // InterruptInLength/4 |
| 243 | for (i = 1; i <= InterruptInLength; i++) { |
| 244 | T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 245 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 246 | TSTATUS.value = T02.value; //20061009 anson's endian |
Pekka Enberg | 88ebc4b | 2008-10-22 11:03:19 +0300 | [diff] [blame] | 247 | Mds_SendComplete( adapter, &TSTATUS ); |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 248 | T02.value = cpu_to_le32(pltmp[i]) >> 8; |
| 249 | } |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 250 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 251 | return; |
| 252 | error: |
Pekka Enberg | 44e8541 | 2008-10-29 20:10:32 +0200 | [diff] [blame] | 253 | atomic_dec(&pWb35Tx->TxResultCount); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 254 | pWb35Tx->EP2vm_state = VM_STOP; |
| 255 | } |
| 256 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 257 | static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) |
| 258 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 259 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 260 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 261 | struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb; |
| 262 | u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; |
| 263 | int retv; |
| 264 | |
| 265 | if (pHwData->SurpriseRemove || pHwData->HwStop) |
| 266 | goto error; |
| 267 | |
| 268 | if (pWb35Tx->tx_halt) |
| 269 | goto error; |
| 270 | |
| 271 | // |
| 272 | // Issuing URB |
| 273 | // |
| 274 | usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2), |
| 275 | pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32); |
| 276 | |
| 277 | pWb35Tx->EP2vm_state = VM_RUNNING; |
| 278 | retv = usb_submit_urb(pUrb, GFP_ATOMIC); |
| 279 | |
| 280 | if (retv < 0) { |
| 281 | #ifdef _PE_TX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 282 | printk("EP2 Tx Irp sending error\n"); |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 283 | #endif |
| 284 | goto error; |
| 285 | } |
| 286 | |
| 287 | return; |
| 288 | error: |
| 289 | pWb35Tx->EP2vm_state = VM_STOP; |
| 290 | atomic_dec(&pWb35Tx->TxResultCount); |
| 291 | } |
| 292 | |
| 293 | void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter) |
| 294 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 295 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 296 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 297 | |
| 298 | // Allow only one thread to run into function |
| 299 | if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) { |
| 300 | pWb35Tx->EP2vm_state = VM_RUNNING; |
| 301 | Wb35Tx_EP2VM(adapter); |
| 302 | } |
| 303 | else |
| 304 | atomic_dec(&pWb35Tx->TxResultCount); |
| 305 | } |