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