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