]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/winbond/wb35tx.c
arm: dts: tx6: move vbus pinctrls to regulator nodes
[karo-tx-linux.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         bool 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 }