Linux Audio

Check our new training course

Open-source upstreaming

Need help get the support for your hardware in upstream Linux?
Loading...
Note: File does not exist in v4.6.
  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
 17unsigned char
 18Wb35Tx_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
 26static void Wb35Tx(struct wbsoft_priv *adapter);
 27
 28static 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	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) // 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
 60error:
 61	atomic_dec(&pWb35Tx->TxFireCounter);
 62	pWb35Tx->EP4vm_state = VM_STOP;
 63}
 64
 65static void Wb35Tx(struct wbsoft_priv *adapter)
 66{
 67	struct hw_data *	pHwData = &adapter->sHwData;
 68	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
 69	u8		*pTxBufferAddress;
 70	struct wb35_mds *pMds = &adapter->Mds;
 71	struct urb *	pUrb = (struct urb *)pWb35Tx->Tx4Urb;
 72	int         	retv;
 73	u32		SendIndex;
 74
 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	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->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
116void 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
129unsigned 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	{
140		usb_free_urb( pWb35Tx->Tx4Urb );
141		return false;
142	}
143
144	return true;
145}
146
147//======================================================
148void Wb35Tx_stop(struct hw_data * pHwData)
149{
150	struct wb35_tx *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	pr_debug("EP2 Tx stop\n");
156
157	// Trying to canceling the Irp of EP4
158	if (pWb35Tx->EP4vm_state == VM_RUNNING)
159		usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
160	pr_debug("EP4 Tx stop\n");
161}
162
163//======================================================
164void Wb35Tx_destroy(struct hw_data * pHwData)
165{
166	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
167
168	// Wait for VM stop
169	do {
170		msleep(10);  // Delay for waiting function enter 940623.1.a
171	} while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
172	msleep(10);  // Delay for waiting function enter 940623.1.b
173
174	if (pWb35Tx->Tx4Urb)
175		usb_free_urb( pWb35Tx->Tx4Urb );
176
177	if (pWb35Tx->Tx2Urb)
178		usb_free_urb( pWb35Tx->Tx2Urb );
179
180	pr_debug("Wb35Tx_destroy OK\n");
181}
182
183void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount)
184{
185	struct hw_data * pHwData = &adapter->sHwData;
186	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
187	unsigned char Trigger = false;
188
189	if (pWb35Tx->TxTimer > TimeCount)
190		Trigger = true;
191	else if (TimeCount > (pWb35Tx->TxTimer+500))
192		Trigger = true;
193
194	if (Trigger) {
195		pWb35Tx->TxTimer = TimeCount;
196		Wb35Tx_EP2VM_start(adapter);
197	}
198}
199
200static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter);
201
202static void Wb35Tx_EP2VM_complete(struct urb * pUrb)
203{
204	struct wbsoft_priv *adapter = pUrb->context;
205	struct hw_data *	pHwData = &adapter->sHwData;
206	struct T02_descriptor	T02, TSTATUS;
207	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
208	u32 *		pltmp = (u32 *)pWb35Tx->EP2_buf;
209	u32		i;
210	u16		InterruptInLength;
211
212
213	// Variable setting
214	pWb35Tx->EP2vm_state = VM_COMPLETED;
215	pWb35Tx->EP2VM_status = pUrb->status;
216
217	// For Linux 2.4. Interrupt will always trigger
218	if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
219		goto error;
220
221	if (pWb35Tx->tx_halt)
222		goto error;
223
224	//The Urb is completed, check the result
225	if (pWb35Tx->EP2VM_status != 0) {
226		printk("EP2 IoCompleteRoutine return error\n");
227		pWb35Tx->EP2vm_state= VM_STOP;
228		goto error;
229	}
230
231	// Update the Tx result
232	InterruptInLength = pUrb->actual_length;
233	// Modify for minimum memory access and DWORD alignment.
234	T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
235	InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
236	InterruptInLength >>= 2; // InterruptInLength/4
237	for (i = 1; i <= InterruptInLength; i++) {
238		T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
239
240		TSTATUS.value = T02.value;  //20061009 anson's endian
241		Mds_SendComplete( adapter, &TSTATUS );
242		T02.value = cpu_to_le32(pltmp[i]) >> 8;
243	}
244
245	return;
246error:
247	atomic_dec(&pWb35Tx->TxResultCount);
248	pWb35Tx->EP2vm_state = VM_STOP;
249}
250
251static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
252{
253	struct hw_data *	pHwData = &adapter->sHwData;
254	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
255	struct urb *	pUrb = (struct urb *)pWb35Tx->Tx2Urb;
256	u32 *	pltmp = (u32 *)pWb35Tx->EP2_buf;
257	int		retv;
258
259	if (pHwData->SurpriseRemove)
260		goto error;
261
262	if (pWb35Tx->tx_halt)
263		goto error;
264
265	//
266	// Issuing URB
267	//
268	usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2),
269			  pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32);
270
271	pWb35Tx->EP2vm_state = VM_RUNNING;
272	retv = usb_submit_urb(pUrb, GFP_ATOMIC);
273
274	if (retv < 0) {
275		pr_debug("EP2 Tx Irp sending error\n");
276		goto error;
277	}
278
279	return;
280error:
281	pWb35Tx->EP2vm_state = VM_STOP;
282	atomic_dec(&pWb35Tx->TxResultCount);
283}
284
285void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter)
286{
287	struct hw_data * pHwData = &adapter->sHwData;
288	struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx;
289
290	// Allow only one thread to run into function
291	if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
292		pWb35Tx->EP2vm_state = VM_RUNNING;
293		Wb35Tx_EP2VM(adapter);
294	} else
295		atomic_dec(&pWb35Tx->TxResultCount);
296}