1#include "headers.h"
2
3static 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
29int 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
70int 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
113int 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
122int 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
131int 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
185void 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
235void 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
248