Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
wb35tx.c
Go to the documentation of this file.
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
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++;
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 }