pvrusb2: reduce stack usage pvr2_eeprom_analyze()
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / winbond / wb35tx.c
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 */
11 #include <linux/usb.h>
12 #include <linux/gfp.h>
13
14 #include "wb35tx_f.h"
15 #include "mds_f.h"
16
17 unsigned char
18 Wb35Tx_get_tx_buffer(struct hw_data *pHwData, u8 **pBuffer)
19 {
20 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
21
22 *pBuffer = pWb35Tx->TxBuffer[0];
23 return true;
24 }
25
26 static void Wb35Tx(struct wbsoft_priv *adapter);
27
28 static void Wb35Tx_complete(struct urb *pUrb)
29 {
30 struct wbsoft_priv *adapter = pUrb->context;
31 struct hw_data *pHwData = &adapter->sHwData;
32 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
33 struct wb35_mds *pMds = &adapter->Mds;
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 /* Set the owner. Free the owner bit always. */
40 pMds->TxOwner[pWb35Tx->TxSendIndex] = 0;
41 pWb35Tx->TxSendIndex++;
42 pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
43
44 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
45 goto error;
46
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
61 error:
62 atomic_dec(&pWb35Tx->TxFireCounter);
63 pWb35Tx->EP4vm_state = VM_STOP;
64 }
65
66 static void Wb35Tx(struct wbsoft_priv *adapter)
67 {
68 struct hw_data *pHwData = &adapter->sHwData;
69 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
70 u8 *pTxBufferAddress;
71 struct wb35_mds *pMds = &adapter->Mds;
72 struct urb *pUrb = (struct urb *)pWb35Tx->Tx4Urb;
73 int retv;
74 u32 SendIndex;
75
76 if (pHwData->SurpriseRemove)
77 goto cleanup;
78
79 if (pWb35Tx->tx_halt)
80 goto cleanup;
81
82 /* Ownership checking */
83 SendIndex = pWb35Tx->TxSendIndex;
84 /* No more data need to be sent, return immediately */
85 if (!pMds->TxOwner[SendIndex])
86 goto cleanup;
87
88 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
89
90 /* Issuing URB */
91 usb_fill_bulk_urb(pUrb, pHwData->udev,
92 usb_sndbulkpipe(pHwData->udev, 4),
93 pTxBufferAddress, pMds->TxBufferSize[SendIndex],
94 Wb35Tx_complete, adapter);
95
96 pWb35Tx->EP4vm_state = VM_RUNNING;
97 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
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)
106 Wb35Tx_EP2VM_start(adapter);
107
108 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
109 return;
110
111 cleanup:
112 pWb35Tx->EP4vm_state = VM_STOP;
113 atomic_dec(&pWb35Tx->TxFireCounter);
114 }
115
116 void Wb35Tx_start(struct wbsoft_priv *adapter)
117 {
118 struct hw_data *pHwData = &adapter->sHwData;
119 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
120
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);
127 }
128
129 unsigned char Wb35Tx_initial(struct hw_data *pHwData)
130 {
131 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
132
133 pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC);
134 if (!pWb35Tx->Tx4Urb)
135 return false;
136
137 pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC);
138 if (!pWb35Tx->Tx2Urb) {
139 usb_free_urb(pWb35Tx->Tx4Urb);
140 return false;
141 }
142
143 return true;
144 }
145
146 void Wb35Tx_stop(struct hw_data *pHwData)
147 {
148 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
149
150 /* Try to cancel the Trp of EP2 */
151 if (pWb35Tx->EP2vm_state == VM_RUNNING)
152 /* Only use unlink, let Wb35Tx_destroy free them */
153 usb_unlink_urb(pWb35Tx->Tx2Urb);
154 pr_debug("EP2 Tx stop\n");
155
156 /* Try to cancel the Irp of EP4 */
157 if (pWb35Tx->EP4vm_state == VM_RUNNING)
158 /* Only use unlink, let Wb35Tx_destroy free them */
159 usb_unlink_urb(pWb35Tx->Tx4Urb);
160 pr_debug("EP4 Tx stop\n");
161 }
162
163 void Wb35Tx_destroy(struct hw_data *pHwData)
164 {
165 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
166
167 /* Wait for VM stop */
168 do {
169 msleep(10); /* Delay for waiting function enter 940623.1.a */
170 } while ((pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP));
171 msleep(10); /* Delay for waiting function enter 940623.1.b */
172
173 usb_free_urb(pWb35Tx->Tx4Urb);
174 usb_free_urb(pWb35Tx->Tx2Urb);
175
176 pr_debug("Wb35Tx_destroy OK\n");
177 }
178
179 void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
180 {
181 struct hw_data *pHwData = &adapter->sHwData;
182 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
183 unsigned char Trigger = false;
184
185 if (pWb35Tx->TxTimer > TimeCount)
186 Trigger = true;
187 else if (TimeCount > (pWb35Tx->TxTimer+500))
188 Trigger = true;
189
190 if (Trigger) {
191 pWb35Tx->TxTimer = TimeCount;
192 Wb35Tx_EP2VM_start(adapter);
193 }
194 }
195
196 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
197
198 static void Wb35Tx_EP2VM_complete(struct urb *pUrb)
199 {
200 struct wbsoft_priv *adapter = pUrb->context;
201 struct hw_data *pHwData = &adapter->sHwData;
202 struct T02_descriptor T02, TSTATUS;
203 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
204 u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
205 u32 i;
206 u16 InterruptInLength;
207
208 /* Variable setting */
209 pWb35Tx->EP2vm_state = VM_COMPLETED;
210 pWb35Tx->EP2VM_status = pUrb->status;
211
212 /* For Linux 2.4. Interrupt will always trigger */
213 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
214 goto error;
215
216 if (pWb35Tx->tx_halt)
217 goto error;
218
219 /* The Urb is completed, check the result */
220 if (pWb35Tx->EP2VM_status != 0) {
221 printk("EP2 IoCompleteRoutine return error\n");
222 pWb35Tx->EP2vm_state = VM_STOP;
223 goto error;
224 }
225
226 /* Update the Tx result */
227 InterruptInLength = pUrb->actual_length;
228 /* 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 */
232 for (i = 1; i <= InterruptInLength; i++) {
233 T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
234
235 TSTATUS.value = T02.value; /* 20061009 anson's endian */
236 Mds_SendComplete(adapter, &TSTATUS);
237 T02.value = cpu_to_le32(pltmp[i]) >> 8;
238 }
239
240 return;
241 error:
242 atomic_dec(&pWb35Tx->TxResultCount);
243 pWb35Tx->EP2vm_state = VM_STOP;
244 }
245
246 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
247 {
248 struct hw_data *pHwData = &adapter->sHwData;
249 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
250 struct urb *pUrb = (struct urb *)pWb35Tx->Tx2Urb;
251 u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
252 int retv;
253
254 if (pHwData->SurpriseRemove)
255 goto error;
256
257 if (pWb35Tx->tx_halt)
258 goto error;
259
260 /* Issuing URB */
261 usb_fill_int_urb(pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev, 2),
262 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete,
263 adapter, 32);
264
265 pWb35Tx->EP2vm_state = VM_RUNNING;
266 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
267
268 if (retv < 0) {
269 pr_debug("EP2 Tx Irp sending error\n");
270 goto error;
271 }
272
273 return;
274 error:
275 pWb35Tx->EP2vm_state = VM_STOP;
276 atomic_dec(&pWb35Tx->TxResultCount);
277 }
278
279 void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
280 {
281 struct hw_data *pHwData = &adapter->sHwData;
282 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
283
284 /* Allow only one thread to run into function */
285 if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
286 pWb35Tx->EP2vm_state = VM_RUNNING;
287 Wb35Tx_EP2VM(adapter);
288 } else
289 atomic_dec(&pWb35Tx->TxResultCount);
290 }