• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 #include "wb35tx_f.h"
14 #include "mds_f.h"
15 #include "sysdef.h"
16 
17 unsigned char
Wb35Tx_get_tx_buffer(phw_data_t pHwData,u8 ** pBuffer)18 Wb35Tx_get_tx_buffer(phw_data_t pHwData, u8 **pBuffer)
19 {
20 	PWB35TX pWb35Tx = &pHwData->Wb35Tx;
21 
22 	*pBuffer = pWb35Tx->TxBuffer[0];
23 	return true;
24 }
25 
26 static void Wb35Tx(struct wbsoft_priv *adapter);
27 
Wb35Tx_complete(struct urb * pUrb)28 static void Wb35Tx_complete(struct urb * pUrb)
29 {
30 	struct wbsoft_priv *adapter = pUrb->context;
31 	phw_data_t	pHwData = &adapter->sHwData;
32 	PWB35TX		pWb35Tx = &pHwData->Wb35Tx;
33 	PMDS		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 	pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
40 	pWb35Tx->TxSendIndex++;
41 	pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
42 
43 	if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
44 		goto error;
45 
46 	if (pWb35Tx->tx_halt)
47 		goto error;
48 
49 	// The URB is completed, check the result
50 	if (pWb35Tx->EP4VM_status != 0) {
51 		printk("URB submission failed\n");
52 		pWb35Tx->EP4vm_state = VM_STOP;
53 		goto error;
54 	}
55 
56 	Mds_Tx(adapter);
57 	Wb35Tx(adapter);
58 	return;
59 
60 error:
61 	atomic_dec(&pWb35Tx->TxFireCounter);
62 	pWb35Tx->EP4vm_state = VM_STOP;
63 }
64 
Wb35Tx(struct wbsoft_priv * adapter)65 static void Wb35Tx(struct wbsoft_priv *adapter)
66 {
67 	phw_data_t	pHwData = &adapter->sHwData;
68 	PWB35TX		pWb35Tx = &pHwData->Wb35Tx;
69 	u8		*pTxBufferAddress;
70 	PMDS		pMds = &adapter->Mds;
71 	struct urb *	pUrb = (struct urb *)pWb35Tx->Tx4Urb;
72 	int         	retv;
73 	u32		SendIndex;
74 
75 
76 	if (pHwData->SurpriseRemove || pHwData->HwStop)
77 		goto cleanup;
78 
79 	if (pWb35Tx->tx_halt)
80 		goto cleanup;
81 
82 	// Ownership checking
83 	SendIndex = pWb35Tx->TxSendIndex;
84 	if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
85 		goto cleanup;
86 
87 	pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
88 	//
89 	// Issuing URB
90 	//
91 	usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
92 			  usb_sndbulkpipe(pHwData->WbUsb.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 
Wb35Tx_start(struct wbsoft_priv * adapter)116 void Wb35Tx_start(struct wbsoft_priv *adapter)
117 {
118 	phw_data_t pHwData = &adapter->sHwData;
119 	PWB35TX 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 
Wb35Tx_initial(phw_data_t pHwData)129 unsigned char Wb35Tx_initial(phw_data_t pHwData)
130 {
131 	PWB35TX 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 	{
140 		usb_free_urb( pWb35Tx->Tx4Urb );
141 		return false;
142 	}
143 
144 	return true;
145 }
146 
147 //======================================================
Wb35Tx_stop(phw_data_t pHwData)148 void Wb35Tx_stop(phw_data_t pHwData)
149 {
150 	PWB35TX pWb35Tx = &pHwData->Wb35Tx;
151 
152 	// Trying to canceling the Trp of EP2
153 	if (pWb35Tx->EP2vm_state == VM_RUNNING)
154 		usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
155 	#ifdef _PE_TX_DUMP_
156 	WBDEBUG(("EP2 Tx stop\n"));
157 	#endif
158 
159 	// Trying to canceling the Irp of EP4
160 	if (pWb35Tx->EP4vm_state == VM_RUNNING)
161 		usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
162 	#ifdef _PE_TX_DUMP_
163 	WBDEBUG(("EP4 Tx stop\n"));
164 	#endif
165 }
166 
167 //======================================================
Wb35Tx_destroy(phw_data_t pHwData)168 void Wb35Tx_destroy(phw_data_t pHwData)
169 {
170 	PWB35TX pWb35Tx = &pHwData->Wb35Tx;
171 
172 	// Wait for VM stop
173 	do {
174 		msleep(10);  // Delay for waiting function enter 940623.1.a
175 	} while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
176 	msleep(10);  // Delay for waiting function enter 940623.1.b
177 
178 	if (pWb35Tx->Tx4Urb)
179 		usb_free_urb( pWb35Tx->Tx4Urb );
180 
181 	if (pWb35Tx->Tx2Urb)
182 		usb_free_urb( pWb35Tx->Tx2Urb );
183 
184 	#ifdef _PE_TX_DUMP_
185 	WBDEBUG(("Wb35Tx_destroy OK\n"));
186 	#endif
187 }
188 
Wb35Tx_CurrentTime(struct wbsoft_priv * adapter,u32 TimeCount)189 void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
190 {
191 	phw_data_t pHwData = &adapter->sHwData;
192 	PWB35TX pWb35Tx = &pHwData->Wb35Tx;
193 	unsigned char Trigger = false;
194 
195 	if (pWb35Tx->TxTimer > TimeCount)
196 		Trigger = true;
197 	else if (TimeCount > (pWb35Tx->TxTimer+500))
198 		Trigger = true;
199 
200 	if (Trigger) {
201 		pWb35Tx->TxTimer = TimeCount;
202 		Wb35Tx_EP2VM_start(adapter);
203 	}
204 }
205 
206 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
207 
Wb35Tx_EP2VM_complete(struct urb * pUrb)208 static void Wb35Tx_EP2VM_complete(struct urb * pUrb)
209 {
210 	struct wbsoft_priv *adapter = pUrb->context;
211 	phw_data_t	pHwData = &adapter->sHwData;
212 	T02_DESCRIPTOR	T02, TSTATUS;
213 	PWB35TX		pWb35Tx = &pHwData->Wb35Tx;
214 	u32 *		pltmp = (u32 *)pWb35Tx->EP2_buf;
215 	u32		i;
216 	u16		InterruptInLength;
217 
218 
219 	// Variable setting
220 	pWb35Tx->EP2vm_state = VM_COMPLETED;
221 	pWb35Tx->EP2VM_status = pUrb->status;
222 
223 	// For Linux 2.4. Interrupt will always trigger
224 	if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
225 		goto error;
226 
227 	if (pWb35Tx->tx_halt)
228 		goto error;
229 
230 	//The Urb is completed, check the result
231 	if (pWb35Tx->EP2VM_status != 0) {
232 		WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
233 		pWb35Tx->EP2vm_state= VM_STOP;
234 		goto error;
235 	}
236 
237 	// Update the Tx result
238 	InterruptInLength = pUrb->actual_length;
239 	// Modify for minimum memory access and DWORD alignment.
240 	T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
241 	InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
242 	InterruptInLength >>= 2; // InterruptInLength/4
243 	for (i = 1; i <= InterruptInLength; i++) {
244 		T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
245 
246 		TSTATUS.value = T02.value;  //20061009 anson's endian
247 		Mds_SendComplete( adapter, &TSTATUS );
248 		T02.value = cpu_to_le32(pltmp[i]) >> 8;
249 	}
250 
251 	return;
252 error:
253 	atomic_dec(&pWb35Tx->TxResultCount);
254 	pWb35Tx->EP2vm_state = VM_STOP;
255 }
256 
Wb35Tx_EP2VM(struct wbsoft_priv * adapter)257 static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
258 {
259 	phw_data_t	pHwData = &adapter->sHwData;
260 	PWB35TX pWb35Tx = &pHwData->Wb35Tx;
261 	struct urb *	pUrb = (struct urb *)pWb35Tx->Tx2Urb;
262 	u32 *	pltmp = (u32 *)pWb35Tx->EP2_buf;
263 	int		retv;
264 
265 	if (pHwData->SurpriseRemove || pHwData->HwStop)
266 		goto error;
267 
268 	if (pWb35Tx->tx_halt)
269 		goto error;
270 
271 	//
272 	// Issuing URB
273 	//
274 	usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
275 			  pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32);
276 
277 	pWb35Tx->EP2vm_state = VM_RUNNING;
278 	retv = usb_submit_urb(pUrb, GFP_ATOMIC);
279 
280 	if (retv < 0) {
281 		#ifdef _PE_TX_DUMP_
282 		WBDEBUG(("EP2 Tx Irp sending error\n"));
283 		#endif
284 		goto error;
285 	}
286 
287 	return;
288 error:
289 	pWb35Tx->EP2vm_state = VM_STOP;
290 	atomic_dec(&pWb35Tx->TxResultCount);
291 }
292 
Wb35Tx_EP2VM_start(struct wbsoft_priv * adapter)293 void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
294 {
295 	phw_data_t pHwData = &adapter->sHwData;
296 	PWB35TX pWb35Tx = &pHwData->Wb35Tx;
297 
298 	// Allow only one thread to run into function
299 	if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
300 		pWb35Tx->EP2vm_state = VM_RUNNING;
301 		Wb35Tx_EP2VM(adapter);
302 	}
303 	else
304 		atomic_dec(&pWb35Tx->TxResultCount);
305 }
306