Root/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
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}
297

Archive Download this file



interactive