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