blob: 5df39d46cda48e1f26450229dc190111d4e52a9e [file] [log] [blame]
Pavel Machek66101de2008-10-01 14:36:56 +02001//============================================================================
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 Enberg80aba532008-10-30 13:04:29 +020011#include <linux/usb.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/gfp.h>
Pavel Machek66101de2008-10-01 14:36:56 +020013
Pekka Enberg80aba532008-10-30 13:04:29 +020014#include "wb35tx_f.h"
Pekka Enberg9ce922f2008-10-30 13:05:42 +020015#include "mds_f.h"
Pavel Machek66101de2008-10-01 14:36:56 +020016
17unsigned char
Pekka Enberg8e41b4b2009-01-12 18:02:47 +020018Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer)
Pavel Machek66101de2008-10-01 14:36:56 +020019{
Pekka Enbergeb62f3e2009-01-08 18:32:14 +020020 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +020021
22 *pBuffer = pWb35Tx->TxBuffer[0];
Pekka Enberg279b6cc2008-10-27 22:46:39 +020023 return true;
Pavel Machek66101de2008-10-01 14:36:56 +020024}
25
Pekka Enberg5c580932008-10-30 19:04:54 +020026static void Wb35Tx(struct wbsoft_priv *adapter);
Pavel Machek66101de2008-10-01 14:36:56 +020027
Pekka Enberg5c580932008-10-30 19:04:54 +020028static void Wb35Tx_complete(struct urb * pUrb)
29{
30 struct wbsoft_priv *adapter = pUrb->context;
Pekka Enberg8e41b4b2009-01-12 18:02:47 +020031 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +020032 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enbergb7caf942009-08-12 11:03:33 +030033 struct wb35_mds *pMds = &adapter->Mds;
Pekka Enberg5c580932008-10-30 19:04:54 +020034
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 Enberg87cb9a62010-11-01 22:29:30 +020043 if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
Pekka Enberg5c580932008-10-30 19:04:54 +020044 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
60error:
61 atomic_dec(&pWb35Tx->TxFireCounter);
62 pWb35Tx->EP4vm_state = VM_STOP;
Pavel Machek66101de2008-10-01 14:36:56 +020063}
64
Pekka Enberg5c580932008-10-30 19:04:54 +020065static void Wb35Tx(struct wbsoft_priv *adapter)
Pavel Machek66101de2008-10-01 14:36:56 +020066{
Pekka Enberg8e41b4b2009-01-12 18:02:47 +020067 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +020068 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg8b384e02008-10-21 00:03:41 +030069 u8 *pTxBufferAddress;
Pekka Enbergb7caf942009-08-12 11:03:33 +030070 struct wb35_mds *pMds = &adapter->Mds;
Pavel Machek66101de2008-10-01 14:36:56 +020071 struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
72 int retv;
73 u32 SendIndex;
74
75
Pekka Enberg87cb9a62010-11-01 22:29:30 +020076 if (pHwData->SurpriseRemove)
Pavel Machek66101de2008-10-01 14:36:56 +020077 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 Enberg2894c6c2010-11-28 23:00:08 +020091 usb_fill_bulk_urb(pUrb, pHwData->udev,
92 usb_sndbulkpipe(pHwData->udev, 4),
Pavel Machek66101de2008-10-01 14:36:56 +020093 pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
Pekka Enberg42c84bb2008-10-30 16:14:36 +020094 Wb35Tx_complete, adapter);
Pavel Machek66101de2008-10-01 14:36:56 +020095
96 pWb35Tx->EP4vm_state = VM_RUNNING;
Greg Kroah-Hartman7c126042008-10-27 14:21:24 -070097 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
Pavel Machek66101de2008-10-01 14:36:56 +020098 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 Enberg42c84bb2008-10-30 16:14:36 +0200106 Wb35Tx_EP2VM_start(adapter);
Pavel Machek66101de2008-10-01 14:36:56 +0200107
108 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
109 return;
110
111 cleanup:
112 pWb35Tx->EP4vm_state = VM_STOP;
Pekka Enberg44e85412008-10-29 20:10:32 +0200113 atomic_dec(&pWb35Tx->TxFireCounter);
Pavel Machek66101de2008-10-01 14:36:56 +0200114}
115
Pekka Enberg5c580932008-10-30 19:04:54 +0200116void Wb35Tx_start(struct wbsoft_priv *adapter)
Pavel Machek66101de2008-10-01 14:36:56 +0200117{
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200118 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200119 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +0200120
Pekka Enberg5c580932008-10-30 19:04:54 +0200121 // 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 Machek66101de2008-10-01 14:36:56 +0200127}
128
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200129unsigned char Wb35Tx_initial(struct hw_data * pHwData)
Pavel Machek66101de2008-10-01 14:36:56 +0200130{
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200131 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +0200132
Greg Kroah-Hartmanf3d20182008-10-27 14:21:24 -0700133 pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC);
Pavel Machek66101de2008-10-01 14:36:56 +0200134 if (!pWb35Tx->Tx4Urb)
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200135 return false;
Pavel Machek66101de2008-10-01 14:36:56 +0200136
Greg Kroah-Hartmanf3d20182008-10-27 14:21:24 -0700137 pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC);
Pavel Machek66101de2008-10-01 14:36:56 +0200138 if (!pWb35Tx->Tx2Urb)
139 {
140 usb_free_urb( pWb35Tx->Tx4Urb );
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200141 return false;
Pavel Machek66101de2008-10-01 14:36:56 +0200142 }
143
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200144 return true;
Pavel Machek66101de2008-10-01 14:36:56 +0200145}
146
147//======================================================
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200148void Wb35Tx_stop(struct hw_data * pHwData)
Pavel Machek66101de2008-10-01 14:36:56 +0200149{
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200150 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +0200151
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 Enberg2855bb72010-11-28 23:00:00 +0200155 pr_debug("EP2 Tx stop\n");
Pavel Machek66101de2008-10-01 14:36:56 +0200156
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 Enberg2855bb72010-11-28 23:00:00 +0200160 pr_debug("EP4 Tx stop\n");
Pavel Machek66101de2008-10-01 14:36:56 +0200161}
162
163//======================================================
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200164void Wb35Tx_destroy(struct hw_data * pHwData)
Pavel Machek66101de2008-10-01 14:36:56 +0200165{
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200166 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +0200167
168 // Wait for VM stop
169 do {
Pekka Enberg34222e02008-10-22 19:07:03 +0300170 msleep(10); // Delay for waiting function enter 940623.1.a
Pavel Machek66101de2008-10-01 14:36:56 +0200171 } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
Pekka Enberg34222e02008-10-22 19:07:03 +0300172 msleep(10); // Delay for waiting function enter 940623.1.b
Pavel Machek66101de2008-10-01 14:36:56 +0200173
174 if (pWb35Tx->Tx4Urb)
175 usb_free_urb( pWb35Tx->Tx4Urb );
176
177 if (pWb35Tx->Tx2Urb)
178 usb_free_urb( pWb35Tx->Tx2Urb );
179
Pekka Enberg2855bb72010-11-28 23:00:00 +0200180 pr_debug("Wb35Tx_destroy OK\n");
Pavel Machek66101de2008-10-01 14:36:56 +0200181}
182
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200183void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
Pavel Machek66101de2008-10-01 14:36:56 +0200184{
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200185 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200186 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200187 unsigned char Trigger = false;
Pavel Machek66101de2008-10-01 14:36:56 +0200188
189 if (pWb35Tx->TxTimer > TimeCount)
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200190 Trigger = true;
Pavel Machek66101de2008-10-01 14:36:56 +0200191 else if (TimeCount > (pWb35Tx->TxTimer+500))
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200192 Trigger = true;
Pavel Machek66101de2008-10-01 14:36:56 +0200193
194 if (Trigger) {
195 pWb35Tx->TxTimer = TimeCount;
Pekka Enberg42c84bb2008-10-30 16:14:36 +0200196 Wb35Tx_EP2VM_start(adapter);
Pavel Machek66101de2008-10-01 14:36:56 +0200197 }
198}
199
Pekka Enberg5c580932008-10-30 19:04:54 +0200200static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
Pavel Machek66101de2008-10-01 14:36:56 +0200201
Pekka Enberg5c580932008-10-30 19:04:54 +0200202static void Wb35Tx_EP2VM_complete(struct urb * pUrb)
Pavel Machek66101de2008-10-01 14:36:56 +0200203{
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200204 struct wbsoft_priv *adapter = pUrb->context;
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200205 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergc4d562a2010-09-19 12:28:38 +0300206 struct T02_descriptor T02, TSTATUS;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200207 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg8b384e02008-10-21 00:03:41 +0300208 u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
Pavel Machek66101de2008-10-01 14:36:56 +0200209 u32 i;
210 u16 InterruptInLength;
211
212
213 // Variable setting
214 pWb35Tx->EP2vm_state = VM_COMPLETED;
215 pWb35Tx->EP2VM_status = pUrb->status;
216
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300217 // For Linux 2.4. Interrupt will always trigger
Pekka Enberg87cb9a62010-11-01 22:29:30 +0200218 if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300219 goto error;
Pavel Machek66101de2008-10-01 14:36:56 +0200220
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300221 if (pWb35Tx->tx_halt)
222 goto error;
Pavel Machek66101de2008-10-01 14:36:56 +0200223
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300224 //The Urb is completed, check the result
225 if (pWb35Tx->EP2VM_status != 0) {
Pekka Enberg0c59dba2009-01-08 11:31:59 +0200226 printk("EP2 IoCompleteRoutine return error\n");
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300227 pWb35Tx->EP2vm_state= VM_STOP;
228 goto error;
229 }
Pavel Machek66101de2008-10-01 14:36:56 +0200230
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300231 // 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 Machek66101de2008-10-01 14:36:56 +0200239
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300240 TSTATUS.value = T02.value; //20061009 anson's endian
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300241 Mds_SendComplete( adapter, &TSTATUS );
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300242 T02.value = cpu_to_le32(pltmp[i]) >> 8;
243 }
Pavel Machek66101de2008-10-01 14:36:56 +0200244
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300245 return;
246error:
Pekka Enberg44e85412008-10-29 20:10:32 +0200247 atomic_dec(&pWb35Tx->TxResultCount);
Pavel Machek66101de2008-10-01 14:36:56 +0200248 pWb35Tx->EP2vm_state = VM_STOP;
249}
250
Pekka Enberg5c580932008-10-30 19:04:54 +0200251static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
252{
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200253 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200254 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg5c580932008-10-30 19:04:54 +0200255 struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
256 u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
257 int retv;
258
Pekka Enberg87cb9a62010-11-01 22:29:30 +0200259 if (pHwData->SurpriseRemove)
Pekka Enberg5c580932008-10-30 19:04:54 +0200260 goto error;
261
262 if (pWb35Tx->tx_halt)
263 goto error;
264
265 //
266 // Issuing URB
267 //
Pekka Enberg2894c6c2010-11-28 23:00:08 +0200268 usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2),
Pekka Enberg5c580932008-10-30 19:04:54 +0200269 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 Enberg2855bb72010-11-28 23:00:00 +0200275 pr_debug("EP2 Tx Irp sending error\n");
Pekka Enberg5c580932008-10-30 19:04:54 +0200276 goto error;
277 }
278
279 return;
280error:
281 pWb35Tx->EP2vm_state = VM_STOP;
282 atomic_dec(&pWb35Tx->TxResultCount);
283}
284
285void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
286{
Pekka Enberg8e41b4b2009-01-12 18:02:47 +0200287 struct hw_data * pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200288 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg5c580932008-10-30 19:04:54 +0200289
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 Srinivasanaf12cc52011-03-31 15:00:17 -0500294 } else
Pekka Enberg5c580932008-10-30 19:04:54 +0200295 atomic_dec(&pWb35Tx->TxResultCount);
296}