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> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 12 | #include <linux/gfp.h> |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 13 | |
Pekka Enberg | 80aba53 | 2008-10-30 13:04:29 +0200 | [diff] [blame] | 14 | #include "wb35tx_f.h" |
Pekka Enberg | 9ce922f | 2008-10-30 13:05:42 +0200 | [diff] [blame] | 15 | #include "mds_f.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 | b7caf94 | 2009-08-12 11:03:33 +0300 | [diff] [blame] | 33 | struct wb35_mds *pMds = &adapter->Mds; |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 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 | |
Pekka Enberg | 87cb9a6 | 2010-11-01 22:29:30 +0200 | [diff] [blame] | 43 | if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 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 | b7caf94 | 2009-08-12 11:03:33 +0300 | [diff] [blame] | 70 | struct wb35_mds *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 | |
Pekka Enberg | 87cb9a6 | 2010-11-01 22:29:30 +0200 | [diff] [blame] | 76 | if (pHwData->SurpriseRemove) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 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 | // |
Pekka Enberg | 2894c6c | 2010-11-28 23:00:08 +0200 | [diff] [blame] | 91 | usb_fill_bulk_urb(pUrb, pHwData->udev, |
| 92 | usb_sndbulkpipe(pHwData->udev, 4), |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 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 |
Pekka Enberg | 2855bb7 | 2010-11-28 23:00:00 +0200 | [diff] [blame] | 155 | pr_debug("EP2 Tx stop\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 156 | |
| 157 | // Trying to canceling the Irp of EP4 |
| 158 | if (pWb35Tx->EP4vm_state == VM_RUNNING) |
| 159 | usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them |
Pekka Enberg | 2855bb7 | 2010-11-28 23:00:00 +0200 | [diff] [blame] | 160 | pr_debug("EP4 Tx stop\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | //====================================================== |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 164 | void Wb35Tx_destroy(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 165 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 166 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 167 | |
| 168 | // Wait for VM stop |
| 169 | do { |
Pekka Enberg | 34222e0 | 2008-10-22 19:07:03 +0300 | [diff] [blame] | 170 | msleep(10); // Delay for waiting function enter 940623.1.a |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 171 | } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) ); |
Pekka Enberg | 34222e0 | 2008-10-22 19:07:03 +0300 | [diff] [blame] | 172 | msleep(10); // Delay for waiting function enter 940623.1.b |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 173 | |
| 174 | if (pWb35Tx->Tx4Urb) |
| 175 | usb_free_urb( pWb35Tx->Tx4Urb ); |
| 176 | |
| 177 | if (pWb35Tx->Tx2Urb) |
| 178 | usb_free_urb( pWb35Tx->Tx2Urb ); |
| 179 | |
Pekka Enberg | 2855bb7 | 2010-11-28 23:00:00 +0200 | [diff] [blame] | 180 | pr_debug("Wb35Tx_destroy OK\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 181 | } |
| 182 | |
Pekka Enberg | 1e8a2b6 | 2008-10-30 16:14:38 +0200 | [diff] [blame] | 183 | void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 184 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 185 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 186 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 187 | unsigned char Trigger = false; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 188 | |
| 189 | if (pWb35Tx->TxTimer > TimeCount) |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 190 | Trigger = true; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 191 | else if (TimeCount > (pWb35Tx->TxTimer+500)) |
Pekka Enberg | 279b6cc | 2008-10-27 22:46:39 +0200 | [diff] [blame] | 192 | Trigger = true; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 193 | |
| 194 | if (Trigger) { |
| 195 | pWb35Tx->TxTimer = TimeCount; |
Pekka Enberg | 42c84bb | 2008-10-30 16:14:36 +0200 | [diff] [blame] | 196 | Wb35Tx_EP2VM_start(adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 197 | } |
| 198 | } |
| 199 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 200 | static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 201 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 202 | static void Wb35Tx_EP2VM_complete(struct urb * pUrb) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 203 | { |
Pekka Enberg | 1e8a2b6 | 2008-10-30 16:14:38 +0200 | [diff] [blame] | 204 | struct wbsoft_priv *adapter = pUrb->context; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 205 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | c4d562a | 2010-09-19 12:28:38 +0300 | [diff] [blame] | 206 | struct T02_descriptor T02, TSTATUS; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 207 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 8b384e0 | 2008-10-21 00:03:41 +0300 | [diff] [blame] | 208 | u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 209 | u32 i; |
| 210 | u16 InterruptInLength; |
| 211 | |
| 212 | |
| 213 | // Variable setting |
| 214 | pWb35Tx->EP2vm_state = VM_COMPLETED; |
| 215 | pWb35Tx->EP2VM_status = pUrb->status; |
| 216 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 217 | // For Linux 2.4. Interrupt will always trigger |
Pekka Enberg | 87cb9a6 | 2010-11-01 22:29:30 +0200 | [diff] [blame] | 218 | if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 219 | goto error; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 220 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 221 | if (pWb35Tx->tx_halt) |
| 222 | goto error; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 223 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 224 | //The Urb is completed, check the result |
| 225 | if (pWb35Tx->EP2VM_status != 0) { |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 226 | printk("EP2 IoCompleteRoutine return error\n"); |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 227 | pWb35Tx->EP2vm_state= VM_STOP; |
| 228 | goto error; |
| 229 | } |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 230 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 231 | // Update the Tx result |
| 232 | InterruptInLength = pUrb->actual_length; |
| 233 | // Modify for minimum memory access and DWORD alignment. |
| 234 | T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0] |
| 235 | InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable |
| 236 | InterruptInLength >>= 2; // InterruptInLength/4 |
| 237 | for (i = 1; i <= InterruptInLength; i++) { |
| 238 | T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 239 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 240 | TSTATUS.value = T02.value; //20061009 anson's endian |
Pekka Enberg | 88ebc4b | 2008-10-22 11:03:19 +0300 | [diff] [blame] | 241 | Mds_SendComplete( adapter, &TSTATUS ); |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 242 | T02.value = cpu_to_le32(pltmp[i]) >> 8; |
| 243 | } |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 244 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 245 | return; |
| 246 | error: |
Pekka Enberg | 44e8541 | 2008-10-29 20:10:32 +0200 | [diff] [blame] | 247 | atomic_dec(&pWb35Tx->TxResultCount); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 248 | pWb35Tx->EP2vm_state = VM_STOP; |
| 249 | } |
| 250 | |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 251 | static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) |
| 252 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 253 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 254 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 255 | struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb; |
| 256 | u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; |
| 257 | int retv; |
| 258 | |
Pekka Enberg | 87cb9a6 | 2010-11-01 22:29:30 +0200 | [diff] [blame] | 259 | if (pHwData->SurpriseRemove) |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 260 | goto error; |
| 261 | |
| 262 | if (pWb35Tx->tx_halt) |
| 263 | goto error; |
| 264 | |
| 265 | // |
| 266 | // Issuing URB |
| 267 | // |
Pekka Enberg | 2894c6c | 2010-11-28 23:00:08 +0200 | [diff] [blame] | 268 | usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2), |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 269 | pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32); |
| 270 | |
| 271 | pWb35Tx->EP2vm_state = VM_RUNNING; |
| 272 | retv = usb_submit_urb(pUrb, GFP_ATOMIC); |
| 273 | |
| 274 | if (retv < 0) { |
Pekka Enberg | 2855bb7 | 2010-11-28 23:00:00 +0200 | [diff] [blame] | 275 | pr_debug("EP2 Tx Irp sending error\n"); |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 276 | goto error; |
| 277 | } |
| 278 | |
| 279 | return; |
| 280 | error: |
| 281 | pWb35Tx->EP2vm_state = VM_STOP; |
| 282 | atomic_dec(&pWb35Tx->TxResultCount); |
| 283 | } |
| 284 | |
| 285 | void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter) |
| 286 | { |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 287 | struct hw_data * pHwData = &adapter->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 288 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 289 | |
| 290 | // Allow only one thread to run into function |
| 291 | if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) { |
| 292 | pWb35Tx->EP2vm_state = VM_RUNNING; |
| 293 | Wb35Tx_EP2VM(adapter); |
Karthigan Srinivasan | af12cc5 | 2011-03-31 15:00:17 -0500 | [diff] [blame] | 294 | } else |
Pekka Enberg | 5c58093 | 2008-10-30 19:04:54 +0200 | [diff] [blame] | 295 | atomic_dec(&pWb35Tx->TxResultCount); |
| 296 | } |