Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.15-rc8 290 lines 7.3 kB view raw
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 /* 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 61error: 62 atomic_dec(&pWb35Tx->TxFireCounter); 63 pWb35Tx->EP4vm_state = VM_STOP; 64} 65 66static 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 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 usb_free_urb(pWb35Tx->Tx4Urb); 140 return false; 141 } 142 143 return true; 144} 145 146void 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 163void 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 179void 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 196static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter); 197 198static 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; 241error: 242 atomic_dec(&pWb35Tx->TxResultCount); 243 pWb35Tx->EP2vm_state = VM_STOP; 244} 245 246static 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; 274error: 275 pWb35Tx->EP2vm_state = VM_STOP; 276 atomic_dec(&pWb35Tx->TxResultCount); 277} 278 279void 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}