Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 1 | #include "headers.h" |
| 2 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 3 | INT InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter, |
| 4 | UINT addr, |
| 5 | PVOID buff, |
| 6 | INT len) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 7 | { |
| 8 | int retval = 0; |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 9 | USHORT usRetries = 0; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 10 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 11 | if (psIntfAdapter == NULL) { |
| 12 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Interface Adapter is NULL"); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 13 | return -EINVAL; |
| 14 | } |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 15 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 16 | if (psIntfAdapter->psAdapter->device_removed == TRUE) { |
| 17 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Device got removed"); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 18 | return -ENODEV; |
| 19 | } |
| 20 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 21 | if ((psIntfAdapter->psAdapter->StopAllXaction == TRUE) && (psIntfAdapter->psAdapter->chip_id >= T3LPB)) { |
| 22 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "Currently Xaction is not allowed on the bus"); |
Dan Carpenter | f05321c | 2010-11-13 07:37:49 +0300 | [diff] [blame] | 23 | return -EACCES; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 24 | } |
| 25 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 26 | if (psIntfAdapter->bSuspended == TRUE || psIntfAdapter->bPreparingForBusSuspend == TRUE) { |
| 27 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "Bus is in suspended states hence RDM not allowed.."); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 28 | return -EACCES; |
| 29 | } |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 30 | psIntfAdapter->psAdapter->DeviceAccess = TRUE; |
| 31 | |
| 32 | do { |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 33 | retval = usb_control_msg(psIntfAdapter->udev, |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 34 | usb_rcvctrlpipe(psIntfAdapter->udev, 0), |
| 35 | 0x02, |
| 36 | 0xC2, |
| 37 | (addr & 0xFFFF), |
| 38 | ((addr >> 16) & 0xFFFF), |
| 39 | buff, |
| 40 | len, |
| 41 | 5000); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 42 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 43 | usRetries++; |
| 44 | if (-ENODEV == retval) { |
| 45 | psIntfAdapter->psAdapter->device_removed = TRUE; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 46 | break; |
| 47 | } |
| 48 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 49 | } while ((retval < 0) && (usRetries < MAX_RDM_WRM_RETIRES)); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 50 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 51 | if (retval < 0) { |
| 52 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM failed status :%d, retires :%d", retval, usRetries); |
| 53 | psIntfAdapter->psAdapter->DeviceAccess = FALSE; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 54 | return retval; |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 55 | } else { |
| 56 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM sent %d", retval); |
| 57 | psIntfAdapter->psAdapter->DeviceAccess = FALSE; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 58 | return STATUS_SUCCESS; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 59 | } |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 60 | } |
| 61 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 62 | INT InterfaceWRM(PS_INTERFACE_ADAPTER psIntfAdapter, |
| 63 | UINT addr, |
| 64 | PVOID buff, |
| 65 | INT len) |
| 66 | { |
| 67 | int retval = 0; |
| 68 | USHORT usRetries = 0; |
| 69 | |
| 70 | if (psIntfAdapter == NULL) { |
| 71 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Interface Adapter is NULL"); |
| 72 | return -EINVAL; |
| 73 | } |
| 74 | |
| 75 | if (psIntfAdapter->psAdapter->device_removed == TRUE) { |
| 76 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Device got removed"); |
| 77 | return -ENODEV; |
| 78 | } |
| 79 | |
| 80 | if ((psIntfAdapter->psAdapter->StopAllXaction == TRUE) && (psIntfAdapter->psAdapter->chip_id >= T3LPB)) { |
| 81 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "Currently Xaction is not allowed on the bus..."); |
| 82 | return -EACCES; |
| 83 | } |
| 84 | |
| 85 | if (psIntfAdapter->bSuspended == TRUE || psIntfAdapter->bPreparingForBusSuspend == TRUE) { |
| 86 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "Bus is in suspended states hence RDM not allowed.."); |
| 87 | return -EACCES; |
| 88 | } |
| 89 | |
| 90 | psIntfAdapter->psAdapter->DeviceAccess = TRUE; |
| 91 | |
| 92 | do { |
| 93 | retval = usb_control_msg(psIntfAdapter->udev, |
| 94 | usb_sndctrlpipe(psIntfAdapter->udev, 0), |
| 95 | 0x01, |
| 96 | 0x42, |
| 97 | (addr & 0xFFFF), |
| 98 | ((addr >> 16) & 0xFFFF), |
| 99 | buff, |
| 100 | len, |
| 101 | 5000); |
| 102 | |
| 103 | usRetries++; |
| 104 | if (-ENODEV == retval) { |
| 105 | psIntfAdapter->psAdapter->device_removed = TRUE; |
| 106 | break; |
| 107 | } |
| 108 | |
| 109 | } while ((retval < 0) && (usRetries < MAX_RDM_WRM_RETIRES)); |
| 110 | |
| 111 | if (retval < 0) { |
| 112 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "WRM failed status :%d, retires :%d", retval, usRetries); |
| 113 | psIntfAdapter->psAdapter->DeviceAccess = FALSE; |
| 114 | return retval; |
| 115 | } else { |
| 116 | psIntfAdapter->psAdapter->DeviceAccess = FALSE; |
| 117 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "WRM sent %d", retval); |
| 118 | return STATUS_SUCCESS; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | INT BcmRDM(PVOID arg, |
| 123 | UINT addr, |
| 124 | PVOID buff, |
| 125 | INT len) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 126 | { |
| 127 | return InterfaceRDM((PS_INTERFACE_ADAPTER)arg, addr, buff, len); |
| 128 | } |
| 129 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 130 | INT BcmWRM(PVOID arg, |
| 131 | UINT addr, |
| 132 | PVOID buff, |
| 133 | INT len) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 134 | { |
| 135 | return InterfaceWRM((PS_INTERFACE_ADAPTER)arg, addr, buff, len); |
| 136 | } |
| 137 | |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 138 | INT Bcm_clear_halt_of_endpoints(PMINI_ADAPTER Adapter) |
| 139 | { |
| 140 | PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter); |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 141 | INT status = STATUS_SUCCESS; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 142 | |
| 143 | /* |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 144 | * usb_clear_halt - tells device to clear endpoint halt/stall condition |
| 145 | * @dev: device whose endpoint is halted |
| 146 | * @pipe: endpoint "pipe" being cleared |
| 147 | * @ Context: !in_interrupt () |
| 148 | * |
| 149 | * usb_clear_halt is the synchrnous call and returns 0 on success else returns with error code. |
| 150 | * This is used to clear halt conditions for bulk and interrupt endpoints only. |
| 151 | * Control and isochronous endpoints never halts. |
| 152 | * |
| 153 | * Any URBs queued for such an endpoint should normally be unlinked by the driver |
| 154 | * before clearing the halt condition. |
| 155 | * |
| 156 | */ |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 157 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 158 | /* Killing all the submitted urbs to different end points. */ |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 159 | Bcm_kill_all_URBs(psIntfAdapter); |
| 160 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 161 | /* clear the halted/stalled state for every end point */ |
| 162 | status = usb_clear_halt(psIntfAdapter->udev, psIntfAdapter->sIntrIn.int_in_pipe); |
| 163 | if (status != STATUS_SUCCESS) |
| 164 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Unable to Clear Halt of Interrupt IN end point. :%d ", status); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 165 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 166 | status = usb_clear_halt(psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_pipe); |
| 167 | if (status != STATUS_SUCCESS) |
| 168 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Unable to Clear Halt of Bulk IN end point. :%d ", status); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 169 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 170 | status = usb_clear_halt(psIntfAdapter->udev, psIntfAdapter->sBulkOut.bulk_out_pipe); |
| 171 | if (status != STATUS_SUCCESS) |
| 172 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Unable to Clear Halt of Bulk OUT end point. :%d ", status); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 173 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 174 | return status; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 175 | } |
| 176 | |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 177 | VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter) |
| 178 | { |
| 179 | struct urb *tempUrb = NULL; |
| 180 | UINT i; |
| 181 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 182 | /* |
| 183 | * usb_kill_urb - cancel a transfer request and wait for it to finish |
| 184 | * @urb: pointer to URB describing a previously submitted request, |
| 185 | * returns nothing as it is void returned API. |
| 186 | * |
| 187 | * This routine cancels an in-progress request. It is guaranteed that |
| 188 | * upon return all completion handlers will have finished and the URB |
| 189 | * will be totally idle and available for reuse |
| 190 | * |
| 191 | * This routine may not be used in an interrupt context (such as a bottom |
| 192 | * half or a completion handler), or when holding a spinlock, or in other |
| 193 | * situations where the caller can't schedule(). |
| 194 | * |
| 195 | */ |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 196 | |
| 197 | /* Cancel submitted Interrupt-URB's */ |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 198 | if (psIntfAdapter->psInterruptUrb != NULL) { |
| 199 | if (psIntfAdapter->psInterruptUrb->status == -EINPROGRESS) |
| 200 | usb_kill_urb(psIntfAdapter->psInterruptUrb); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | /* Cancel All submitted TX URB's */ |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 204 | for (i = 0; i < MAXIMUM_USB_TCB; i++) { |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 205 | tempUrb = psIntfAdapter->asUsbTcb[i].urb; |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 206 | if (tempUrb) { |
| 207 | if (tempUrb->status == -EINPROGRESS) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 208 | usb_kill_urb(tempUrb); |
| 209 | } |
| 210 | } |
| 211 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 212 | for (i = 0; i < MAXIMUM_USB_RCB; i++) { |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 213 | tempUrb = psIntfAdapter->asUsbRcb[i].urb; |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 214 | if (tempUrb) { |
| 215 | if (tempUrb->status == -EINPROGRESS) |
| 216 | usb_kill_urb(tempUrb); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 217 | } |
| 218 | } |
| 219 | |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 220 | atomic_set(&psIntfAdapter->uNumTcbUsed, 0); |
| 221 | atomic_set(&psIntfAdapter->uCurrTcb, 0); |
| 222 | |
| 223 | atomic_set(&psIntfAdapter->uNumRcbUsed, 0); |
| 224 | atomic_set(&psIntfAdapter->uCurrRcb, 0); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 225 | } |
| 226 | |
| 227 | VOID putUsbSuspend(struct work_struct *work) |
| 228 | { |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 229 | PS_INTERFACE_ADAPTER psIntfAdapter = NULL; |
| 230 | struct usb_interface *intf = NULL; |
| 231 | psIntfAdapter = container_of(work, S_INTERFACE_ADAPTER, usbSuspendWork); |
| 232 | intf = psIntfAdapter->interface; |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 233 | |
Kevin McKinney | 54ced00 | 2011-10-10 21:01:50 -0400 | [diff] [blame] | 234 | if (psIntfAdapter->bSuspended == FALSE) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 235 | usb_autopm_put_interface(intf); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 236 | } |
| 237 | |