Merge tag 'sound-fix-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[deliverable/linux.git] / drivers / staging / winbond / wb35tx.c
CommitLineData
8c6c4460
HK
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"
66101de1
PM
16
17unsigned char
81416446 18Wb35Tx_get_tx_buffer(struct hw_data *pHwData, u8 **pBuffer)
66101de1 19{
eb62f3ea 20 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
66101de1
PM
21
22 *pBuffer = pWb35Tx->TxBuffer[0];
279b6ccc 23 return true;
66101de1
PM
24}
25
5c58093e
PE
26static void Wb35Tx(struct wbsoft_priv *adapter);
27
81416446 28static void Wb35Tx_complete(struct urb *pUrb)
66101de1 29{
5c58093e 30 struct wbsoft_priv *adapter = pUrb->context;
81416446 31 struct hw_data *pHwData = &adapter->sHwData;
eb62f3ea 32 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
b7caf94f 33 struct wb35_mds *pMds = &adapter->Mds;
66101de1 34
5c58093e 35 printk("wb35: tx complete\n");
8c6c4460 36 /* Variable setting */
5c58093e 37 pWb35Tx->EP4vm_state = VM_COMPLETED;
8c6c4460
HK
38 pWb35Tx->EP4VM_status = pUrb->status; /* Store the last result of Irp */
39 /* Set the owner. Free the owner bit always. */
81416446 40 pMds->TxOwner[pWb35Tx->TxSendIndex] = 0;
5c58093e
PE
41 pWb35Tx->TxSendIndex++;
42 pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
66101de1 43
907af425 44 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
5c58093e 45 goto error;
66101de1 46
5c58093e
PE
47 if (pWb35Tx->tx_halt)
48 goto error;
49
8c6c4460 50 /* The URB is completed, check the result */
5c58093e 51 if (pWb35Tx->EP4VM_status != 0) {
be2b8fc1 52 dev_err(&pUrb->dev->dev, "URB submission failed\n");
5c58093e
PE
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{
81416446 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;
81416446
HK
72 struct urb *pUrb = (struct urb *)pWb35Tx->Tx4Urb;
73 int retv;
66101de1
PM
74 u32 SendIndex;
75
87cb9a63 76 if (pHwData->SurpriseRemove)
66101de1
PM
77 goto cleanup;
78
79 if (pWb35Tx->tx_halt)
80 goto cleanup;
81
8c6c4460 82 /* Ownership checking */
66101de1 83 SendIndex = pWb35Tx->TxSendIndex;
8c6c4460
HK
84 /* No more data need to be sent, return immediately */
85 if (!pMds->TxOwner[SendIndex])
66101de1
PM
86 goto cleanup;
87
88 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
8c6c4460
HK
89
90 /* Issuing URB */
2894c6cd
PE
91 usb_fill_bulk_urb(pUrb, pHwData->udev,
92 usb_sndbulkpipe(pHwData->udev, 4),
81416446 93 pTxBufferAddress, pMds->TxBufferSize[SendIndex],
42c84bb4 94 Wb35Tx_complete, adapter);
66101de1
PM
95
96 pWb35Tx->EP4vm_state = VM_RUNNING;
7c126043 97 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
81416446 98 if (retv < 0) {
be2b8fc1 99 dev_err(&pUrb->dev->dev, "EP4 Tx Irp sending error\n");
66101de1
PM
100 goto cleanup;
101 }
102
8c6c4460 103 /* Check if driver needs issue Irp for EP2 */
66101de1
PM
104 pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
105 if (pWb35Tx->TxFillCount > 12)
42c84bb4 106 Wb35Tx_EP2VM_start(adapter);
66101de1
PM
107
108 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
109 return;
110
111 cleanup:
112 pWb35Tx->EP4vm_state = VM_STOP;
44e8541c 113 atomic_dec(&pWb35Tx->TxFireCounter);
66101de1
PM
114}
115
5c58093e 116void Wb35Tx_start(struct wbsoft_priv *adapter)
66101de1 117{
81416446 118 struct hw_data *pHwData = &adapter->sHwData;
eb62f3ea 119 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
66101de1 120
8c6c4460 121 /* Allow only one thread to run into function */
5c58093e
PE
122 if (atomic_inc_return(&pWb35Tx->TxFireCounter) == 1) {
123 pWb35Tx->EP4vm_state = VM_RUNNING;
124 Wb35Tx(adapter);
125 } else
126 atomic_dec(&pWb35Tx->TxFireCounter);
66101de1
PM
127}
128
81416446 129unsigned char Wb35Tx_initial(struct hw_data *pHwData)
66101de1 130{
eb62f3ea 131 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
66101de1 132
f3d20188 133 pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC);
66101de1 134 if (!pWb35Tx->Tx4Urb)
279b6ccc 135 return false;
66101de1 136
f3d20188 137 pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC);
926ae525 138 if (!pWb35Tx->Tx2Urb) {
81416446 139 usb_free_urb(pWb35Tx->Tx4Urb);
279b6ccc 140 return false;
66101de1
PM
141 }
142
279b6ccc 143 return true;
66101de1
PM
144}
145
81416446 146void Wb35Tx_stop(struct hw_data *pHwData)
66101de1 147{
eb62f3ea 148 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
66101de1 149
8c6c4460 150 /* Try to cancel the Trp of EP2 */
66101de1 151 if (pWb35Tx->EP2vm_state == VM_RUNNING)
907af425 152 /* Only use unlink, let Wb35Tx_destroy free them */
81416446 153 usb_unlink_urb(pWb35Tx->Tx2Urb);
2855bb79 154 pr_debug("EP2 Tx stop\n");
66101de1 155
8c6c4460 156 /* Try to cancel the Irp of EP4 */
66101de1 157 if (pWb35Tx->EP4vm_state == VM_RUNNING)
907af425 158 /* Only use unlink, let Wb35Tx_destroy free them */
81416446 159 usb_unlink_urb(pWb35Tx->Tx4Urb);
2855bb79 160 pr_debug("EP4 Tx stop\n");
66101de1
PM
161}
162
81416446 163void Wb35Tx_destroy(struct hw_data *pHwData)
66101de1 164{
eb62f3ea 165 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
66101de1 166
8c6c4460 167 /* Wait for VM stop */
66101de1 168 do {
8c6c4460 169 msleep(10); /* Delay for waiting function enter 940623.1.a */
81416446 170 } while ((pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP));
8c6c4460 171 msleep(10); /* Delay for waiting function enter 940623.1.b */
66101de1 172
ee692cfa
HK
173 usb_free_urb(pWb35Tx->Tx4Urb);
174 usb_free_urb(pWb35Tx->Tx2Urb);
66101de1 175
2855bb79 176 pr_debug("Wb35Tx_destroy OK\n");
66101de1
PM
177}
178
1e8a2b60 179void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
66101de1 180{
81416446 181 struct hw_data *pHwData = &adapter->sHwData;
eb62f3ea 182 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
ffb324aa 183 bool Trigger = false;
66101de1
PM
184
185 if (pWb35Tx->TxTimer > TimeCount)
279b6ccc 186 Trigger = true;
66101de1 187 else if (TimeCount > (pWb35Tx->TxTimer+500))
279b6ccc 188 Trigger = true;
66101de1
PM
189
190 if (Trigger) {
191 pWb35Tx->TxTimer = TimeCount;
42c84bb4 192 Wb35Tx_EP2VM_start(adapter);
66101de1
PM
193 }
194}
195
5c58093e 196static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
66101de1 197
81416446 198static void Wb35Tx_EP2VM_complete(struct urb *pUrb)
66101de1 199{
1e8a2b60 200 struct wbsoft_priv *adapter = pUrb->context;
81416446 201 struct hw_data *pHwData = &adapter->sHwData;
c4d562a9 202 struct T02_descriptor T02, TSTATUS;
eb62f3ea 203 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
81416446 204 u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
66101de1
PM
205 u32 i;
206 u16 InterruptInLength;
207
8c6c4460 208 /* Variable setting */
66101de1
PM
209 pWb35Tx->EP2vm_state = VM_COMPLETED;
210 pWb35Tx->EP2VM_status = pUrb->status;
211
8c6c4460 212 /* For Linux 2.4. Interrupt will always trigger */
907af425 213 if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */
dc7e04fe
PE
214 goto error;
215
216 if (pWb35Tx->tx_halt)
217 goto error;
218
8c6c4460 219 /* The Urb is completed, check the result */
dc7e04fe 220 if (pWb35Tx->EP2VM_status != 0) {
be2b8fc1 221 dev_err(&pUrb->dev->dev, "EP2 IoCompleteRoutine return error\n");
81416446 222 pWb35Tx->EP2vm_state = VM_STOP;
dc7e04fe
PE
223 goto error;
224 }
66101de1 225
8c6c4460 226 /* Update the Tx result */
dc7e04fe 227 InterruptInLength = pUrb->actual_length;
8c6c4460
HK
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 */
dc7e04fe
PE
232 for (i = 1; i <= InterruptInLength; i++) {
233 T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
234
8c6c4460 235 TSTATUS.value = T02.value; /* 20061009 anson's endian */
81416446 236 Mds_SendComplete(adapter, &TSTATUS);
dc7e04fe
PE
237 T02.value = cpu_to_le32(pltmp[i]) >> 8;
238 }
239
240 return;
241error:
44e8541c 242 atomic_dec(&pWb35Tx->TxResultCount);
66101de1
PM
243 pWb35Tx->EP2vm_state = VM_STOP;
244}
245
5c58093e
PE
246static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
247{
81416446 248 struct hw_data *pHwData = &adapter->sHwData;
eb62f3ea 249 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
81416446
HK
250 struct urb *pUrb = (struct urb *)pWb35Tx->Tx2Urb;
251 u32 *pltmp = (u32 *)pWb35Tx->EP2_buf;
5c58093e
PE
252 int retv;
253
87cb9a63 254 if (pHwData->SurpriseRemove)
5c58093e
PE
255 goto error;
256
257 if (pWb35Tx->tx_halt)
258 goto error;
259
8c6c4460 260 /* Issuing URB */
81416446 261 usb_fill_int_urb(pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev, 2),
926ae525
HK
262 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete,
263 adapter, 32);
5c58093e
PE
264
265 pWb35Tx->EP2vm_state = VM_RUNNING;
266 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
267
268 if (retv < 0) {
2855bb79 269 pr_debug("EP2 Tx Irp sending error\n");
5c58093e
PE
270 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{
81416446 281 struct hw_data *pHwData = &adapter->sHwData;
eb62f3ea 282 struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
5c58093e 283
8c6c4460 284 /* Allow only one thread to run into function */
5c58093e
PE
285 if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
286 pWb35Tx->EP2vm_state = VM_RUNNING;
287 Wb35Tx_EP2VM(adapter);
af12cc50 288 } else
5c58093e
PE
289 atomic_dec(&pWb35Tx->TxResultCount);
290}
This page took 0.522104 seconds and 5 git commands to generate.