PM / sleep: Asynchronous threads for suspend_noirq
[linux/fpc-iii.git] / drivers / staging / winbond / wb35tx.c
blob708c5b05f86c6e929d98fe8e4f9512970a37d525
1 /*
2 * Copyright (c) 1996-2002 Winbond Electronic Corporation
4 * Module Name:
5 * Wb35Tx.c
7 * Abstract:
8 * Processing the Tx message and put into down layer
11 #include <linux/usb.h>
12 #include <linux/gfp.h>
14 #include "wb35tx_f.h"
15 #include "mds_f.h"
17 unsigned char
18 Wb35Tx_get_tx_buffer(struct hw_data *pHwData, u8 **pBuffer)
20 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
22 *pBuffer = pWb35Tx->TxBuffer[0];
23 return true;
26 static void Wb35Tx(struct wbsoft_priv *adapter);
28 static void Wb35Tx_complete(struct urb *pUrb)
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;
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;
44 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
45 goto error;
47 if (pWb35Tx->tx_halt)
48 goto error;
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;
57 Mds_Tx(adapter);
58 Wb35Tx(adapter);
59 return;
61 error:
62 atomic_dec(&pWb35Tx->TxFireCounter);
63 pWb35Tx->EP4vm_state = VM_STOP;
66 static void Wb35Tx(struct wbsoft_priv *adapter)
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;
76 if (pHwData->SurpriseRemove)
77 goto cleanup;
79 if (pWb35Tx->tx_halt)
80 goto cleanup;
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;
88 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
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);
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;
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);
108 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
109 return;
111 cleanup:
112 pWb35Tx->EP4vm_state = VM_STOP;
113 atomic_dec(&pWb35Tx->TxFireCounter);
116 void Wb35Tx_start(struct wbsoft_priv *adapter)
118 struct hw_data *pHwData = &adapter->sHwData;
119 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
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);
129 unsigned char Wb35Tx_initial(struct hw_data *pHwData)
131 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
133 pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC);
134 if (!pWb35Tx->Tx4Urb)
135 return false;
137 pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC);
138 if (!pWb35Tx->Tx2Urb) {
139 usb_free_urb(pWb35Tx->Tx4Urb);
140 return false;
143 return true;
146 void Wb35Tx_stop(struct hw_data *pHwData)
148 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
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");
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");
163 void Wb35Tx_destroy(struct hw_data *pHwData)
165 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
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 */
173 usb_free_urb(pWb35Tx->Tx4Urb);
174 usb_free_urb(pWb35Tx->Tx2Urb);
176 pr_debug("Wb35Tx_destroy OK\n");
179 void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
181 struct hw_data *pHwData = &adapter->sHwData;
182 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
183 bool Trigger = false;
185 if (pWb35Tx->TxTimer > TimeCount)
186 Trigger = true;
187 else if (TimeCount > (pWb35Tx->TxTimer+500))
188 Trigger = true;
190 if (Trigger) {
191 pWb35Tx->TxTimer = TimeCount;
192 Wb35Tx_EP2VM_start(adapter);
196 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
198 static void Wb35Tx_EP2VM_complete(struct urb *pUrb)
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;
208 /* Variable setting */
209 pWb35Tx->EP2vm_state = VM_COMPLETED;
210 pWb35Tx->EP2VM_status = pUrb->status;
212 /* For Linux 2.4. Interrupt will always trigger */
213 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
214 goto error;
216 if (pWb35Tx->tx_halt)
217 goto error;
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;
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);
235 TSTATUS.value = T02.value; /* 20061009 anson's endian */
236 Mds_SendComplete(adapter, &TSTATUS);
237 T02.value = cpu_to_le32(pltmp[i]) >> 8;
240 return;
241 error:
242 atomic_dec(&pWb35Tx->TxResultCount);
243 pWb35Tx->EP2vm_state = VM_STOP;
246 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
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;
254 if (pHwData->SurpriseRemove)
255 goto error;
257 if (pWb35Tx->tx_halt)
258 goto error;
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);
265 pWb35Tx->EP2vm_state = VM_RUNNING;
266 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
268 if (retv < 0) {
269 pr_debug("EP2 Tx Irp sending error\n");
270 goto error;
273 return;
274 error:
275 pWb35Tx->EP2vm_state = VM_STOP;
276 atomic_dec(&pWb35Tx->TxResultCount);
279 void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
281 struct hw_data *pHwData = &adapter->sHwData;
282 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
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);