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