blob: 708c5b05f86c6e929d98fe8e4f9512970a37d525 [file] [log] [blame]
Harsh Kumar8c6c4462012-09-26 23:24:45 +05301/*
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
Harsh Kumar81416442012-09-26 23:34:42 +053018Wb35Tx_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
Harsh Kumar81416442012-09-26 23:34:42 +053028static void Wb35Tx_complete(struct urb *pUrb)
Pekka Enberg5c580932008-10-30 19:04:54 +020029{
30 struct wbsoft_priv *adapter = pUrb->context;
Harsh Kumar81416442012-09-26 23:34:42 +053031 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");
Harsh Kumar8c6c4462012-09-26 23:24:45 +053036 /* Variable setting */
Pekka Enberg5c580932008-10-30 19:04:54 +020037 pWb35Tx->EP4vm_state = VM_COMPLETED;
Harsh Kumar8c6c4462012-09-26 23:24:45 +053038 pWb35Tx->EP4VM_status = pUrb->status; /* Store the last result of Irp */
39 /* Set the owner. Free the owner bit always. */
Harsh Kumar81416442012-09-26 23:34:42 +053040 pMds->TxOwner[pWb35Tx->TxSendIndex] = 0;
Pekka Enberg5c580932008-10-30 19:04:54 +020041 pWb35Tx->TxSendIndex++;
42 pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
43
Harsh Kumar907af422012-09-26 23:33:39 +053044 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
Pekka Enberg5c580932008-10-30 19:04:54 +020045 goto error;
46
47 if (pWb35Tx->tx_halt)
48 goto error;
49
Harsh Kumar8c6c4462012-09-26 23:24:45 +053050 /* The URB is completed, check the result */
Pekka Enberg5c580932008-10-30 19:04:54 +020051 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;
Pavel Machek66101de2008-10-01 14:36:56 +020064}
65
Pekka Enberg5c580932008-10-30 19:04:54 +020066static void Wb35Tx(struct wbsoft_priv *adapter)
Pavel Machek66101de2008-10-01 14:36:56 +020067{
Harsh Kumar81416442012-09-26 23:34:42 +053068 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +020069 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg8b384e02008-10-21 00:03:41 +030070 u8 *pTxBufferAddress;
Pekka Enbergb7caf942009-08-12 11:03:33 +030071 struct wb35_mds *pMds = &adapter->Mds;
Harsh Kumar81416442012-09-26 23:34:42 +053072 struct urb *pUrb = (struct urb *)pWb35Tx->Tx4Urb;
73 int retv;
Pavel Machek66101de2008-10-01 14:36:56 +020074 u32 SendIndex;
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
Harsh Kumar8c6c4462012-09-26 23:24:45 +053082 /* Ownership checking */
Pavel Machek66101de2008-10-01 14:36:56 +020083 SendIndex = pWb35Tx->TxSendIndex;
Harsh Kumar8c6c4462012-09-26 23:24:45 +053084 /* No more data need to be sent, return immediately */
85 if (!pMds->TxOwner[SendIndex])
Pavel Machek66101de2008-10-01 14:36:56 +020086 goto cleanup;
87
88 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
Harsh Kumar8c6c4462012-09-26 23:24:45 +053089
90 /* Issuing URB */
Pekka Enberg2894c6c2010-11-28 23:00:08 +020091 usb_fill_bulk_urb(pUrb, pHwData->udev,
92 usb_sndbulkpipe(pHwData->udev, 4),
Harsh Kumar81416442012-09-26 23:34:42 +053093 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);
Harsh Kumar81416442012-09-26 23:34:42 +053098 if (retv < 0) {
Pavel Machek66101de2008-10-01 14:36:56 +020099 printk("EP4 Tx Irp sending error\n");
100 goto cleanup;
101 }
102
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530103 /* Check if driver needs issue Irp for EP2 */
Pavel Machek66101de2008-10-01 14:36:56 +0200104 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{
Harsh Kumar81416442012-09-26 23:34:42 +0530118 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
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530121 /* Allow only one thread to run into function */
Pekka Enberg5c580932008-10-30 19:04:54 +0200122 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
Harsh Kumar81416442012-09-26 23:34:42 +0530129unsigned 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);
Harsh Kumar926ae5252012-09-26 23:35:42 +0530138 if (!pWb35Tx->Tx2Urb) {
Harsh Kumar81416442012-09-26 23:34:42 +0530139 usb_free_urb(pWb35Tx->Tx4Urb);
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200140 return false;
Pavel Machek66101de2008-10-01 14:36:56 +0200141 }
142
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200143 return true;
Pavel Machek66101de2008-10-01 14:36:56 +0200144}
145
Harsh Kumar81416442012-09-26 23:34:42 +0530146void Wb35Tx_stop(struct hw_data *pHwData)
Pavel Machek66101de2008-10-01 14:36:56 +0200147{
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200148 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +0200149
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530150 /* Try to cancel the Trp of EP2 */
Pavel Machek66101de2008-10-01 14:36:56 +0200151 if (pWb35Tx->EP2vm_state == VM_RUNNING)
Harsh Kumar907af422012-09-26 23:33:39 +0530152 /* Only use unlink, let Wb35Tx_destroy free them */
Harsh Kumar81416442012-09-26 23:34:42 +0530153 usb_unlink_urb(pWb35Tx->Tx2Urb);
Pekka Enberg2855bb72010-11-28 23:00:00 +0200154 pr_debug("EP2 Tx stop\n");
Pavel Machek66101de2008-10-01 14:36:56 +0200155
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530156 /* Try to cancel the Irp of EP4 */
Pavel Machek66101de2008-10-01 14:36:56 +0200157 if (pWb35Tx->EP4vm_state == VM_RUNNING)
Harsh Kumar907af422012-09-26 23:33:39 +0530158 /* Only use unlink, let Wb35Tx_destroy free them */
Harsh Kumar81416442012-09-26 23:34:42 +0530159 usb_unlink_urb(pWb35Tx->Tx4Urb);
Pekka Enberg2855bb72010-11-28 23:00:00 +0200160 pr_debug("EP4 Tx stop\n");
Pavel Machek66101de2008-10-01 14:36:56 +0200161}
162
Harsh Kumar81416442012-09-26 23:34:42 +0530163void Wb35Tx_destroy(struct hw_data *pHwData)
Pavel Machek66101de2008-10-01 14:36:56 +0200164{
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200165 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pavel Machek66101de2008-10-01 14:36:56 +0200166
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530167 /* Wait for VM stop */
Pavel Machek66101de2008-10-01 14:36:56 +0200168 do {
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530169 msleep(10); /* Delay for waiting function enter 940623.1.a */
Harsh Kumar81416442012-09-26 23:34:42 +0530170 } while ((pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP));
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530171 msleep(10); /* Delay for waiting function enter 940623.1.b */
Pavel Machek66101de2008-10-01 14:36:56 +0200172
Harsh Kumaree692cf2012-09-26 23:36:15 +0530173 usb_free_urb(pWb35Tx->Tx4Urb);
174 usb_free_urb(pWb35Tx->Tx2Urb);
Pavel Machek66101de2008-10-01 14:36:56 +0200175
Pekka Enberg2855bb72010-11-28 23:00:00 +0200176 pr_debug("Wb35Tx_destroy OK\n");
Pavel Machek66101de2008-10-01 14:36:56 +0200177}
178
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200179void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
Pavel Machek66101de2008-10-01 14:36:56 +0200180{
Harsh Kumar81416442012-09-26 23:34:42 +0530181 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200182 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Peter Senna Tschudinffb324a2013-09-22 00:27:49 +0200183 bool Trigger = false;
Pavel Machek66101de2008-10-01 14:36:56 +0200184
185 if (pWb35Tx->TxTimer > TimeCount)
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200186 Trigger = true;
Pavel Machek66101de2008-10-01 14:36:56 +0200187 else if (TimeCount > (pWb35Tx->TxTimer+500))
Pekka Enberg279b6cc2008-10-27 22:46:39 +0200188 Trigger = true;
Pavel Machek66101de2008-10-01 14:36:56 +0200189
190 if (Trigger) {
191 pWb35Tx->TxTimer = TimeCount;
Pekka Enberg42c84bb2008-10-30 16:14:36 +0200192 Wb35Tx_EP2VM_start(adapter);
Pavel Machek66101de2008-10-01 14:36:56 +0200193 }
194}
195
Pekka Enberg5c580932008-10-30 19:04:54 +0200196static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
Pavel Machek66101de2008-10-01 14:36:56 +0200197
Harsh Kumar81416442012-09-26 23:34:42 +0530198static void Wb35Tx_EP2VM_complete(struct urb *pUrb)
Pavel Machek66101de2008-10-01 14:36:56 +0200199{
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200200 struct wbsoft_priv *adapter = pUrb->context;
Harsh Kumar81416442012-09-26 23:34:42 +0530201 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enbergc4d562a2010-09-19 12:28:38 +0300202 struct T02_descriptor T02, TSTATUS;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200203 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Harsh Kumar81416442012-09-26 23:34:42 +0530204 u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
Pavel Machek66101de2008-10-01 14:36:56 +0200205 u32 i;
206 u16 InterruptInLength;
207
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530208 /* Variable setting */
Pavel Machek66101de2008-10-01 14:36:56 +0200209 pWb35Tx->EP2vm_state = VM_COMPLETED;
210 pWb35Tx->EP2VM_status = pUrb->status;
211
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530212 /* For Linux 2.4. Interrupt will always trigger */
Harsh Kumar907af422012-09-26 23:33:39 +0530213 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300214 goto error;
Pavel Machek66101de2008-10-01 14:36:56 +0200215
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300216 if (pWb35Tx->tx_halt)
217 goto error;
Pavel Machek66101de2008-10-01 14:36:56 +0200218
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530219 /* The Urb is completed, check the result */
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300220 if (pWb35Tx->EP2VM_status != 0) {
Pekka Enberg0c59dba2009-01-08 11:31:59 +0200221 printk("EP2 IoCompleteRoutine return error\n");
Harsh Kumar81416442012-09-26 23:34:42 +0530222 pWb35Tx->EP2vm_state = VM_STOP;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300223 goto error;
224 }
Pavel Machek66101de2008-10-01 14:36:56 +0200225
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530226 /* Update the Tx result */
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300227 InterruptInLength = pUrb->actual_length;
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530228 /* Modify for minimum memory access and DWORD alignment. */
229 T02.value = cpu_to_le32(pltmp[0]) >> 8; /* [31:8] -> [24:0] */
230 InterruptInLength -= 1; /* 20051221.1.c Modify the follow for more stable */
231 InterruptInLength >>= 2; /* InterruptInLength/4 */
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300232 for (i = 1; i <= InterruptInLength; i++) {
233 T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
Pavel Machek66101de2008-10-01 14:36:56 +0200234
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530235 TSTATUS.value = T02.value; /* 20061009 anson's endian */
Harsh Kumar81416442012-09-26 23:34:42 +0530236 Mds_SendComplete(adapter, &TSTATUS);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300237 T02.value = cpu_to_le32(pltmp[i]) >> 8;
238 }
Pavel Machek66101de2008-10-01 14:36:56 +0200239
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300240 return;
241error:
Pekka Enberg44e85412008-10-29 20:10:32 +0200242 atomic_dec(&pWb35Tx->TxResultCount);
Pavel Machek66101de2008-10-01 14:36:56 +0200243 pWb35Tx->EP2vm_state = VM_STOP;
244}
245
Pekka Enberg5c580932008-10-30 19:04:54 +0200246static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
247{
Harsh Kumar81416442012-09-26 23:34:42 +0530248 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200249 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Harsh Kumar81416442012-09-26 23:34:42 +0530250 struct urb *pUrb = (struct urb *)pWb35Tx->Tx2Urb;
251 u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
Pekka Enberg5c580932008-10-30 19:04:54 +0200252 int retv;
253
Pekka Enberg87cb9a62010-11-01 22:29:30 +0200254 if (pHwData->SurpriseRemove)
Pekka Enberg5c580932008-10-30 19:04:54 +0200255 goto error;
256
257 if (pWb35Tx->tx_halt)
258 goto error;
259
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530260 /* Issuing URB */
Harsh Kumar81416442012-09-26 23:34:42 +0530261 usb_fill_int_urb(pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev, 2),
Harsh Kumar926ae5252012-09-26 23:35:42 +0530262 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete,
263 adapter, 32);
Pekka Enberg5c580932008-10-30 19:04:54 +0200264
265 pWb35Tx->EP2vm_state = VM_RUNNING;
266 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
267
268 if (retv < 0) {
Pekka Enberg2855bb72010-11-28 23:00:00 +0200269 pr_debug("EP2 Tx Irp sending error\n");
Pekka Enberg5c580932008-10-30 19:04:54 +0200270 goto error;
271 }
272
273 return;
274error:
275 pWb35Tx->EP2vm_state = VM_STOP;
276 atomic_dec(&pWb35Tx->TxResultCount);
277}
278
279void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
280{
Harsh Kumar81416442012-09-26 23:34:42 +0530281 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enbergeb62f3e2009-01-08 18:32:14 +0200282 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
Pekka Enberg5c580932008-10-30 19:04:54 +0200283
Harsh Kumar8c6c4462012-09-26 23:24:45 +0530284 /* Allow only one thread to run into function */
Pekka Enberg5c580932008-10-30 19:04:54 +0200285 if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
286 pWb35Tx->EP2vm_state = VM_RUNNING;
287 Wb35Tx_EP2VM(adapter);
Karthigan Srinivasanaf12cc52011-03-31 15:00:17 -0500288 } else
Pekka Enberg5c580932008-10-30 19:04:54 +0200289 atomic_dec(&pWb35Tx->TxResultCount);
290}