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 | // Wb35Rx.c |
| 6 | // |
| 7 | // Abstract: |
| 8 | // Processing the Rx message from down layer |
| 9 | // |
| 10 | //============================================================================ |
Pekka Enberg | 80aba53 | 2008-10-30 13:04:29 +0200 | [diff] [blame] | 11 | #include <linux/usb.h> |
| 12 | |
Pekka Enberg | 7fff131 | 2008-10-30 16:14:39 +0200 | [diff] [blame] | 13 | #include "core.h" |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 14 | #include "sysdef.h" |
Pekka Enberg | 80aba53 | 2008-10-30 13:04:29 +0200 | [diff] [blame] | 15 | #include "wb35rx_f.h" |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 16 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 17 | static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int PacketSize) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 18 | { |
Pekka Enberg | 7fff131 | 2008-10-30 16:14:39 +0200 | [diff] [blame] | 19 | struct wbsoft_priv *priv = hw->priv; |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 20 | struct sk_buff *skb; |
| 21 | struct ieee80211_rx_status rx_status = {0}; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 22 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 23 | if (!priv->enabled) |
| 24 | return; |
| 25 | |
| 26 | skb = dev_alloc_skb(PacketSize); |
| 27 | if (!skb) { |
| 28 | printk("Not enough memory for packet, FIXME\n"); |
| 29 | return; |
| 30 | } |
| 31 | |
| 32 | memcpy(skb_put(skb, PacketSize), |
| 33 | pRxBufferAddress, |
| 34 | PacketSize); |
| 35 | |
| 36 | /* |
| 37 | rx_status.rate = 10; |
| 38 | rx_status.channel = 1; |
| 39 | rx_status.freq = 12345; |
| 40 | rx_status.phymode = MODE_IEEE80211B; |
| 41 | */ |
| 42 | |
Johannes Berg | f1d58c2 | 2009-06-17 13:13:00 +0200 | [diff] [blame] | 43 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); |
| 44 | ieee80211_rx_irqsafe(hw, skb); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 45 | } |
| 46 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 47 | static void Wb35Rx_adjust(PDESCRIPTOR pRxDes) |
| 48 | { |
| 49 | u32 * pRxBufferAddress; |
| 50 | u32 DecryptionMethod; |
| 51 | u32 i; |
| 52 | u16 BufferSize; |
| 53 | |
| 54 | DecryptionMethod = pRxDes->R01.R01_decryption_method; |
| 55 | pRxBufferAddress = pRxDes->buffer_address[0]; |
| 56 | BufferSize = pRxDes->buffer_size[0]; |
| 57 | |
| 58 | // Adjust the last part of data. Only data left |
| 59 | BufferSize -= 4; // For CRC-32 |
| 60 | if (DecryptionMethod) |
| 61 | BufferSize -= 4; |
| 62 | if (DecryptionMethod == 3) // For CCMP |
| 63 | BufferSize -= 4; |
| 64 | |
| 65 | // Adjust the IV field which after 802.11 header and ICV field. |
| 66 | if (DecryptionMethod == 1) // For WEP |
| 67 | { |
| 68 | for( i=6; i>0; i-- ) |
| 69 | pRxBufferAddress[i] = pRxBufferAddress[i-1]; |
| 70 | pRxDes->buffer_address[0] = pRxBufferAddress + 1; |
| 71 | BufferSize -= 4; // 4 byte for IV |
| 72 | } |
| 73 | else if( DecryptionMethod ) // For TKIP and CCMP |
| 74 | { |
| 75 | for (i=7; i>1; i--) |
| 76 | pRxBufferAddress[i] = pRxBufferAddress[i-2]; |
| 77 | pRxDes->buffer_address[0] = pRxBufferAddress + 2;//Update the descriptor, shift 8 byte |
| 78 | BufferSize -= 8; // 8 byte for IV + ICV |
| 79 | } |
| 80 | pRxDes->buffer_size[0] = BufferSize; |
| 81 | } |
| 82 | |
| 83 | static u16 Wb35Rx_indicate(struct ieee80211_hw *hw) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 84 | { |
Pekka Enberg | 7fff131 | 2008-10-30 16:14:39 +0200 | [diff] [blame] | 85 | struct wbsoft_priv *priv = hw->priv; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 86 | struct hw_data * pHwData = &priv->sHwData; |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 87 | DESCRIPTOR RxDes; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 88 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 89 | u8 * pRxBufferAddress; |
| 90 | u16 PacketSize; |
| 91 | u16 stmp, BufferSize, stmp2 = 0; |
| 92 | u32 RxBufferId; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 93 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 94 | // Only one thread be allowed to run into the following |
| 95 | do { |
| 96 | RxBufferId = pWb35Rx->RxProcessIndex; |
| 97 | if (pWb35Rx->RxOwner[ RxBufferId ]) //Owner by VM |
| 98 | break; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 99 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 100 | pWb35Rx->RxProcessIndex++; |
| 101 | pWb35Rx->RxProcessIndex %= MAX_USB_RX_BUFFER_NUMBER; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 102 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 103 | pRxBufferAddress = pWb35Rx->pDRx; |
| 104 | BufferSize = pWb35Rx->RxBufferSize[ RxBufferId ]; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 105 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 106 | // Parse the bulkin buffer |
| 107 | while (BufferSize >= 4) { |
| 108 | if ((cpu_to_le32(*(u32 *)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) //Is ending? 921002.9.a |
| 109 | break; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 110 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 111 | // Get the R00 R01 first |
| 112 | RxDes.R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress); |
| 113 | PacketSize = (u16)RxDes.R00.R00_receive_byte_count; |
| 114 | RxDes.R01.value = le32_to_cpu(*((u32 *)(pRxBufferAddress+4))); |
| 115 | // For new DMA 4k |
| 116 | if ((PacketSize & 0x03) > 0) |
| 117 | PacketSize -= 4; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 118 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 119 | // Basic check for Rx length. Is length valid? |
| 120 | if (PacketSize > MAX_PACKET_SIZE) { |
| 121 | #ifdef _PE_RX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 122 | printk("Serious ERROR : Rx data size too long, size =%d\n", PacketSize); |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 123 | #endif |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 124 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 125 | pWb35Rx->EP3vm_state = VM_STOP; |
| 126 | pWb35Rx->Ep3ErrorCount2++; |
| 127 | break; |
| 128 | } |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 129 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 130 | // Start to process Rx buffer |
| 131 | // RxDes.Descriptor_ID = RxBufferId; // Due to synchronous indicate, the field doesn't necessary to use. |
| 132 | BufferSize -= 8; //subtract 8 byte for 35's USB header length |
| 133 | pRxBufferAddress += 8; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 134 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 135 | RxDes.buffer_address[0] = pRxBufferAddress; |
| 136 | RxDes.buffer_size[0] = PacketSize; |
| 137 | RxDes.buffer_number = 1; |
| 138 | RxDes.buffer_start_index = 0; |
| 139 | RxDes.buffer_total_size = RxDes.buffer_size[0]; |
| 140 | Wb35Rx_adjust(&RxDes); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 141 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 142 | packet_came(hw, pRxBufferAddress, PacketSize); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 143 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 144 | // Move RxBuffer point to the next |
| 145 | stmp = PacketSize + 3; |
| 146 | stmp &= ~0x03; // 4n alignment |
| 147 | pRxBufferAddress += stmp; |
| 148 | BufferSize -= stmp; |
| 149 | stmp2 += stmp; |
| 150 | } |
| 151 | |
| 152 | // Reclaim resource |
| 153 | pWb35Rx->RxOwner[ RxBufferId ] = 1; |
| 154 | } while (true); |
| 155 | |
| 156 | return stmp2; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 157 | } |
| 158 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 159 | static void Wb35Rx(struct ieee80211_hw *hw); |
| 160 | |
| 161 | static void Wb35Rx_Complete(struct urb *urb) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 162 | { |
Pekka Enberg | 7fff131 | 2008-10-30 16:14:39 +0200 | [diff] [blame] | 163 | struct ieee80211_hw *hw = urb->context; |
| 164 | struct wbsoft_priv *priv = hw->priv; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 165 | struct hw_data * pHwData = &priv->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 166 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pekka Enberg | 8b384e0 | 2008-10-21 00:03:41 +0300 | [diff] [blame] | 167 | u8 * pRxBufferAddress; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 168 | u32 SizeCheck; |
| 169 | u16 BulkLength; |
| 170 | u32 RxBufferId; |
| 171 | R00_DESCRIPTOR R00; |
| 172 | |
| 173 | // Variable setting |
| 174 | pWb35Rx->EP3vm_state = VM_COMPLETED; |
Pekka Enberg | a55a89b | 2008-10-22 11:01:16 +0300 | [diff] [blame] | 175 | pWb35Rx->EP3VM_status = urb->status;//Store the last result of Irp |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 176 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 177 | RxBufferId = pWb35Rx->CurrentRxBufferId; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 178 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 179 | pRxBufferAddress = pWb35Rx->pDRx; |
Pekka Enberg | a55a89b | 2008-10-22 11:01:16 +0300 | [diff] [blame] | 180 | BulkLength = (u16)urb->actual_length; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 181 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 182 | // The IRP is completed |
| 183 | pWb35Rx->EP3vm_state = VM_COMPLETED; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 184 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 185 | if (pHwData->SurpriseRemove || pHwData->HwStop) // Must be here, or RxBufferId is invalid |
| 186 | goto error; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 187 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 188 | if (pWb35Rx->rx_halt) |
| 189 | goto error; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 190 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 191 | // Start to process the data only in successful condition |
| 192 | pWb35Rx->RxOwner[ RxBufferId ] = 0; // Set the owner to driver |
| 193 | R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 194 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 195 | // The URB is completed, check the result |
| 196 | if (pWb35Rx->EP3VM_status != 0) { |
| 197 | #ifdef _PE_USB_STATE_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 198 | printk("EP3 IoCompleteRoutine return error\n"); |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 199 | #endif |
| 200 | pWb35Rx->EP3vm_state = VM_STOP; |
| 201 | goto error; |
| 202 | } |
| 203 | |
| 204 | // 20060220 For recovering. check if operating in single USB mode |
| 205 | if (!HAL_USB_MODE_BURST(pHwData)) { |
| 206 | SizeCheck = R00.R00_receive_byte_count; //20060926 anson's endian |
| 207 | if ((SizeCheck & 0x03) > 0) |
| 208 | SizeCheck -= 4; |
| 209 | SizeCheck = (SizeCheck + 3) & ~0x03; |
| 210 | SizeCheck += 12; // 8 + 4 badbeef |
| 211 | if ((BulkLength > 1600) || |
| 212 | (SizeCheck > 1600) || |
| 213 | (BulkLength != SizeCheck) || |
| 214 | (BulkLength == 0)) { // Add for fail Urb |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 215 | pWb35Rx->EP3vm_state = VM_STOP; |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 216 | pWb35Rx->Ep3ErrorCount2++; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 217 | } |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 218 | } |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 219 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 220 | // Indicating the receiving data |
| 221 | pWb35Rx->ByteReceived += BulkLength; |
| 222 | pWb35Rx->RxBufferSize[ RxBufferId ] = BulkLength; |
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 | if (!pWb35Rx->RxOwner[ RxBufferId ]) |
Pekka Enberg | 7fff131 | 2008-10-30 16:14:39 +0200 | [diff] [blame] | 225 | Wb35Rx_indicate(hw); |
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 | kfree(pWb35Rx->pDRx); |
| 228 | // Do the next receive |
Pekka Enberg | 7fff131 | 2008-10-30 16:14:39 +0200 | [diff] [blame] | 229 | Wb35Rx(hw); |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 230 | return; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 231 | |
Pekka Enberg | dc7e04f | 2008-10-21 12:14:58 +0300 | [diff] [blame] | 232 | error: |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 233 | pWb35Rx->RxOwner[ RxBufferId ] = 1; // Set the owner to hardware |
Pekka Enberg | 44e8541 | 2008-10-29 20:10:32 +0200 | [diff] [blame] | 234 | atomic_dec(&pWb35Rx->RxFireCounter); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 235 | pWb35Rx->EP3vm_state = VM_STOP; |
| 236 | } |
| 237 | |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 238 | // This function cannot reentrain |
| 239 | static void Wb35Rx(struct ieee80211_hw *hw) |
| 240 | { |
| 241 | struct wbsoft_priv *priv = hw->priv; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 242 | struct hw_data * pHwData = &priv->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 243 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 244 | u8 * pRxBufferAddress; |
| 245 | struct urb *urb = pWb35Rx->RxUrb; |
| 246 | int retv; |
| 247 | u32 RxBufferId; |
| 248 | |
| 249 | // |
| 250 | // Issuing URB |
| 251 | // |
| 252 | if (pHwData->SurpriseRemove || pHwData->HwStop) |
| 253 | goto error; |
| 254 | |
| 255 | if (pWb35Rx->rx_halt) |
| 256 | goto error; |
| 257 | |
| 258 | // Get RxBuffer's ID |
| 259 | RxBufferId = pWb35Rx->RxBufferId; |
| 260 | if (!pWb35Rx->RxOwner[RxBufferId]) { |
| 261 | // It's impossible to run here. |
| 262 | #ifdef _PE_RX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 263 | printk("Rx driver fifo unavailable\n"); |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 264 | #endif |
| 265 | goto error; |
| 266 | } |
| 267 | |
| 268 | // Update buffer point, then start to bulkin the data from USB |
| 269 | pWb35Rx->RxBufferId++; |
| 270 | pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER; |
| 271 | |
| 272 | pWb35Rx->CurrentRxBufferId = RxBufferId; |
| 273 | |
| 274 | pWb35Rx->pDRx = kzalloc(MAX_USB_RX_BUFFER, GFP_ATOMIC); |
| 275 | if (!pWb35Rx->pDRx) { |
| 276 | printk("w35und: Rx memory alloc failed\n"); |
| 277 | goto error; |
| 278 | } |
| 279 | pRxBufferAddress = pWb35Rx->pDRx; |
| 280 | |
| 281 | usb_fill_bulk_urb(urb, pHwData->WbUsb.udev, |
| 282 | usb_rcvbulkpipe(pHwData->WbUsb.udev, 3), |
| 283 | pRxBufferAddress, MAX_USB_RX_BUFFER, |
| 284 | Wb35Rx_Complete, hw); |
| 285 | |
| 286 | pWb35Rx->EP3vm_state = VM_RUNNING; |
| 287 | |
| 288 | retv = usb_submit_urb(urb, GFP_ATOMIC); |
| 289 | |
| 290 | if (retv != 0) { |
| 291 | printk("Rx URB sending error\n"); |
| 292 | goto error; |
| 293 | } |
| 294 | return; |
| 295 | |
| 296 | error: |
| 297 | // VM stop |
| 298 | pWb35Rx->EP3vm_state = VM_STOP; |
| 299 | atomic_dec(&pWb35Rx->RxFireCounter); |
| 300 | } |
| 301 | |
| 302 | void Wb35Rx_start(struct ieee80211_hw *hw) |
| 303 | { |
| 304 | struct wbsoft_priv *priv = hw->priv; |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 305 | struct hw_data * pHwData = &priv->sHwData; |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 306 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 307 | |
| 308 | // Allow only one thread to run into the Wb35Rx() function |
| 309 | if (atomic_inc_return(&pWb35Rx->RxFireCounter) == 1) { |
| 310 | pWb35Rx->EP3vm_state = VM_RUNNING; |
| 311 | Wb35Rx(hw); |
| 312 | } else |
| 313 | atomic_dec(&pWb35Rx->RxFireCounter); |
| 314 | } |
| 315 | |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 316 | //===================================================================================== |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 317 | static void Wb35Rx_reset_descriptor( struct hw_data * pHwData ) |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 318 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 319 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pekka Enberg | c139a81 | 2008-10-30 19:04:53 +0200 | [diff] [blame] | 320 | u32 i; |
| 321 | |
| 322 | pWb35Rx->ByteReceived = 0; |
| 323 | pWb35Rx->RxProcessIndex = 0; |
| 324 | pWb35Rx->RxBufferId = 0; |
| 325 | pWb35Rx->EP3vm_state = VM_STOP; |
| 326 | pWb35Rx->rx_halt = 0; |
| 327 | |
| 328 | // Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable. |
| 329 | for( i=0; i<MAX_USB_RX_BUFFER_NUMBER; i++ ) |
| 330 | pWb35Rx->RxOwner[i] = 1; |
| 331 | } |
| 332 | |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 333 | unsigned char Wb35Rx_initial(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 334 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 335 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 336 | |
| 337 | // Initial the Buffer Queue |
| 338 | Wb35Rx_reset_descriptor( pHwData ); |
| 339 | |
Greg Kroah-Hartman | f3d2018 | 2008-10-27 14:21:24 -0700 | [diff] [blame] | 340 | pWb35Rx->RxUrb = usb_alloc_urb(0, GFP_ATOMIC); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 341 | return (!!pWb35Rx->RxUrb); |
| 342 | } |
| 343 | |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 344 | void Wb35Rx_stop(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 345 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 346 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 347 | |
| 348 | // Canceling the Irp if already sends it out. |
| 349 | if (pWb35Rx->EP3vm_state == VM_RUNNING) { |
| 350 | usb_unlink_urb( pWb35Rx->RxUrb ); // Only use unlink, let Wb35Rx_destroy to free them |
| 351 | #ifdef _PE_RX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 352 | printk("EP3 Rx stop\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 353 | #endif |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | // Needs process context |
Pekka Enberg | 8e41b4b | 2009-01-12 18:02:47 +0200 | [diff] [blame] | 358 | void Wb35Rx_destroy(struct hw_data * pHwData) |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 359 | { |
Pekka Enberg | eb62f3e | 2009-01-08 18:32:14 +0200 | [diff] [blame] | 360 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 361 | |
| 362 | do { |
Pekka Enberg | 34222e0 | 2008-10-22 19:07:03 +0300 | [diff] [blame] | 363 | msleep(10); // Delay for waiting function enter 940623.1.a |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 364 | } while (pWb35Rx->EP3vm_state != VM_STOP); |
Pekka Enberg | 34222e0 | 2008-10-22 19:07:03 +0300 | [diff] [blame] | 365 | msleep(10); // Delay for waiting function exit 940623.1.b |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 366 | |
| 367 | if (pWb35Rx->RxUrb) |
| 368 | usb_free_urb( pWb35Rx->RxUrb ); |
| 369 | #ifdef _PE_RX_DUMP_ |
Pekka Enberg | 0c59dba | 2009-01-08 11:31:59 +0200 | [diff] [blame] | 370 | printk("Wb35Rx_destroy OK\n"); |
Pavel Machek | 66101de | 2008-10-01 14:36:56 +0200 | [diff] [blame] | 371 | #endif |
| 372 | } |
| 373 | |