xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_usb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /** @file moal_usb.c
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * @brief This file contains the interfaceing to USB bus
4*4882a593Smuzhiyun  * driver.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright 2008-2021 NXP
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This software file (the File) is distributed by NXP
10*4882a593Smuzhiyun  * under the terms of the GNU General Public License Version 2, June 1991
11*4882a593Smuzhiyun  * (the License).  You may use, redistribute and/or modify the File in
12*4882a593Smuzhiyun  * accordance with the terms and conditions of the License, a copy of which
13*4882a593Smuzhiyun  * is available by writing to the Free Software Foundation, Inc.,
14*4882a593Smuzhiyun  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15*4882a593Smuzhiyun  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18*4882a593Smuzhiyun  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19*4882a593Smuzhiyun  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
20*4882a593Smuzhiyun  * this warranty disclaimer.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /********************************************************
25*4882a593Smuzhiyun Change log:
26*4882a593Smuzhiyun     10/21/2008: initial version
27*4882a593Smuzhiyun ********************************************************/
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include "moal_main.h"
30*4882a593Smuzhiyun #include "moal_usb.h"
31*4882a593Smuzhiyun extern struct semaphore AddRemoveCardSem;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /********************************************************
34*4882a593Smuzhiyun 		Local Variables
35*4882a593Smuzhiyun ********************************************************/
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #if defined(USB8997) || defined(USB9098) || defined(USB9097) ||                \
38*4882a593Smuzhiyun 	defined(USB8978) || defined(USBNW62X)
39*4882a593Smuzhiyun /** Card-type detection frame response */
40*4882a593Smuzhiyun typedef struct {
41*4882a593Smuzhiyun 	/** 32-bit ACK+WINNER field */
42*4882a593Smuzhiyun 	t_u32 ack_winner;
43*4882a593Smuzhiyun 	/** 32-bit Sequence number */
44*4882a593Smuzhiyun 	t_u32 seq;
45*4882a593Smuzhiyun 	/** 32-bit extend */
46*4882a593Smuzhiyun 	t_u32 extend;
47*4882a593Smuzhiyun 	/** 32-bit chip-revision code */
48*4882a593Smuzhiyun 	t_u32 chip_rev;
49*4882a593Smuzhiyun 	/** 32-bit strap setting */
50*4882a593Smuzhiyun 	t_u32 strap;
51*4882a593Smuzhiyun } usb_ack_pkt;
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /** NXP USB device */
55*4882a593Smuzhiyun #define NXP_USB_DEVICE(vid, pid, name)                                         \
56*4882a593Smuzhiyun 	USB_DEVICE(vid, pid), .driver_info = (t_ptr)name
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /** Name of the USB driver */
59*4882a593Smuzhiyun static const char usbdriver_name[] = "usbxxx";
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /** This structure contains the device signature */
62*4882a593Smuzhiyun static struct usb_device_id woal_usb_table[] = {
63*4882a593Smuzhiyun /* Enter the device signature inside */
64*4882a593Smuzhiyun #ifdef USB8801
65*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8801_VID_1, USB8801_PID_1, "NXP WLAN USB Adapter")},
66*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8801_VID_1, USB8801_PID_2, "NXP WLAN USB Adapter")},
67*4882a593Smuzhiyun #endif
68*4882a593Smuzhiyun #ifdef USB8897
69*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_1, "NXP WLAN USB Adapter")},
70*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_2, "NXP WLAN USB Adapter")},
71*4882a593Smuzhiyun #endif
72*4882a593Smuzhiyun #ifdef USB8997
73*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_1, "NXP WLAN USB Adapter")},
74*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997V2_PID_1,
75*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
76*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_2, "NXP WLAN USB Adapter")},
77*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_3, "NXP WLAN USB Adapter")},
78*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_4, "NXP WLAN USB Adapter")},
79*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_5, "NXP WLAN USB Adapter")},
80*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_6, "NXP WLAN USB Adapter")},
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun #ifdef USB8978
83*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_1, "NXP WLAN USB Adapter")},
84*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_1_BT,
85*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
86*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2, "NXP WLAN USB Adapter")},
87*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2_BT,
88*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun #ifdef USB9098
91*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_1, "NXP WLAN USB Adapter")},
92*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_2, "NXP WLAN USB Adapter")},
93*4882a593Smuzhiyun #endif
94*4882a593Smuzhiyun #ifdef USB9097
95*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_1, "NXP WLAN USB Adapter")},
96*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_2, "NXP WLAN USB Adapter")},
97*4882a593Smuzhiyun #endif
98*4882a593Smuzhiyun #ifdef USBNW62X
99*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USBNW62X_VID_1, USBNW62X_PID_1,
100*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
101*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USBNW62X_VID_1, USBNW62X_PID_2,
102*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
103*4882a593Smuzhiyun #endif
104*4882a593Smuzhiyun 	/* Terminating entry */
105*4882a593Smuzhiyun 	{},
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /** This structure contains the device signature */
109*4882a593Smuzhiyun static struct usb_device_id woal_usb_table_skip_fwdnld[] = {
110*4882a593Smuzhiyun /* Enter the device signature inside */
111*4882a593Smuzhiyun #ifdef USB8801
112*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8801_VID_1, USB8801_PID_2, "NXP WLAN USB Adapter")},
113*4882a593Smuzhiyun #endif
114*4882a593Smuzhiyun #ifdef USB8897
115*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_2, "NXP WLAN USB Adapter")},
116*4882a593Smuzhiyun #endif
117*4882a593Smuzhiyun #ifdef USB8997
118*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_2, "NXP WLAN USB Adapter")},
119*4882a593Smuzhiyun #endif
120*4882a593Smuzhiyun #ifdef USB8978
121*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2, "NXP WLAN USB Adapter")},
122*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2_BT,
123*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
124*4882a593Smuzhiyun #endif
125*4882a593Smuzhiyun #ifdef USB9098
126*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_2, "NXP WLAN USB Adapter")},
127*4882a593Smuzhiyun #endif
128*4882a593Smuzhiyun #ifdef USB9097
129*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_2, "NXP WLAN USB Adapter")},
130*4882a593Smuzhiyun #endif
131*4882a593Smuzhiyun #ifdef USBNW62X
132*4882a593Smuzhiyun 	{NXP_USB_DEVICE(USBNW62X_VID_1, USBNW62X_PID_2,
133*4882a593Smuzhiyun 			"NXP WLAN USB Adapter")},
134*4882a593Smuzhiyun #endif
135*4882a593Smuzhiyun 	/* Terminating entry */
136*4882a593Smuzhiyun 	{},
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun static mlan_status woal_usb_submit_rx_urb(urb_context *ctx, int size);
140*4882a593Smuzhiyun static int woal_usb_probe(struct usb_interface *intf,
141*4882a593Smuzhiyun 			  const struct usb_device_id *id);
142*4882a593Smuzhiyun static void woal_usb_disconnect(struct usb_interface *intf);
143*4882a593Smuzhiyun static mlan_status woal_usb_write_data_sync(moal_handle *handle,
144*4882a593Smuzhiyun 					    mlan_buffer *pmbuf, t_u32 endpoint,
145*4882a593Smuzhiyun 					    t_u32 timeout);
146*4882a593Smuzhiyun static mlan_status woal_usb_read_data_sync(moal_handle *handle,
147*4882a593Smuzhiyun 					   mlan_buffer *pmbuf, t_u32 endpoint,
148*4882a593Smuzhiyun 					   t_u32 timeout);
149*4882a593Smuzhiyun #ifdef CONFIG_PM
150*4882a593Smuzhiyun static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message);
151*4882a593Smuzhiyun static int woal_usb_resume(struct usb_interface *intf);
152*4882a593Smuzhiyun #endif /* CONFIG_PM */
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun /** woal_usb_driver */
155*4882a593Smuzhiyun static struct usb_driver REFDATA woal_usb_driver = {
156*4882a593Smuzhiyun 	/* Driver name */
157*4882a593Smuzhiyun 	.name = usbdriver_name,
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	/* Probe function name */
160*4882a593Smuzhiyun 	.probe = woal_usb_probe,
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	/* Disconnect function name */
163*4882a593Smuzhiyun 	.disconnect = woal_usb_disconnect,
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* Device signature table */
166*4882a593Smuzhiyun 	.id_table = woal_usb_table,
167*4882a593Smuzhiyun #ifdef CONFIG_PM
168*4882a593Smuzhiyun 	/* Suspend function name */
169*4882a593Smuzhiyun 	.suspend = woal_usb_suspend,
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	/* Resume function name */
172*4882a593Smuzhiyun 	.resume = woal_usb_resume,
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	/* Reset resume function name */
175*4882a593Smuzhiyun 	.reset_resume = woal_usb_resume,
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
178*4882a593Smuzhiyun 	/* Driver supports autosuspend */
179*4882a593Smuzhiyun 	.supports_autosuspend = 1,
180*4882a593Smuzhiyun #endif
181*4882a593Smuzhiyun #endif /* CONFIG_PM */
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, woal_usb_table);
185*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, woal_usb_table_skip_fwdnld);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun /* moal interface ops */
188*4882a593Smuzhiyun static moal_if_ops usb_ops;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /********************************************************
191*4882a593Smuzhiyun 		Global Variables
192*4882a593Smuzhiyun ********************************************************/
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /********************************************************
195*4882a593Smuzhiyun 		Local Functions
196*4882a593Smuzhiyun ********************************************************/
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
199*4882a593Smuzhiyun /**
200*4882a593Smuzhiyun  *  @brief This function receive packet of the data/cmd/event packet
201*4882a593Smuzhiyun  *         and pass to MLAN
202*4882a593Smuzhiyun  *
203*4882a593Smuzhiyun  *  @param urb		Pointer to struct urb
204*4882a593Smuzhiyun  *  @param regs		Registers
205*4882a593Smuzhiyun  *
206*4882a593Smuzhiyun  *  @return 	   	N/A
207*4882a593Smuzhiyun  */
woal_usb_receive(struct urb * urb,struct pt_regs * regs)208*4882a593Smuzhiyun static void woal_usb_receive(struct urb *urb, struct pt_regs *regs)
209*4882a593Smuzhiyun #else
210*4882a593Smuzhiyun /**
211*4882a593Smuzhiyun  * @brief This function receive packet of the data/cmd/event packet
212*4882a593Smuzhiyun  *         and pass to MLAN
213*4882a593Smuzhiyun  *
214*4882a593Smuzhiyun  *  @param urb		Pointer to struct urb
215*4882a593Smuzhiyun  *
216*4882a593Smuzhiyun  *  @return 	   	N/A
217*4882a593Smuzhiyun  */
218*4882a593Smuzhiyun static void woal_usb_receive(struct urb *urb)
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	urb_context *context = NULL;
222*4882a593Smuzhiyun 	moal_handle *handle = NULL;
223*4882a593Smuzhiyun 	mlan_buffer *pmbuf = NULL;
224*4882a593Smuzhiyun 	struct usb_card_rec *cardp = NULL;
225*4882a593Smuzhiyun 	int recv_length;
226*4882a593Smuzhiyun 	int size;
227*4882a593Smuzhiyun 	mlan_status status = MLAN_STATUS_SUCCESS;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	ENTER();
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if (!urb || !urb->context) {
232*4882a593Smuzhiyun 		PRINTM(MERROR, "URB or URB context is not valid in USB Rx\n");
233*4882a593Smuzhiyun 		LEAVE();
234*4882a593Smuzhiyun 		return;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 	context = (urb_context *)urb->context;
237*4882a593Smuzhiyun 	handle = context->handle;
238*4882a593Smuzhiyun 	pmbuf = context->pmbuf;
239*4882a593Smuzhiyun 	recv_length = urb->actual_length;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (!handle || !handle->card || !pmbuf) {
242*4882a593Smuzhiyun 		PRINTM(MERROR,
243*4882a593Smuzhiyun 		       "moal handle, card structure or mlan_buffer is not valid in USB Rx\n");
244*4882a593Smuzhiyun 		LEAVE();
245*4882a593Smuzhiyun 		return;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	cardp = (struct usb_card_rec *)handle->card;
248*4882a593Smuzhiyun 	if (cardp->rx_cmd_ep == context->ep)
249*4882a593Smuzhiyun 		atomic_dec(&cardp->rx_cmd_urb_pending);
250*4882a593Smuzhiyun 	else
251*4882a593Smuzhiyun 		atomic_dec(&cardp->rx_data_urb_pending);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (recv_length) {
254*4882a593Smuzhiyun 		if (urb->status || (handle->surprise_removed == MTRUE)) {
255*4882a593Smuzhiyun 			if (handle->surprise_removed || handle->is_suspended) {
256*4882a593Smuzhiyun 				woal_free_mlan_buffer(handle, pmbuf);
257*4882a593Smuzhiyun 				context->pmbuf = NULL;
258*4882a593Smuzhiyun 				goto rx_exit;
259*4882a593Smuzhiyun 			} else {
260*4882a593Smuzhiyun 				PRINTM(MERROR,
261*4882a593Smuzhiyun 				       "EP %d Rx URB status failure: %d\n",
262*4882a593Smuzhiyun 				       context->ep, urb->status);
263*4882a593Smuzhiyun 				/* Do not free mlan_buffer in case of command ep
264*4882a593Smuzhiyun 				 */
265*4882a593Smuzhiyun 				if (cardp->rx_cmd_ep != context->ep)
266*4882a593Smuzhiyun 					woal_free_mlan_buffer(handle, pmbuf);
267*4882a593Smuzhiyun 				goto setup_for_next;
268*4882a593Smuzhiyun 			}
269*4882a593Smuzhiyun 		}
270*4882a593Smuzhiyun 		pmbuf->data_len = recv_length;
271*4882a593Smuzhiyun 		pmbuf->flags |= MLAN_BUF_FLAG_RX_DEAGGR;
272*4882a593Smuzhiyun 		/* Send packet to MLAN */
273*4882a593Smuzhiyun 		atomic_inc(&handle->rx_pending);
274*4882a593Smuzhiyun 		status = mlan_recv(handle->pmlan_adapter, pmbuf, context->ep);
275*4882a593Smuzhiyun 		PRINTM(MINFO, "Receive length = 0x%x, status=%d\n", recv_length,
276*4882a593Smuzhiyun 		       status);
277*4882a593Smuzhiyun 		if (status == MLAN_STATUS_PENDING) {
278*4882a593Smuzhiyun 			queue_work(handle->workqueue, &handle->main_work);
279*4882a593Smuzhiyun 			/* urb for data_ep is re-submitted now, unless we reach
280*4882a593Smuzhiyun 			 * USB_HIGH_RX_PENDING */
281*4882a593Smuzhiyun 			/* urb for cmd_ep will be re-submitted in callback
282*4882a593Smuzhiyun 			 * moal_recv_complete */
283*4882a593Smuzhiyun 			if (cardp->rx_cmd_ep == context->ep)
284*4882a593Smuzhiyun 				goto rx_exit;
285*4882a593Smuzhiyun 			else if (atomic_read(&handle->rx_pending) >=
286*4882a593Smuzhiyun 				 USB_HIGH_RX_PENDING) {
287*4882a593Smuzhiyun 				context->pmbuf = NULL;
288*4882a593Smuzhiyun 				goto rx_exit;
289*4882a593Smuzhiyun 			}
290*4882a593Smuzhiyun 		} else {
291*4882a593Smuzhiyun 			atomic_dec(&handle->rx_pending);
292*4882a593Smuzhiyun 			if (status == MLAN_STATUS_FAILURE) {
293*4882a593Smuzhiyun 				PRINTM(MERROR,
294*4882a593Smuzhiyun 				       "MLAN fail to process the receive data\n");
295*4882a593Smuzhiyun 			} else if ((status == MLAN_STATUS_SUCCESS) &&
296*4882a593Smuzhiyun 				   (pmbuf->flags &
297*4882a593Smuzhiyun 				    MLAN_BUF_FLAG_SLEEPCFM_RESP)) {
298*4882a593Smuzhiyun 				pmbuf->flags &= ~MLAN_BUF_FLAG_SLEEPCFM_RESP;
299*4882a593Smuzhiyun 				queue_work(handle->workqueue,
300*4882a593Smuzhiyun 					   &handle->main_work);
301*4882a593Smuzhiyun 			}
302*4882a593Smuzhiyun 			/* Do not free mlan_buffer in case of command ep */
303*4882a593Smuzhiyun 			if (cardp->rx_cmd_ep != context->ep)
304*4882a593Smuzhiyun 				woal_free_mlan_buffer(handle, pmbuf);
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 	} else if (urb->status) {
307*4882a593Smuzhiyun 		if (!((cardp->rx_data_ep == context->ep) &&
308*4882a593Smuzhiyun 		      (cardp->resubmit_urbs == 1))) {
309*4882a593Smuzhiyun 			if (!handle->is_suspended) {
310*4882a593Smuzhiyun 				PRINTM(MMSG, "Card is removed: %d\n",
311*4882a593Smuzhiyun 				       urb->status);
312*4882a593Smuzhiyun 				handle->surprise_removed = MTRUE;
313*4882a593Smuzhiyun 			}
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 		woal_free_mlan_buffer(handle, pmbuf);
316*4882a593Smuzhiyun 		context->pmbuf = NULL;
317*4882a593Smuzhiyun 		goto rx_exit;
318*4882a593Smuzhiyun 	} else {
319*4882a593Smuzhiyun 		/* Do not free mlan_buffer in case of command ep */
320*4882a593Smuzhiyun 		if (cardp->rx_cmd_ep != context->ep)
321*4882a593Smuzhiyun 			woal_free_mlan_buffer(handle, pmbuf);
322*4882a593Smuzhiyun 		goto setup_for_next;
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun setup_for_next:
326*4882a593Smuzhiyun 	if (cardp->rx_cmd_ep == context->ep) {
327*4882a593Smuzhiyun 		size = MLAN_RX_CMD_BUF_SIZE;
328*4882a593Smuzhiyun 	} else {
329*4882a593Smuzhiyun 		if (cardp->rx_deaggr_ctrl.enable) {
330*4882a593Smuzhiyun 			size = cardp->rx_deaggr_ctrl.aggr_max;
331*4882a593Smuzhiyun 			if (cardp->rx_deaggr_ctrl.aggr_mode ==
332*4882a593Smuzhiyun 			    MLAN_USB_AGGR_MODE_NUM) {
333*4882a593Smuzhiyun 				size *= MAX(MLAN_USB_MAX_PKT_SIZE,
334*4882a593Smuzhiyun 					    cardp->rx_deaggr_ctrl.aggr_align);
335*4882a593Smuzhiyun 				size = MAX(size, MLAN_RX_DATA_BUF_SIZE);
336*4882a593Smuzhiyun 			}
337*4882a593Smuzhiyun 		} else
338*4882a593Smuzhiyun 			size = MLAN_RX_DATA_BUF_SIZE;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 	woal_usb_submit_rx_urb(context, size);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun rx_exit:
343*4882a593Smuzhiyun 	LEAVE();
344*4882a593Smuzhiyun 	return;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
348*4882a593Smuzhiyun /**
349*4882a593Smuzhiyun  *  @brief  Call back function to handle the status of the Tx data URB
350*4882a593Smuzhiyun  *
351*4882a593Smuzhiyun  *  @param urb      Pointer to urb structure
352*4882a593Smuzhiyun  *  @param regs     Registers
353*4882a593Smuzhiyun  *
354*4882a593Smuzhiyun  *  @return         N/A
355*4882a593Smuzhiyun  */
woal_usb_tx_complete(struct urb * urb,struct pt_regs * regs)356*4882a593Smuzhiyun static void woal_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
357*4882a593Smuzhiyun #else
358*4882a593Smuzhiyun /**
359*4882a593Smuzhiyun  * @brief  Call back function to handle the status of the Tx data URB
360*4882a593Smuzhiyun  *
361*4882a593Smuzhiyun  * @param urb      Pointer to urb structure
362*4882a593Smuzhiyun  *
363*4882a593Smuzhiyun  * @return         N/A
364*4882a593Smuzhiyun  */
365*4882a593Smuzhiyun static void woal_usb_tx_complete(struct urb *urb)
366*4882a593Smuzhiyun #endif
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	urb_context *context = NULL;
369*4882a593Smuzhiyun 	moal_handle *handle = NULL;
370*4882a593Smuzhiyun 	struct usb_card_rec *cardp = NULL;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	ENTER();
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if (!urb || !urb->context) {
375*4882a593Smuzhiyun 		PRINTM(MERROR,
376*4882a593Smuzhiyun 		       "URB or URB context is not valid in USB Tx complete\n");
377*4882a593Smuzhiyun 		LEAVE();
378*4882a593Smuzhiyun 		return;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 	context = (urb_context *)urb->context;
381*4882a593Smuzhiyun 	handle = context->handle;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (!handle || !handle->card || !context->pmbuf) {
384*4882a593Smuzhiyun 		PRINTM(MERROR,
385*4882a593Smuzhiyun 		       "moal handle, card structure or mlan_buffer is not valid in USB Tx complete\n");
386*4882a593Smuzhiyun 		LEAVE();
387*4882a593Smuzhiyun 		return;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 	cardp = handle->card;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/* Handle the transmission complete validations */
392*4882a593Smuzhiyun 	if (urb->status) {
393*4882a593Smuzhiyun 		PRINTM(MERROR, "EP %d Tx URB status failure: %d\n", context->ep,
394*4882a593Smuzhiyun 		       urb->status);
395*4882a593Smuzhiyun 		mlan_write_data_async_complete(handle->pmlan_adapter,
396*4882a593Smuzhiyun 					       context->pmbuf, context->ep,
397*4882a593Smuzhiyun 					       MLAN_STATUS_FAILURE);
398*4882a593Smuzhiyun 	} else {
399*4882a593Smuzhiyun 		mlan_write_data_async_complete(handle->pmlan_adapter,
400*4882a593Smuzhiyun 					       context->pmbuf, context->ep,
401*4882a593Smuzhiyun 					       MLAN_STATUS_SUCCESS);
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/* Decrease pending URB counter */
405*4882a593Smuzhiyun 	if (context->ep == cardp->tx_cmd_ep)
406*4882a593Smuzhiyun 		atomic_dec(&cardp->tx_cmd_urb_pending);
407*4882a593Smuzhiyun 	else if (context->ep == cardp->tx_data_ep)
408*4882a593Smuzhiyun 		atomic_dec(&cardp->tx_data_urb_pending);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	queue_work(handle->workqueue, &handle->main_work);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	LEAVE();
413*4882a593Smuzhiyun 	return;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /**
417*4882a593Smuzhiyun  *  @brief This function sets up the data to receive
418*4882a593Smuzhiyun  *
419*4882a593Smuzhiyun  *  @param ctx		Pointer to urb_context structure
420*4882a593Smuzhiyun  *  @param size	        Skb size
421*4882a593Smuzhiyun  *
422*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
423*4882a593Smuzhiyun  */
woal_usb_submit_rx_urb(urb_context * ctx,int size)424*4882a593Smuzhiyun static mlan_status woal_usb_submit_rx_urb(urb_context *ctx, int size)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	moal_handle *handle = ctx->handle;
427*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
428*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_FAILURE;
429*4882a593Smuzhiyun 	t_u8 *data = NULL;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	ENTER();
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	if (handle->surprise_removed || handle->is_suspended) {
434*4882a593Smuzhiyun 		if ((cardp->rx_cmd_ep == ctx->ep) && ctx->pmbuf) {
435*4882a593Smuzhiyun 			woal_free_mlan_buffer(handle, ctx->pmbuf);
436*4882a593Smuzhiyun 			ctx->pmbuf = NULL;
437*4882a593Smuzhiyun 		}
438*4882a593Smuzhiyun 		PRINTM(MERROR,
439*4882a593Smuzhiyun 		       "Card removed/suspended, EP %d Rx URB submit skipped\n",
440*4882a593Smuzhiyun 		       ctx->ep);
441*4882a593Smuzhiyun 		goto rx_ret;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	if (cardp->rx_cmd_ep != ctx->ep) {
445*4882a593Smuzhiyun 		ctx->pmbuf = woal_alloc_mlan_buffer(handle, size);
446*4882a593Smuzhiyun 		if (!ctx->pmbuf) {
447*4882a593Smuzhiyun 			PRINTM(MERROR,
448*4882a593Smuzhiyun 			       "Fail to submit Rx URB due to no memory/skb\n");
449*4882a593Smuzhiyun 			goto rx_ret;
450*4882a593Smuzhiyun 		}
451*4882a593Smuzhiyun 		ctx->pmbuf->data_offset = MLAN_RX_HEADER_LEN;
452*4882a593Smuzhiyun 		data = ctx->pmbuf->pbuf + ctx->pmbuf->data_offset;
453*4882a593Smuzhiyun 	} else {
454*4882a593Smuzhiyun 		ctx->pmbuf->data_offset = 0;
455*4882a593Smuzhiyun 		data = ctx->pmbuf->pbuf + ctx->pmbuf->data_offset;
456*4882a593Smuzhiyun 	}
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	if (cardp->rx_cmd_ep == ctx->ep &&
459*4882a593Smuzhiyun 	    cardp->rx_cmd_ep_type == USB_ENDPOINT_XFER_INT)
460*4882a593Smuzhiyun 		usb_fill_int_urb(ctx->urb, cardp->udev,
461*4882a593Smuzhiyun 				 usb_rcvintpipe(cardp->udev, ctx->ep), data,
462*4882a593Smuzhiyun 				 size - ctx->pmbuf->data_offset,
463*4882a593Smuzhiyun 				 woal_usb_receive, (void *)ctx,
464*4882a593Smuzhiyun 				 cardp->rx_cmd_interval);
465*4882a593Smuzhiyun 	else
466*4882a593Smuzhiyun 		usb_fill_bulk_urb(ctx->urb, cardp->udev,
467*4882a593Smuzhiyun 				  usb_rcvbulkpipe(cardp->udev, ctx->ep), data,
468*4882a593Smuzhiyun 				  size - ctx->pmbuf->data_offset,
469*4882a593Smuzhiyun 				  woal_usb_receive, (void *)ctx);
470*4882a593Smuzhiyun 	if (cardp->rx_cmd_ep == ctx->ep)
471*4882a593Smuzhiyun 		atomic_inc(&cardp->rx_cmd_urb_pending);
472*4882a593Smuzhiyun 	else
473*4882a593Smuzhiyun 		atomic_inc(&cardp->rx_data_urb_pending);
474*4882a593Smuzhiyun 	if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) {
475*4882a593Smuzhiyun 		/* Submit URB failure */
476*4882a593Smuzhiyun 		PRINTM(MERROR, "Submit EP %d Rx URB failed: %d\n", ctx->ep,
477*4882a593Smuzhiyun 		       ret);
478*4882a593Smuzhiyun 		woal_free_mlan_buffer(handle, ctx->pmbuf);
479*4882a593Smuzhiyun 		if (cardp->rx_cmd_ep == ctx->ep)
480*4882a593Smuzhiyun 			atomic_dec(&cardp->rx_cmd_urb_pending);
481*4882a593Smuzhiyun 		else
482*4882a593Smuzhiyun 			atomic_dec(&cardp->rx_data_urb_pending);
483*4882a593Smuzhiyun 		ctx->pmbuf = NULL;
484*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
485*4882a593Smuzhiyun 	} else {
486*4882a593Smuzhiyun 		ret = MLAN_STATUS_SUCCESS;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun rx_ret:
489*4882a593Smuzhiyun 	LEAVE();
490*4882a593Smuzhiyun 	return ret;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun /********************************************************
494*4882a593Smuzhiyun 		Global Functions
495*4882a593Smuzhiyun ********************************************************/
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun #if defined(USB8997) || defined(USB9098) || defined(USB9097) ||                \
498*4882a593Smuzhiyun 	defined(USB8978) || defined(USBNW62X)
499*4882a593Smuzhiyun /**
500*4882a593Smuzhiyun  *  @brief  Check chip revision
501*4882a593Smuzhiyun  *
502*4882a593Smuzhiyun  *  @param handle        A pointer to moal_handle structure
503*4882a593Smuzhiyun  *  @param usb_chip_rev  A pointer to usb_chip_rev variable
504*4882a593Smuzhiyun  *  @param usb_strap     A pointer to usb_strap
505*4882a593Smuzhiyun  *
506*4882a593Smuzhiyun  *  @return 	   	 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
507*4882a593Smuzhiyun  */
woal_check_chip_revision(moal_handle * handle,t_u32 * usb_chip_rev,t_u32 * usb_strap)508*4882a593Smuzhiyun static mlan_status woal_check_chip_revision(moal_handle *handle,
509*4882a593Smuzhiyun 					    t_u32 *usb_chip_rev,
510*4882a593Smuzhiyun 					    t_u32 *usb_strap)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
513*4882a593Smuzhiyun 	mlan_buffer mbuf;
514*4882a593Smuzhiyun 	t_u8 *tx_buff = NULL;
515*4882a593Smuzhiyun 	t_u8 *recv_buff = NULL;
516*4882a593Smuzhiyun 	usb_ack_pkt ack_pkt;
517*4882a593Smuzhiyun 	t_u32 extend_ver;
518*4882a593Smuzhiyun 	t_u8 tx_size = CHIP_REV_TX_BUF_SIZE;
519*4882a593Smuzhiyun 	struct usb_card_rec *cardp = handle->card;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	ENTER();
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	/* Allocate memory for transmit */
524*4882a593Smuzhiyun 	tx_buff = kzalloc(tx_size, GFP_ATOMIC | GFP_DMA);
525*4882a593Smuzhiyun 	if (tx_buff == NULL) {
526*4882a593Smuzhiyun 		PRINTM(MERROR,
527*4882a593Smuzhiyun 		       "Could not allocate buffer for chip revision check frame transmission\n");
528*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
529*4882a593Smuzhiyun 		goto cleanup;
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	/* Allocate memory for receive */
533*4882a593Smuzhiyun 	recv_buff = kzalloc(CHIP_REV_RX_BUF_SIZE, GFP_ATOMIC | GFP_DMA);
534*4882a593Smuzhiyun 	if (recv_buff == NULL) {
535*4882a593Smuzhiyun 		PRINTM(MERROR,
536*4882a593Smuzhiyun 		       "Could not allocate buffer for chip revision check frame response\n");
537*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
538*4882a593Smuzhiyun 		goto cleanup;
539*4882a593Smuzhiyun 	}
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	/* The struct is initialised to all zero */
542*4882a593Smuzhiyun 	memset(&ack_pkt, 0, sizeof(usb_ack_pkt));
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* Send pseudo data to check winner status first */
545*4882a593Smuzhiyun 	memset(&mbuf, 0, sizeof(mlan_buffer));
546*4882a593Smuzhiyun 	mbuf.pbuf = (t_u8 *)tx_buff;
547*4882a593Smuzhiyun 	mbuf.data_len = tx_size;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	/* Send the chip revision check frame */
550*4882a593Smuzhiyun 	ret = woal_usb_write_data_sync(handle, &mbuf, cardp->tx_cmd_ep,
551*4882a593Smuzhiyun 				       MLAN_USB_BULK_MSG_TIMEOUT);
552*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
553*4882a593Smuzhiyun 		PRINTM(MERROR,
554*4882a593Smuzhiyun 		       "Chip revision check frame dnld: write_data failed, ret %d\n",
555*4882a593Smuzhiyun 		       ret);
556*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
557*4882a593Smuzhiyun 		goto cleanup;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	memset(&mbuf, 0, sizeof(mlan_buffer));
561*4882a593Smuzhiyun 	mbuf.pbuf = (t_u8 *)recv_buff;
562*4882a593Smuzhiyun 	mbuf.data_len = CHIP_REV_RX_BUF_SIZE;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	/* Receive the chip revision check frame response */
565*4882a593Smuzhiyun 	ret = woal_usb_read_data_sync(handle, &mbuf, cardp->rx_cmd_ep,
566*4882a593Smuzhiyun 				      MLAN_USB_BULK_MSG_TIMEOUT);
567*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
568*4882a593Smuzhiyun 		PRINTM(MERROR,
569*4882a593Smuzhiyun 		       "Chip revision check frame response: read_data failed, ret %d\n",
570*4882a593Smuzhiyun 		       ret);
571*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
572*4882a593Smuzhiyun 		goto cleanup;
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 	moal_memcpy_ext(handle, &ack_pkt, recv_buff, sizeof(usb_ack_pkt),
575*4882a593Smuzhiyun 			sizeof(ack_pkt));
576*4882a593Smuzhiyun 	ack_pkt.ack_winner = woal_le32_to_cpu(ack_pkt.ack_winner);
577*4882a593Smuzhiyun 	ack_pkt.seq = woal_le32_to_cpu(ack_pkt.seq);
578*4882a593Smuzhiyun 	ack_pkt.extend = woal_le32_to_cpu(ack_pkt.extend);
579*4882a593Smuzhiyun 	ack_pkt.chip_rev = woal_le32_to_cpu(ack_pkt.chip_rev);
580*4882a593Smuzhiyun 	ack_pkt.strap = woal_le32_to_cpu(ack_pkt.strap);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	if ((ack_pkt.extend & 0xffff0000) == EXTEND_HDR) {
583*4882a593Smuzhiyun 		extend_ver = ack_pkt.extend & 0x0000ffff;
584*4882a593Smuzhiyun 		*usb_chip_rev = ack_pkt.chip_rev & 0x000000ff;
585*4882a593Smuzhiyun 		if (extend_ver >= EXTEND_V2) {
586*4882a593Smuzhiyun 			PRINTM(MINFO, "chip_rev=0x%x, strap=0x%x\n",
587*4882a593Smuzhiyun 			       *usb_chip_rev, ack_pkt.strap);
588*4882a593Smuzhiyun 			*usb_strap = ack_pkt.strap & 0x7;
589*4882a593Smuzhiyun 		} else
590*4882a593Smuzhiyun 			PRINTM(MINFO, "chip_rev=0x%x\n", *usb_chip_rev);
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun cleanup:
593*4882a593Smuzhiyun 	kfree(recv_buff);
594*4882a593Smuzhiyun 	kfree(tx_buff);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	LEAVE();
597*4882a593Smuzhiyun 	return ret;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun #endif
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun /**
602*4882a593Smuzhiyun  *  @brief This function unlink urb
603*4882a593Smuzhiyun  *
604*4882a593Smuzhiyun  *  @param handle A pointer to moal_handle structure
605*4882a593Smuzhiyun  *  @return 	  N/A
606*4882a593Smuzhiyun  */
woal_usb_unlink_urb(void * card_desc)607*4882a593Smuzhiyun static void woal_usb_unlink_urb(void *card_desc)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)card_desc;
610*4882a593Smuzhiyun 	int i;
611*4882a593Smuzhiyun 	ENTER();
612*4882a593Smuzhiyun 	if (cardp) {
613*4882a593Smuzhiyun 		/* Unlink Rx cmd URB */
614*4882a593Smuzhiyun 		if (atomic_read(&cardp->rx_cmd_urb_pending) &&
615*4882a593Smuzhiyun 		    cardp->rx_cmd.urb) {
616*4882a593Smuzhiyun 			usb_kill_urb(cardp->rx_cmd.urb);
617*4882a593Smuzhiyun 		}
618*4882a593Smuzhiyun 		/* Unlink Rx data URBs */
619*4882a593Smuzhiyun 		if (atomic_read(&cardp->rx_data_urb_pending)) {
620*4882a593Smuzhiyun 			for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
621*4882a593Smuzhiyun 				if (cardp->rx_data_list[i].urb)
622*4882a593Smuzhiyun 					usb_kill_urb(
623*4882a593Smuzhiyun 						cardp->rx_data_list[i].urb);
624*4882a593Smuzhiyun 			}
625*4882a593Smuzhiyun 		}
626*4882a593Smuzhiyun 		/* Unlink Tx cmd URB */
627*4882a593Smuzhiyun 		if (atomic_read(&cardp->tx_cmd_urb_pending) &&
628*4882a593Smuzhiyun 		    cardp->tx_cmd.urb) {
629*4882a593Smuzhiyun 			usb_kill_urb(cardp->tx_cmd.urb);
630*4882a593Smuzhiyun 		}
631*4882a593Smuzhiyun 		/* Unlink Tx data URBs */
632*4882a593Smuzhiyun 		if (atomic_read(&cardp->tx_data_urb_pending)) {
633*4882a593Smuzhiyun 			for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
634*4882a593Smuzhiyun 				if (cardp->tx_data_list[i].urb) {
635*4882a593Smuzhiyun 					usb_kill_urb(
636*4882a593Smuzhiyun 						cardp->tx_data_list[i].urb);
637*4882a593Smuzhiyun 				}
638*4882a593Smuzhiyun 			}
639*4882a593Smuzhiyun 		}
640*4882a593Smuzhiyun 	}
641*4882a593Smuzhiyun 	LEAVE();
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun /**
645*4882a593Smuzhiyun  *  @brief  Free Tx/Rx urb, skb and Rx buffer
646*4882a593Smuzhiyun  *
647*4882a593Smuzhiyun  *  @param cardp	Pointer usb_card_rec
648*4882a593Smuzhiyun  *
649*4882a593Smuzhiyun  *  @return 	   	N/A
650*4882a593Smuzhiyun  */
woal_usb_free(struct usb_card_rec * cardp)651*4882a593Smuzhiyun void woal_usb_free(struct usb_card_rec *cardp)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun 	int i;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	ENTER();
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	woal_usb_unlink_urb(cardp);
658*4882a593Smuzhiyun 	/* Free Rx data URBs */
659*4882a593Smuzhiyun 	for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
660*4882a593Smuzhiyun 		if (cardp->rx_data_list[i].urb) {
661*4882a593Smuzhiyun 			usb_free_urb(cardp->rx_data_list[i].urb);
662*4882a593Smuzhiyun 			cardp->rx_data_list[i].urb = NULL;
663*4882a593Smuzhiyun 		}
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 	/* Free Rx cmd URB */
666*4882a593Smuzhiyun 	if (cardp->rx_cmd.urb) {
667*4882a593Smuzhiyun 		usb_free_urb(cardp->rx_cmd.urb);
668*4882a593Smuzhiyun 		cardp->rx_cmd.urb = NULL;
669*4882a593Smuzhiyun 	}
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	/* Free Tx data URBs */
672*4882a593Smuzhiyun 	for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
673*4882a593Smuzhiyun 		if (cardp->tx_data_list[i].urb) {
674*4882a593Smuzhiyun 			usb_free_urb(cardp->tx_data_list[i].urb);
675*4882a593Smuzhiyun 			cardp->tx_data_list[i].urb = NULL;
676*4882a593Smuzhiyun 		}
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 	/* Free Tx cmd URB */
679*4882a593Smuzhiyun 	if (cardp->tx_cmd.urb) {
680*4882a593Smuzhiyun 		usb_free_urb(cardp->tx_cmd.urb);
681*4882a593Smuzhiyun 		cardp->tx_cmd.urb = NULL;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	LEAVE();
685*4882a593Smuzhiyun 	return;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun 
woal_update_card_type(t_void * card)688*4882a593Smuzhiyun static t_u16 woal_update_card_type(t_void *card)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun 	struct usb_card_rec *cardp_usb = (struct usb_card_rec *)card;
691*4882a593Smuzhiyun 	t_u16 card_type = 0;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	/* Update card type */
694*4882a593Smuzhiyun #ifdef USB8801
695*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
696*4882a593Smuzhiyun 		    (__force __le16)USB8801_PID_1 ||
697*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
698*4882a593Smuzhiyun 		    (__force __le16)USB8801_PID_2) {
699*4882a593Smuzhiyun 		card_type = CARD_TYPE_USB8801;
700*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, CARD_USB8801,
701*4882a593Smuzhiyun 				strlen(CARD_USB8801), strlen(driver_version));
702*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
703*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
704*4882a593Smuzhiyun 					strlen(KERN_VERSION),
705*4882a593Smuzhiyun 				V14, strlen(V14),
706*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
707*4882a593Smuzhiyun 					strlen(KERN_VERSION));
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun #endif
710*4882a593Smuzhiyun #ifdef USB8897
711*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
712*4882a593Smuzhiyun 		    (__force __le16)USB8897_PID_1 ||
713*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
714*4882a593Smuzhiyun 		    (__force __le16)USB8897_PID_2) {
715*4882a593Smuzhiyun 		card_type = CARD_TYPE_USB8897;
716*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, CARD_USB8897,
717*4882a593Smuzhiyun 				strlen(CARD_USB8897), strlen(driver_version));
718*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
719*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
720*4882a593Smuzhiyun 					strlen(KERN_VERSION),
721*4882a593Smuzhiyun 				V15, strlen(V15),
722*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
723*4882a593Smuzhiyun 					strlen(KERN_VERSION));
724*4882a593Smuzhiyun 	}
725*4882a593Smuzhiyun #endif
726*4882a593Smuzhiyun #ifdef USB8997
727*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
728*4882a593Smuzhiyun 		    (__force __le16)USB8997_PID_1 ||
729*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
730*4882a593Smuzhiyun 		    (__force __le16)USB8997_PID_2 ||
731*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
732*4882a593Smuzhiyun 		    (__force __le16)USB8997_PID_3 ||
733*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
734*4882a593Smuzhiyun 		    (__force __le16)USB8997_PID_4 ||
735*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
736*4882a593Smuzhiyun 		    (__force __le16)USB8997_PID_5 ||
737*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
738*4882a593Smuzhiyun 		    (__force __le16)USB8997_PID_6 ||
739*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
740*4882a593Smuzhiyun 		    (__force __le16)USB8997V2_PID_1) {
741*4882a593Smuzhiyun 		card_type = CARD_TYPE_USB8997;
742*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, CARD_USB8997,
743*4882a593Smuzhiyun 				strlen(CARD_USB8997), strlen(driver_version));
744*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
745*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
746*4882a593Smuzhiyun 					strlen(KERN_VERSION),
747*4882a593Smuzhiyun 				V16, strlen(V16),
748*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
749*4882a593Smuzhiyun 					strlen(KERN_VERSION));
750*4882a593Smuzhiyun 	}
751*4882a593Smuzhiyun #endif
752*4882a593Smuzhiyun #ifdef USB8978
753*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
754*4882a593Smuzhiyun 		    (__force __le16)USB8978_PID_1 ||
755*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
756*4882a593Smuzhiyun 		    (__force __le16)USB8978_PID_2) {
757*4882a593Smuzhiyun 		card_type = CARD_TYPE_USB8978;
758*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, "USBIW416",
759*4882a593Smuzhiyun 				strlen("USBIW416"), strlen(driver_version));
760*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
761*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
762*4882a593Smuzhiyun 					strlen(KERN_VERSION),
763*4882a593Smuzhiyun 				V16, strlen(V16),
764*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
765*4882a593Smuzhiyun 					strlen(KERN_VERSION));
766*4882a593Smuzhiyun 	}
767*4882a593Smuzhiyun #endif
768*4882a593Smuzhiyun #ifdef USB9098
769*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
770*4882a593Smuzhiyun 		    (__force __le16)USB9098_PID_1 ||
771*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
772*4882a593Smuzhiyun 		    (__force __le16)USB9098_PID_2) {
773*4882a593Smuzhiyun 		card_type = CARD_TYPE_USB9098;
774*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, CARD_USB9098,
775*4882a593Smuzhiyun 				strlen(CARD_USB9098), strlen(driver_version));
776*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
777*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
778*4882a593Smuzhiyun 					strlen(KERN_VERSION),
779*4882a593Smuzhiyun 				V17, strlen(V17),
780*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
781*4882a593Smuzhiyun 					strlen(KERN_VERSION));
782*4882a593Smuzhiyun 	}
783*4882a593Smuzhiyun #endif
784*4882a593Smuzhiyun #ifdef USB9097
785*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
786*4882a593Smuzhiyun 		    (__force __le16)USB9097_PID_1 ||
787*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
788*4882a593Smuzhiyun 		    (__force __le16)USB9097_PID_2) {
789*4882a593Smuzhiyun 		card_type = CARD_TYPE_USB9097;
790*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, CARD_USB9097,
791*4882a593Smuzhiyun 				strlen(CARD_USB9097), strlen(driver_version));
792*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
793*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
794*4882a593Smuzhiyun 					strlen(KERN_VERSION),
795*4882a593Smuzhiyun 				V17, strlen(V17),
796*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
797*4882a593Smuzhiyun 					strlen(KERN_VERSION));
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun #endif
800*4882a593Smuzhiyun #ifdef USBNW62X
801*4882a593Smuzhiyun 	if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
802*4882a593Smuzhiyun 		    (__force __le16)USBNW62X_PID_1 ||
803*4882a593Smuzhiyun 	    woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
804*4882a593Smuzhiyun 		    (__force __le16)USBNW62X_PID_2) {
805*4882a593Smuzhiyun 		card_type = CARD_TYPE_USBNW62X;
806*4882a593Smuzhiyun 		moal_memcpy_ext(NULL, driver_version, CARD_USBNW62X,
807*4882a593Smuzhiyun 				strlen(CARD_USBNW62X), strlen(driver_version));
808*4882a593Smuzhiyun 		moal_memcpy_ext(NULL,
809*4882a593Smuzhiyun 				driver_version + strlen(INTF_CARDTYPE) +
810*4882a593Smuzhiyun 					strlen(KERN_VERSION),
811*4882a593Smuzhiyun 				V17, strlen(V17),
812*4882a593Smuzhiyun 				strlen(driver_version) - strlen(INTF_CARDTYPE) -
813*4882a593Smuzhiyun 					strlen(KERN_VERSION));
814*4882a593Smuzhiyun 	}
815*4882a593Smuzhiyun #endif
816*4882a593Smuzhiyun 	return card_type;
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun /**
820*4882a593Smuzhiyun  *  @brief Sets the configuration values
821*4882a593Smuzhiyun  *
822*4882a593Smuzhiyun  *  @param intf		Pointer to usb_interface
823*4882a593Smuzhiyun  *  @param id		Pointer to usb_device_id
824*4882a593Smuzhiyun  *
825*4882a593Smuzhiyun  *  @return 	   	Address of variable usb_cardp, error code otherwise
826*4882a593Smuzhiyun  */
woal_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)827*4882a593Smuzhiyun static int woal_usb_probe(struct usb_interface *intf,
828*4882a593Smuzhiyun 			  const struct usb_device_id *id)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun 	struct usb_device *udev;
831*4882a593Smuzhiyun 	struct usb_host_interface *iface_desc;
832*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *endpoint;
833*4882a593Smuzhiyun 	int i;
834*4882a593Smuzhiyun 	struct usb_card_rec *usb_cardp = NULL;
835*4882a593Smuzhiyun 	t_u16 card_type = 0;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	ENTER();
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
840*4882a593Smuzhiyun 	PRINTM(MMSG,
841*4882a593Smuzhiyun 	       "USB probe: idVendor=%x idProduct=%x bInterfaceNumber=%d\n",
842*4882a593Smuzhiyun 	       id->idVendor, id->idProduct, id->bInterfaceNumber);
843*4882a593Smuzhiyun #endif
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	udev = interface_to_usbdev(intf);
846*4882a593Smuzhiyun 	usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
847*4882a593Smuzhiyun 	if (!usb_cardp) {
848*4882a593Smuzhiyun 		LEAVE();
849*4882a593Smuzhiyun 		return -ENOMEM;
850*4882a593Smuzhiyun 	}
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	/* Check probe is for our device */
853*4882a593Smuzhiyun 	for (i = 0; woal_usb_table[i].idVendor; i++) {
854*4882a593Smuzhiyun 		if (woal_cpu_to_le16(udev->descriptor.idVendor) ==
855*4882a593Smuzhiyun 			    (__force __le16)woal_usb_table[i].idVendor &&
856*4882a593Smuzhiyun 		    woal_cpu_to_le16(udev->descriptor.idProduct) ==
857*4882a593Smuzhiyun 			    (__force __le16)woal_usb_table[i].idProduct) {
858*4882a593Smuzhiyun 			PRINTM(MMSG, "VID/PID = %X/%X, Boot2 version = %X\n",
859*4882a593Smuzhiyun 			       woal_cpu_to_le16(udev->descriptor.idVendor),
860*4882a593Smuzhiyun 			       woal_cpu_to_le16(udev->descriptor.idProduct),
861*4882a593Smuzhiyun 			       woal_cpu_to_le16(udev->descriptor.bcdDevice));
862*4882a593Smuzhiyun 			switch (woal_cpu_to_le16(udev->descriptor.idProduct)) {
863*4882a593Smuzhiyun #ifdef USB8801
864*4882a593Smuzhiyun 			case (__force __le16)USB8801_PID_1:
865*4882a593Smuzhiyun #endif /* USB8801 */
866*4882a593Smuzhiyun #ifdef USB8897
867*4882a593Smuzhiyun 			case (__force __le16)USB8897_PID_1:
868*4882a593Smuzhiyun #endif /* USB8897 */
869*4882a593Smuzhiyun #ifdef USB8997
870*4882a593Smuzhiyun 			case (__force __le16)USB8997_PID_1:
871*4882a593Smuzhiyun 			case (__force __le16)USB8997V2_PID_1:
872*4882a593Smuzhiyun #endif /* USB8997 */
873*4882a593Smuzhiyun #ifdef USB8978
874*4882a593Smuzhiyun 			case (__force __le16)USB8978_PID_1:
875*4882a593Smuzhiyun 			case (__force __le16)USB8978_PID_1_BT:
876*4882a593Smuzhiyun #endif /* USB8978 */
877*4882a593Smuzhiyun #ifdef USB9098
878*4882a593Smuzhiyun 			case (__force __le16)USB9098_PID_1:
879*4882a593Smuzhiyun #endif /* USB9098 */
880*4882a593Smuzhiyun #ifdef USB9097
881*4882a593Smuzhiyun 			case (__force __le16)USB9097_PID_1:
882*4882a593Smuzhiyun #endif /* USB9097 */
883*4882a593Smuzhiyun #ifdef USBNW62X
884*4882a593Smuzhiyun 			case (__force __le16)USBNW62X_PID_1:
885*4882a593Smuzhiyun #endif /* USBNW62X */
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 				/* If skip FW is set, we must return error so
888*4882a593Smuzhiyun 				 * the next driver can download the FW */
889*4882a593Smuzhiyun 				if (skip_fwdnld)
890*4882a593Smuzhiyun 					goto error;
891*4882a593Smuzhiyun 				else
892*4882a593Smuzhiyun 					usb_cardp->boot_state = USB_FW_DNLD;
893*4882a593Smuzhiyun 				break;
894*4882a593Smuzhiyun #ifdef USB8801
895*4882a593Smuzhiyun 			case (__force __le16)USB8801_PID_2:
896*4882a593Smuzhiyun #endif /* USB8801 */
897*4882a593Smuzhiyun #ifdef USB8897
898*4882a593Smuzhiyun 			case (__force __le16)USB8897_PID_2:
899*4882a593Smuzhiyun #endif /* USB8897 */
900*4882a593Smuzhiyun #ifdef USB8997
901*4882a593Smuzhiyun 			case (__force __le16)USB8997_PID_2:
902*4882a593Smuzhiyun #endif /* USB8997 */
903*4882a593Smuzhiyun #ifdef USB8978
904*4882a593Smuzhiyun 			case (__force __le16)USB8978_PID_2:
905*4882a593Smuzhiyun 			case (__force __le16)USB8978_PID_2_BT:
906*4882a593Smuzhiyun #endif /* USB8978 */
907*4882a593Smuzhiyun #ifdef USB9098
908*4882a593Smuzhiyun 			case (__force __le16)USB9098_PID_2:
909*4882a593Smuzhiyun #endif /* USB9098 */
910*4882a593Smuzhiyun #ifdef USB9097
911*4882a593Smuzhiyun 			case (__force __le16)USB9097_PID_2:
912*4882a593Smuzhiyun #endif /* USB9097 */
913*4882a593Smuzhiyun #ifdef USBNW62X
914*4882a593Smuzhiyun 			case (__force __le16)USBNW62X_PID_2:
915*4882a593Smuzhiyun #endif /* USBNW62X */
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 				usb_cardp->boot_state = USB_FW_READY;
918*4882a593Smuzhiyun 				break;
919*4882a593Smuzhiyun 			}
920*4882a593Smuzhiyun 			/*To do, get card type*/
921*4882a593Smuzhiyun 			/*			if
922*4882a593Smuzhiyun 			   (woal_cpu_to_le16(udev->descriptor.idProduct) ==
923*4882a593Smuzhiyun 			   USB8897_PID_2) usb_cardp->card_type =
924*4882a593Smuzhiyun 			   CARD_TYPE_USB8897; else if
925*4882a593Smuzhiyun 			   (woal_cpu_to_le16(udev->descriptor.idProduct) ==
926*4882a593Smuzhiyun 			   USB8997_PID_2) usb_cardp->card_type =
927*4882a593Smuzhiyun 			   CARD_TYPE_USB997;
928*4882a593Smuzhiyun 			*/
929*4882a593Smuzhiyun 			break;
930*4882a593Smuzhiyun 		}
931*4882a593Smuzhiyun 	}
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	if (woal_usb_table[i].idVendor) {
934*4882a593Smuzhiyun 		usb_cardp->udev = udev;
935*4882a593Smuzhiyun 		iface_desc = intf->cur_altsetting;
936*4882a593Smuzhiyun 		usb_cardp->intf = intf;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		PRINTM(MINFO,
939*4882a593Smuzhiyun 		       "bcdUSB = 0x%X bDeviceClass = 0x%X"
940*4882a593Smuzhiyun 		       " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
941*4882a593Smuzhiyun 		       woal_cpu_to_le16(udev->descriptor.bcdUSB),
942*4882a593Smuzhiyun 		       udev->descriptor.bDeviceClass,
943*4882a593Smuzhiyun 		       udev->descriptor.bDeviceSubClass,
944*4882a593Smuzhiyun 		       udev->descriptor.bDeviceProtocol);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 		for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
947*4882a593Smuzhiyun 			endpoint = &iface_desc->endpoint[i].desc;
948*4882a593Smuzhiyun 			if ((usb_endpoint_is_bulk_in(endpoint) ||
949*4882a593Smuzhiyun 			     usb_endpoint_is_int_in(endpoint)) &&
950*4882a593Smuzhiyun 			    (usb_endpoint_num(endpoint) ==
951*4882a593Smuzhiyun 				     MLAN_USB_EP_CMD_EVENT ||
952*4882a593Smuzhiyun 			     usb_endpoint_num(endpoint) ==
953*4882a593Smuzhiyun 				     MLAN_USB_EP_CMD_EVENT_IF2)) {
954*4882a593Smuzhiyun 				usb_cardp->rx_cmd_ep_type =
955*4882a593Smuzhiyun 					usb_endpoint_type(endpoint);
956*4882a593Smuzhiyun 				usb_cardp->rx_cmd_interval =
957*4882a593Smuzhiyun 					endpoint->bInterval;
958*4882a593Smuzhiyun 				/* We found a bulk in command/event endpoint */
959*4882a593Smuzhiyun 				PRINTM(MCMND,
960*4882a593Smuzhiyun 				       "Rx CMD/EVT: max packet size = %d, address = %d ep_type=%d\n",
961*4882a593Smuzhiyun 				       woal_le16_to_cpu(
962*4882a593Smuzhiyun 					       endpoint->wMaxPacketSize),
963*4882a593Smuzhiyun 				       endpoint->bEndpointAddress,
964*4882a593Smuzhiyun 				       usb_cardp->rx_cmd_ep_type);
965*4882a593Smuzhiyun 				usb_cardp->rx_cmd_ep =
966*4882a593Smuzhiyun 					(endpoint->bEndpointAddress &
967*4882a593Smuzhiyun 					 USB_ENDPOINT_NUMBER_MASK);
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 				atomic_set(&usb_cardp->rx_cmd_urb_pending, 0);
970*4882a593Smuzhiyun 				if (usb_endpoint_num(endpoint) ==
971*4882a593Smuzhiyun 				    MLAN_USB_EP_CMD_EVENT_IF2)
972*4882a593Smuzhiyun 					usb_cardp->second_mac = MTRUE;
973*4882a593Smuzhiyun 			}
974*4882a593Smuzhiyun 			if (usb_endpoint_is_bulk_in(endpoint) &&
975*4882a593Smuzhiyun 			    (usb_endpoint_num(endpoint) == MLAN_USB_EP_DATA ||
976*4882a593Smuzhiyun 			     usb_endpoint_num(endpoint) ==
977*4882a593Smuzhiyun 				     MLAN_USB_EP_DATA_IF2)) {
978*4882a593Smuzhiyun 				/* We found a bulk in data endpoint */
979*4882a593Smuzhiyun 				PRINTM(MINFO,
980*4882a593Smuzhiyun 				       "Bulk IN: max packet size = %d, address = %d\n",
981*4882a593Smuzhiyun 				       woal_le16_to_cpu(
982*4882a593Smuzhiyun 					       endpoint->wMaxPacketSize),
983*4882a593Smuzhiyun 				       endpoint->bEndpointAddress);
984*4882a593Smuzhiyun 				usb_cardp->rx_data_ep =
985*4882a593Smuzhiyun 					(endpoint->bEndpointAddress &
986*4882a593Smuzhiyun 					 USB_ENDPOINT_NUMBER_MASK);
987*4882a593Smuzhiyun 				atomic_set(&usb_cardp->rx_data_urb_pending, 0);
988*4882a593Smuzhiyun 			}
989*4882a593Smuzhiyun 			if (usb_endpoint_is_bulk_out(endpoint) &&
990*4882a593Smuzhiyun 			    (usb_endpoint_num(endpoint) == MLAN_USB_EP_DATA ||
991*4882a593Smuzhiyun 			     usb_endpoint_num(endpoint) ==
992*4882a593Smuzhiyun 				     MLAN_USB_EP_DATA_IF2)) {
993*4882a593Smuzhiyun 				/* We found a bulk out data endpoint */
994*4882a593Smuzhiyun 				PRINTM(MCMND,
995*4882a593Smuzhiyun 				       "Bulk OUT: max packet size = %d, address = %d\n",
996*4882a593Smuzhiyun 				       woal_le16_to_cpu(
997*4882a593Smuzhiyun 					       endpoint->wMaxPacketSize),
998*4882a593Smuzhiyun 				       endpoint->bEndpointAddress);
999*4882a593Smuzhiyun 				usb_cardp->tx_data_ep =
1000*4882a593Smuzhiyun 					endpoint->bEndpointAddress;
1001*4882a593Smuzhiyun 				atomic_set(&usb_cardp->tx_data_urb_pending, 0);
1002*4882a593Smuzhiyun 				usb_cardp->tx_data_maxpktsize =
1003*4882a593Smuzhiyun 					(__force int)woal_le16_to_cpu(
1004*4882a593Smuzhiyun 						endpoint->wMaxPacketSize);
1005*4882a593Smuzhiyun 			}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 			if ((usb_endpoint_is_bulk_out(endpoint) ||
1008*4882a593Smuzhiyun 			     usb_endpoint_is_int_out(endpoint)) &&
1009*4882a593Smuzhiyun 			    (usb_endpoint_num(endpoint) ==
1010*4882a593Smuzhiyun 				     MLAN_USB_EP_CMD_EVENT ||
1011*4882a593Smuzhiyun 			     usb_endpoint_num(endpoint) ==
1012*4882a593Smuzhiyun 				     MLAN_USB_EP_CMD_EVENT_IF2)) {
1013*4882a593Smuzhiyun 				usb_cardp->tx_cmd_ep_type =
1014*4882a593Smuzhiyun 					usb_endpoint_type(endpoint);
1015*4882a593Smuzhiyun 				usb_cardp->tx_cmd_interval =
1016*4882a593Smuzhiyun 					endpoint->bInterval;
1017*4882a593Smuzhiyun 				/* We found a bulk out command/event endpoint */
1018*4882a593Smuzhiyun 				PRINTM(MCMND,
1019*4882a593Smuzhiyun 				       "Tx CMD: max packet size = %d, address = %d ep_type=%d\n",
1020*4882a593Smuzhiyun 				       woal_le16_to_cpu(
1021*4882a593Smuzhiyun 					       endpoint->wMaxPacketSize),
1022*4882a593Smuzhiyun 				       endpoint->bEndpointAddress,
1023*4882a593Smuzhiyun 				       usb_cardp->tx_cmd_ep_type);
1024*4882a593Smuzhiyun 				usb_cardp->tx_cmd_ep =
1025*4882a593Smuzhiyun 					endpoint->bEndpointAddress;
1026*4882a593Smuzhiyun 				atomic_set(&usb_cardp->tx_cmd_urb_pending, 0);
1027*4882a593Smuzhiyun 				usb_cardp->tx_cmd_maxpktsize =
1028*4882a593Smuzhiyun 					(__force int)woal_le16_to_cpu(
1029*4882a593Smuzhiyun 						endpoint->wMaxPacketSize);
1030*4882a593Smuzhiyun 			}
1031*4882a593Smuzhiyun 		}
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 		if (usb_cardp->boot_state == USB_FW_DNLD) {
1034*4882a593Smuzhiyun 			if (!usb_cardp->tx_cmd_ep || !usb_cardp->rx_cmd_ep)
1035*4882a593Smuzhiyun 				goto error;
1036*4882a593Smuzhiyun 		} else if (usb_cardp->boot_state == USB_FW_READY) {
1037*4882a593Smuzhiyun 			if (!usb_cardp->tx_cmd_ep || !usb_cardp->tx_data_ep ||
1038*4882a593Smuzhiyun 			    !usb_cardp->rx_cmd_ep || !usb_cardp->rx_data_ep) {
1039*4882a593Smuzhiyun 				PRINTM(MERROR,
1040*4882a593Smuzhiyun 				       "%s: invalid endpoint assignment\n",
1041*4882a593Smuzhiyun 				       __FUNCTION__);
1042*4882a593Smuzhiyun 				goto error;
1043*4882a593Smuzhiyun 			}
1044*4882a593Smuzhiyun 		}
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 		usb_cardp->tx_aggr_ctrl.enable = MFALSE;
1047*4882a593Smuzhiyun 		usb_cardp->tx_aggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
1048*4882a593Smuzhiyun 		usb_cardp->tx_aggr_ctrl.aggr_align =
1049*4882a593Smuzhiyun 			MAX(max_tx_buf, MLAN_USB_TX_AGGR_ALIGN);
1050*4882a593Smuzhiyun 		usb_cardp->tx_aggr_ctrl.aggr_max = MLAN_USB_TX_MAX_AGGR_NUM;
1051*4882a593Smuzhiyun 		usb_cardp->tx_aggr_ctrl.aggr_tmo =
1052*4882a593Smuzhiyun 			MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000;
1053*4882a593Smuzhiyun 		usb_cardp->rx_deaggr_ctrl.enable = MFALSE;
1054*4882a593Smuzhiyun 		usb_cardp->rx_deaggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
1055*4882a593Smuzhiyun 		usb_cardp->rx_deaggr_ctrl.aggr_align = MLAN_USB_RX_ALIGN_SIZE;
1056*4882a593Smuzhiyun 		usb_cardp->rx_deaggr_ctrl.aggr_max = MLAN_USB_RX_MAX_AGGR_NUM;
1057*4882a593Smuzhiyun 		usb_cardp->rx_deaggr_ctrl.aggr_tmo =
1058*4882a593Smuzhiyun 			MLAN_USB_RX_DEAGGR_TIMEOUT_USEC;
1059*4882a593Smuzhiyun 		usb_set_intfdata(intf, usb_cardp);
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 		card_type = woal_update_card_type(usb_cardp);
1062*4882a593Smuzhiyun 		if (!card_type) {
1063*4882a593Smuzhiyun 			PRINTM(MERROR,
1064*4882a593Smuzhiyun 			       "usb probe: woal_update_card_type() failed\n");
1065*4882a593Smuzhiyun 			goto error;
1066*4882a593Smuzhiyun 		}
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 		/* At this point wlan_add_card() will be called */
1069*4882a593Smuzhiyun 		if (!(woal_add_card(usb_cardp, &usb_cardp->udev->dev, &usb_ops,
1070*4882a593Smuzhiyun 				    card_type))) {
1071*4882a593Smuzhiyun 			PRINTM(MERROR, "%s: woal_add_card failed\n",
1072*4882a593Smuzhiyun 			       __FUNCTION__);
1073*4882a593Smuzhiyun 			goto error;
1074*4882a593Smuzhiyun 		}
1075*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1076*4882a593Smuzhiyun 		/* Note: From 2.6.34.2 onwards, remote wakeup is NOT enabled by
1077*4882a593Smuzhiyun 		 * default. So drivers wanting remote wakeup will have to enable
1078*4882a593Smuzhiyun 		 * this using -
1079*4882a593Smuzhiyun 		 * device_set_wakeup_enable(&udev->dev, 1);
1080*4882a593Smuzhiyun 		 * It has been observed that some cards having device attr =
1081*4882a593Smuzhiyun 		 * 0xa0 do not support remote wakeup. These cards come
1082*4882a593Smuzhiyun 		 * immediately out of the suspend when power/wakeup file is set
1083*4882a593Smuzhiyun 		 * to 'enabled'. To support all types of cards i.e. with/without
1084*4882a593Smuzhiyun 		 * remote wakeup, we are NOT setting the 'power/wakeup' file
1085*4882a593Smuzhiyun 		 * from here. Also in principle, we are not supposed to change
1086*4882a593Smuzhiyun 		 * the wakeup policy, which is purely a userspace decision.
1087*4882a593Smuzhiyun 		 */
1088*4882a593Smuzhiyun 		/* if (udev->actconfig->desc.bmAttributes &
1089*4882a593Smuzhiyun 		   USB_CONFIG_ATT_WAKEUP) intf->needs_remote_wakeup = 1; */
1090*4882a593Smuzhiyun #endif
1091*4882a593Smuzhiyun 		usb_get_dev(udev);
1092*4882a593Smuzhiyun 		LEAVE();
1093*4882a593Smuzhiyun 		return 0;
1094*4882a593Smuzhiyun 	} else {
1095*4882a593Smuzhiyun 		PRINTM(MINFO, "Discard the Probe request\n");
1096*4882a593Smuzhiyun 		PRINTM(MINFO, "VID = 0x%X PID = 0x%X\n",
1097*4882a593Smuzhiyun 		       woal_cpu_to_le16(udev->descriptor.idVendor),
1098*4882a593Smuzhiyun 		       woal_cpu_to_le16(udev->descriptor.idProduct));
1099*4882a593Smuzhiyun 	}
1100*4882a593Smuzhiyun error:
1101*4882a593Smuzhiyun 	kfree(usb_cardp);
1102*4882a593Smuzhiyun 	usb_cardp = NULL;
1103*4882a593Smuzhiyun 	LEAVE();
1104*4882a593Smuzhiyun 	return -ENXIO;
1105*4882a593Smuzhiyun }
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun /**
1108*4882a593Smuzhiyun  *  @brief Free resource and cleanup
1109*4882a593Smuzhiyun  *
1110*4882a593Smuzhiyun  *  @param intf		Pointer to usb_interface
1111*4882a593Smuzhiyun  *
1112*4882a593Smuzhiyun  *  @return 	   	N/A
1113*4882a593Smuzhiyun  */
woal_usb_disconnect(struct usb_interface * intf)1114*4882a593Smuzhiyun static void woal_usb_disconnect(struct usb_interface *intf)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	struct usb_card_rec *cardp = usb_get_intfdata(intf);
1117*4882a593Smuzhiyun 	moal_handle *phandle = NULL;
1118*4882a593Smuzhiyun 	ENTER();
1119*4882a593Smuzhiyun 	if (!cardp || !cardp->phandle) {
1120*4882a593Smuzhiyun 		PRINTM(MERROR, "Card or phandle is not valid\n");
1121*4882a593Smuzhiyun 		LEAVE();
1122*4882a593Smuzhiyun 		return;
1123*4882a593Smuzhiyun 	}
1124*4882a593Smuzhiyun 	phandle = (moal_handle *)cardp->phandle;
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 	/*
1127*4882a593Smuzhiyun 	 * Update Surprise removed to TRUE
1128*4882a593Smuzhiyun 	 *  Free all the URB's allocated
1129*4882a593Smuzhiyun 	 */
1130*4882a593Smuzhiyun 	phandle->surprise_removed = MTRUE;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	/* Card is removed and we can call wlan_remove_card */
1133*4882a593Smuzhiyun 	PRINTM(MINFO, "Call remove card\n");
1134*4882a593Smuzhiyun 	woal_remove_card(cardp);
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	usb_set_intfdata(intf, NULL);
1137*4882a593Smuzhiyun 	usb_put_dev(interface_to_usbdev(intf));
1138*4882a593Smuzhiyun 	kfree(cardp);
1139*4882a593Smuzhiyun 	LEAVE();
1140*4882a593Smuzhiyun 	return;
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun /**
1144*4882a593Smuzhiyun  *  @brief killall pending urbs
1145*4882a593Smuzhiyun  *
1146*4882a593Smuzhiyun  *  @param handle	  Pointer to moal_handle
1147*4882a593Smuzhiyun  *
1148*4882a593Smuzhiyun  *
1149*4882a593Smuzhiyun  *  @return 	   	  N/A
1150*4882a593Smuzhiyun  */
woal_kill_urbs(moal_handle * handle)1151*4882a593Smuzhiyun void woal_kill_urbs(moal_handle *handle)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun 	ENTER();
1154*4882a593Smuzhiyun 	handle->is_suspended = MTRUE;
1155*4882a593Smuzhiyun 	woal_usb_unlink_urb(handle->card);
1156*4882a593Smuzhiyun 	LEAVE();
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun /**
1160*4882a593Smuzhiyun  *  @brief resubmit urbs
1161*4882a593Smuzhiyun  *
1162*4882a593Smuzhiyun  *  @param handle	  Pointer to moal_handle
1163*4882a593Smuzhiyun  *
1164*4882a593Smuzhiyun  *
1165*4882a593Smuzhiyun  *  @return 	   	  N/A
1166*4882a593Smuzhiyun  */
woal_resubmit_urbs(moal_handle * handle)1167*4882a593Smuzhiyun void woal_resubmit_urbs(moal_handle *handle)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun 	struct usb_card_rec *cardp = handle->card;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	ENTER();
1172*4882a593Smuzhiyun 	handle->is_suspended = MFALSE;
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	if (!atomic_read(&cardp->rx_data_urb_pending)) {
1175*4882a593Smuzhiyun 		/* Submit multiple Rx data URBs */
1176*4882a593Smuzhiyun 		woal_usb_submit_rx_data_urbs(handle);
1177*4882a593Smuzhiyun 	}
1178*4882a593Smuzhiyun 	if (!atomic_read(&cardp->rx_cmd_urb_pending)) {
1179*4882a593Smuzhiyun 		cardp->rx_cmd.pmbuf =
1180*4882a593Smuzhiyun 			woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
1181*4882a593Smuzhiyun 		if (cardp->rx_cmd.pmbuf)
1182*4882a593Smuzhiyun 			woal_usb_submit_rx_urb(&cardp->rx_cmd,
1183*4882a593Smuzhiyun 					       MLAN_RX_CMD_BUF_SIZE);
1184*4882a593Smuzhiyun 	}
1185*4882a593Smuzhiyun 	LEAVE();
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun #ifdef CONFIG_PM
1189*4882a593Smuzhiyun /**
1190*4882a593Smuzhiyun  *  @brief Handle suspend
1191*4882a593Smuzhiyun  *
1192*4882a593Smuzhiyun  *  @param intf		  Pointer to usb_interface
1193*4882a593Smuzhiyun  *  @param message	  Pointer to pm_message_t structure
1194*4882a593Smuzhiyun  *
1195*4882a593Smuzhiyun  *  @return 	   	  MLAN_STATUS_SUCCESS
1196*4882a593Smuzhiyun  */
woal_usb_suspend(struct usb_interface * intf,pm_message_t message)1197*4882a593Smuzhiyun static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message)
1198*4882a593Smuzhiyun {
1199*4882a593Smuzhiyun 	struct usb_card_rec *cardp = usb_get_intfdata(intf);
1200*4882a593Smuzhiyun 	moal_handle *handle = NULL;
1201*4882a593Smuzhiyun 	int i;
1202*4882a593Smuzhiyun 	int ret = 0;
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	ENTER();
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	PRINTM(MCMND, "<--- Enter woal_usb_suspend --->\n");
1207*4882a593Smuzhiyun 	if (!cardp || !cardp->phandle) {
1208*4882a593Smuzhiyun 		PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
1209*4882a593Smuzhiyun 		ret = 0;
1210*4882a593Smuzhiyun 		goto done;
1211*4882a593Smuzhiyun 	}
1212*4882a593Smuzhiyun 	handle = cardp->phandle;
1213*4882a593Smuzhiyun 	if (handle->is_suspended == MTRUE) {
1214*4882a593Smuzhiyun 		PRINTM(MWARN, "Device already suspended\n");
1215*4882a593Smuzhiyun 		ret = 0;
1216*4882a593Smuzhiyun 		goto done;
1217*4882a593Smuzhiyun 	}
1218*4882a593Smuzhiyun #ifdef STA_SUPPORT
1219*4882a593Smuzhiyun 	for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
1220*4882a593Smuzhiyun 		if (handle->priv[i] &&
1221*4882a593Smuzhiyun 		    (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
1222*4882a593Smuzhiyun 			woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
1223*4882a593Smuzhiyun 	}
1224*4882a593Smuzhiyun #endif
1225*4882a593Smuzhiyun 	/* Enable Host Sleep */
1226*4882a593Smuzhiyun 	woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	/* Indicate device suspended */
1229*4882a593Smuzhiyun 	/* The flag must be set here before the usb_kill_urb() calls.
1230*4882a593Smuzhiyun 	 * Reason: In the complete handlers, urb->status(= -ENOENT) and
1231*4882a593Smuzhiyun 	 * 'is_suspended' flag is used in combination to distinguish
1232*4882a593Smuzhiyun 	 * between a suspended state and a 'disconnect' one.
1233*4882a593Smuzhiyun 	 */
1234*4882a593Smuzhiyun 	handle->is_suspended = MTRUE;
1235*4882a593Smuzhiyun 	for (i = 0; i < handle->priv_num; i++)
1236*4882a593Smuzhiyun 		netif_carrier_off(handle->priv[i]->netdev);
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	/* Unlink Rx cmd URB */
1239*4882a593Smuzhiyun 	if (atomic_read(&cardp->rx_cmd_urb_pending) && cardp->rx_cmd.urb) {
1240*4882a593Smuzhiyun 		usb_kill_urb(cardp->rx_cmd.urb);
1241*4882a593Smuzhiyun 	}
1242*4882a593Smuzhiyun 	/* Unlink Rx data URBs */
1243*4882a593Smuzhiyun 	if (atomic_read(&cardp->rx_data_urb_pending)) {
1244*4882a593Smuzhiyun 		for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
1245*4882a593Smuzhiyun 			if (cardp->rx_data_list[i].urb) {
1246*4882a593Smuzhiyun 				usb_kill_urb(cardp->rx_data_list[i].urb);
1247*4882a593Smuzhiyun 				usb_init_urb(cardp->rx_data_list[i].urb);
1248*4882a593Smuzhiyun 			}
1249*4882a593Smuzhiyun 		}
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	/* Unlink Tx data URBs */
1253*4882a593Smuzhiyun 	for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
1254*4882a593Smuzhiyun 		if (cardp->tx_data_list[i].urb) {
1255*4882a593Smuzhiyun 			usb_kill_urb(cardp->tx_data_list[i].urb);
1256*4882a593Smuzhiyun 		}
1257*4882a593Smuzhiyun 	}
1258*4882a593Smuzhiyun 	/* Unlink Tx cmd URB */
1259*4882a593Smuzhiyun 	if (cardp->tx_cmd.urb) {
1260*4882a593Smuzhiyun 		usb_kill_urb(cardp->tx_cmd.urb);
1261*4882a593Smuzhiyun 	}
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 	handle->suspend_wait_q_woken = MTRUE;
1264*4882a593Smuzhiyun 	wake_up_interruptible(&handle->suspend_wait_q);
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun done:
1267*4882a593Smuzhiyun 	PRINTM(MCMND, "<--- Leave woal_usb_suspend --->\n");
1268*4882a593Smuzhiyun 	LEAVE();
1269*4882a593Smuzhiyun 	return ret;
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun /**
1273*4882a593Smuzhiyun  *  @brief Handle resume
1274*4882a593Smuzhiyun  *
1275*4882a593Smuzhiyun  *  @param intf		  Pointer to usb_interface
1276*4882a593Smuzhiyun  *
1277*4882a593Smuzhiyun  *  @return 	   	  MLAN_STATUS_SUCCESS
1278*4882a593Smuzhiyun  */
woal_usb_resume(struct usb_interface * intf)1279*4882a593Smuzhiyun static int woal_usb_resume(struct usb_interface *intf)
1280*4882a593Smuzhiyun {
1281*4882a593Smuzhiyun 	struct usb_card_rec *cardp = usb_get_intfdata(intf);
1282*4882a593Smuzhiyun 	moal_handle *handle = NULL;
1283*4882a593Smuzhiyun 	int i;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	ENTER();
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	PRINTM(MCMND, "<--- Enter woal_usb_resume --->\n");
1288*4882a593Smuzhiyun 	if (!cardp || !cardp->phandle) {
1289*4882a593Smuzhiyun 		PRINTM(MERROR, "Card or adapter structure is not valid\n");
1290*4882a593Smuzhiyun 		goto done;
1291*4882a593Smuzhiyun 	}
1292*4882a593Smuzhiyun 	handle = cardp->phandle;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	if (handle->is_suspended == MFALSE) {
1295*4882a593Smuzhiyun 		PRINTM(MWARN, "Device already resumed\n");
1296*4882a593Smuzhiyun 		goto done;
1297*4882a593Smuzhiyun 	}
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	/* Indicate device resumed.
1300*4882a593Smuzhiyun 	 * The netdev queue will be resumed only after the urbs
1301*4882a593Smuzhiyun 	 * have been resubmitted */
1302*4882a593Smuzhiyun 	handle->is_suspended = MFALSE;
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	if (!atomic_read(&cardp->rx_data_urb_pending)) {
1305*4882a593Smuzhiyun 		/* Submit multiple Rx data URBs */
1306*4882a593Smuzhiyun 		woal_usb_submit_rx_data_urbs(handle);
1307*4882a593Smuzhiyun 	}
1308*4882a593Smuzhiyun 	if (!atomic_read(&cardp->rx_cmd_urb_pending)) {
1309*4882a593Smuzhiyun 		cardp->rx_cmd.pmbuf =
1310*4882a593Smuzhiyun 			woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
1311*4882a593Smuzhiyun 		if (cardp->rx_cmd.pmbuf)
1312*4882a593Smuzhiyun 			woal_usb_submit_rx_urb(&cardp->rx_cmd,
1313*4882a593Smuzhiyun 					       MLAN_RX_CMD_BUF_SIZE);
1314*4882a593Smuzhiyun 	}
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	for (i = 0; i < handle->priv_num; i++)
1317*4882a593Smuzhiyun 		if (handle->priv[i]->media_connected == MTRUE)
1318*4882a593Smuzhiyun 			netif_carrier_on(handle->priv[i]->netdev);
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	/* Disable Host Sleep */
1321*4882a593Smuzhiyun 	if (handle->hs_activated)
1322*4882a593Smuzhiyun 		woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
1323*4882a593Smuzhiyun 			       MOAL_NO_WAIT);
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1326*4882a593Smuzhiyun 		/* Resume handler may be called due to remote wakeup,
1327*4882a593Smuzhiyun 		   force to exit suspend anyway */
1328*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
1329*4882a593Smuzhiyun 	cardp->udev->autosuspend_disabled = 1;
1330*4882a593Smuzhiyun #else
1331*4882a593Smuzhiyun #ifdef CONFIG_PM_RUNTIME
1332*4882a593Smuzhiyun 	cardp->udev->dev.power.runtime_auto = 0;
1333*4882a593Smuzhiyun #endif
1334*4882a593Smuzhiyun #endif /* < 2.6.35 */
1335*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
1336*4882a593Smuzhiyun 	cardp->udev->autoresume_disabled = 0;
1337*4882a593Smuzhiyun #endif /* < 2.6.33 */
1338*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
1339*4882a593Smuzhiyun #ifdef CONFIG_PM_RUNTIME
1340*4882a593Smuzhiyun 	atomic_inc(&(cardp->udev)->dev.power.usage_count);
1341*4882a593Smuzhiyun #endif
1342*4882a593Smuzhiyun #endif /* >= 2.6.34 */
1343*4882a593Smuzhiyun #endif /* >= 2.6.24 */
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun done:
1346*4882a593Smuzhiyun 	PRINTM(MCMND, "<--- Leave woal_usb_resume --->\n");
1347*4882a593Smuzhiyun 	LEAVE();
1348*4882a593Smuzhiyun 	return 0;
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun #endif /* CONFIG_PM */
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun /**
1353*4882a593Smuzhiyun  *  @brief This function initialize the tx URBs
1354*4882a593Smuzhiyun  *
1355*4882a593Smuzhiyun  *  @param handle 	Pointer to moal_handle structure
1356*4882a593Smuzhiyun  *
1357*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1358*4882a593Smuzhiyun  */
woal_usb_tx_init(moal_handle * handle)1359*4882a593Smuzhiyun mlan_status woal_usb_tx_init(moal_handle *handle)
1360*4882a593Smuzhiyun {
1361*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1362*4882a593Smuzhiyun 	int i;
1363*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun 	ENTER();
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	cardp->tx_cmd.handle = handle;
1368*4882a593Smuzhiyun 	cardp->tx_cmd.ep = cardp->tx_cmd_ep;
1369*4882a593Smuzhiyun 	/* Allocate URB for command */
1370*4882a593Smuzhiyun 	cardp->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
1371*4882a593Smuzhiyun 	if (!cardp->tx_cmd.urb) {
1372*4882a593Smuzhiyun 		PRINTM(MERROR, "Tx command URB allocation failed\n");
1373*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1374*4882a593Smuzhiyun 		goto init_exit;
1375*4882a593Smuzhiyun 	}
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 	cardp->tx_data_ix = 0;
1378*4882a593Smuzhiyun 	for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
1379*4882a593Smuzhiyun 		cardp->tx_data_list[i].handle = handle;
1380*4882a593Smuzhiyun 		cardp->tx_data_list[i].ep = cardp->tx_data_ep;
1381*4882a593Smuzhiyun 		/* Allocate URB for data */
1382*4882a593Smuzhiyun 		cardp->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
1383*4882a593Smuzhiyun 		if (!cardp->tx_data_list[i].urb) {
1384*4882a593Smuzhiyun 			PRINTM(MERROR, "Tx data URB allocation failed\n");
1385*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1386*4882a593Smuzhiyun 			goto init_exit;
1387*4882a593Smuzhiyun 		}
1388*4882a593Smuzhiyun 	}
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun init_exit:
1391*4882a593Smuzhiyun 	LEAVE();
1392*4882a593Smuzhiyun 	return ret;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun /**
1396*4882a593Smuzhiyun  *  @brief This function submits the rx data URBs
1397*4882a593Smuzhiyun  *
1398*4882a593Smuzhiyun  *  @param handle 	Pointer to moal_handle structure
1399*4882a593Smuzhiyun  *
1400*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1401*4882a593Smuzhiyun  */
woal_usb_submit_rx_data_urbs(moal_handle * handle)1402*4882a593Smuzhiyun mlan_status woal_usb_submit_rx_data_urbs(moal_handle *handle)
1403*4882a593Smuzhiyun {
1404*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1405*4882a593Smuzhiyun 	int i;
1406*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_FAILURE;
1407*4882a593Smuzhiyun 	t_u32 buffer_len = MLAN_RX_DATA_BUF_SIZE;
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	ENTER();
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	if (cardp->rx_deaggr_ctrl.enable) {
1412*4882a593Smuzhiyun 		buffer_len = cardp->rx_deaggr_ctrl.aggr_max;
1413*4882a593Smuzhiyun 		if (cardp->rx_deaggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_NUM) {
1414*4882a593Smuzhiyun 			buffer_len *= MAX(MLAN_USB_MAX_PKT_SIZE,
1415*4882a593Smuzhiyun 					  cardp->rx_deaggr_ctrl.aggr_align);
1416*4882a593Smuzhiyun 			buffer_len = MAX(buffer_len, MLAN_RX_DATA_BUF_SIZE);
1417*4882a593Smuzhiyun 		}
1418*4882a593Smuzhiyun 	}
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 	for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
1421*4882a593Smuzhiyun 		/* Submit Rx data URB */
1422*4882a593Smuzhiyun 		if (!cardp->rx_data_list[i].pmbuf) {
1423*4882a593Smuzhiyun 			if (woal_usb_submit_rx_urb(&cardp->rx_data_list[i],
1424*4882a593Smuzhiyun 						   buffer_len))
1425*4882a593Smuzhiyun 				continue;
1426*4882a593Smuzhiyun 		}
1427*4882a593Smuzhiyun 		ret = MLAN_STATUS_SUCCESS;
1428*4882a593Smuzhiyun 	}
1429*4882a593Smuzhiyun 	LEAVE();
1430*4882a593Smuzhiyun 	return ret;
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun /**
1434*4882a593Smuzhiyun  *  @brief This function initialize the rx URBs and submit them
1435*4882a593Smuzhiyun  *
1436*4882a593Smuzhiyun  *  @param handle 	Pointer to moal_handle structure
1437*4882a593Smuzhiyun  *
1438*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1439*4882a593Smuzhiyun  */
woal_usb_rx_init(moal_handle * handle)1440*4882a593Smuzhiyun mlan_status woal_usb_rx_init(moal_handle *handle)
1441*4882a593Smuzhiyun {
1442*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1443*4882a593Smuzhiyun 	int i;
1444*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 	ENTER();
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	cardp->rx_cmd.handle = handle;
1449*4882a593Smuzhiyun 	cardp->rx_cmd.ep = cardp->rx_cmd_ep;
1450*4882a593Smuzhiyun 	/* Allocate URB for command/event */
1451*4882a593Smuzhiyun 	cardp->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
1452*4882a593Smuzhiyun 	if (!cardp->rx_cmd.urb) {
1453*4882a593Smuzhiyun 		PRINTM(MERROR, "Rx command URB allocation failed\n");
1454*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1455*4882a593Smuzhiyun 		goto init_exit;
1456*4882a593Smuzhiyun 	}
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	cardp->rx_cmd.pmbuf =
1459*4882a593Smuzhiyun 		woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
1460*4882a593Smuzhiyun 	if (cardp->rx_cmd.pmbuf) {
1461*4882a593Smuzhiyun 		/* Submit Rx command URB */
1462*4882a593Smuzhiyun 		if (woal_usb_submit_rx_urb(&cardp->rx_cmd,
1463*4882a593Smuzhiyun 					   MLAN_RX_CMD_BUF_SIZE)) {
1464*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1465*4882a593Smuzhiyun 			goto init_exit;
1466*4882a593Smuzhiyun 		}
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun 	for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
1469*4882a593Smuzhiyun 		cardp->rx_data_list[i].handle = handle;
1470*4882a593Smuzhiyun 		cardp->rx_data_list[i].ep = cardp->rx_data_ep;
1471*4882a593Smuzhiyun 		/* Allocate URB for data */
1472*4882a593Smuzhiyun 		cardp->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
1473*4882a593Smuzhiyun 		if (!cardp->rx_data_list[i].urb) {
1474*4882a593Smuzhiyun 			PRINTM(MERROR, "Rx data URB allocation failed\n");
1475*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1476*4882a593Smuzhiyun 			goto init_exit;
1477*4882a593Smuzhiyun 		}
1478*4882a593Smuzhiyun 	}
1479*4882a593Smuzhiyun 	ret = woal_usb_submit_rx_data_urbs(handle);
1480*4882a593Smuzhiyun 	if (ret) {
1481*4882a593Smuzhiyun 		PRINTM(MERROR, "Rx data URB submission failed\n");
1482*4882a593Smuzhiyun 		goto init_exit;
1483*4882a593Smuzhiyun 	}
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun init_exit:
1486*4882a593Smuzhiyun 	LEAVE();
1487*4882a593Smuzhiyun 	return ret;
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun /**
1491*4882a593Smuzhiyun  *  @brief  This function downloads data blocks to device
1492*4882a593Smuzhiyun  *
1493*4882a593Smuzhiyun  *  @param handle	Pointer to moal_handle structure
1494*4882a593Smuzhiyun  *  @param pmbuf	Pointer to mlan_buffer structure
1495*4882a593Smuzhiyun  *  @param ep		Endpoint to send
1496*4882a593Smuzhiyun  *  @param timeout 	Timeout value in milliseconds (if 0 the wait is forever)
1497*4882a593Smuzhiyun  *
1498*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1499*4882a593Smuzhiyun  */
woal_usb_write_data_sync(moal_handle * handle,mlan_buffer * pmbuf,t_u32 endpoint,t_u32 timeout)1500*4882a593Smuzhiyun static mlan_status woal_usb_write_data_sync(moal_handle *handle,
1501*4882a593Smuzhiyun 					    mlan_buffer *pmbuf, t_u32 endpoint,
1502*4882a593Smuzhiyun 					    t_u32 timeout)
1503*4882a593Smuzhiyun {
1504*4882a593Smuzhiyun 	struct usb_card_rec *cardp = handle->card;
1505*4882a593Smuzhiyun 	t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
1506*4882a593Smuzhiyun 	t_u8 ep = endpoint;
1507*4882a593Smuzhiyun 	t_u32 length = pmbuf->data_len;
1508*4882a593Smuzhiyun 	int actual_length;
1509*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1510*4882a593Smuzhiyun 	int bulk_out_maxpktsize = 512;
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 	if (ep == cardp->tx_cmd_ep)
1513*4882a593Smuzhiyun 		bulk_out_maxpktsize = cardp->tx_cmd_maxpktsize;
1514*4882a593Smuzhiyun 	else if (ep == cardp->tx_data_ep)
1515*4882a593Smuzhiyun 		bulk_out_maxpktsize = cardp->tx_data_maxpktsize;
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun 	if (length % bulk_out_maxpktsize == 0)
1518*4882a593Smuzhiyun 		length++;
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 	/* Send the data block */
1521*4882a593Smuzhiyun 	ret = usb_bulk_msg(cardp->udev, usb_sndbulkpipe(cardp->udev, ep),
1522*4882a593Smuzhiyun 			   (t_u8 *)data, length, &actual_length, timeout);
1523*4882a593Smuzhiyun 	if (ret) {
1524*4882a593Smuzhiyun 		PRINTM(MERROR, "usb_blk_msg for send failed, ret %d\n", ret);
1525*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1526*4882a593Smuzhiyun 	}
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 	pmbuf->data_len = actual_length;
1529*4882a593Smuzhiyun 	DBG_HEXDUMP(MIF_D, "write sync", data, actual_length);
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	return ret;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun /**
1535*4882a593Smuzhiyun  *  @brief  This function read data blocks to device
1536*4882a593Smuzhiyun  *
1537*4882a593Smuzhiyun  *  @param handle	Pointer to moal_handle structure
1538*4882a593Smuzhiyun  *  @param pmbuf	Pointer to mlan_buffer structure
1539*4882a593Smuzhiyun  *  @param ep		Endpoint to receive
1540*4882a593Smuzhiyun  *  @param timeout 	Timeout value in milliseconds (if 0 the wait is forever)
1541*4882a593Smuzhiyun  *
1542*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1543*4882a593Smuzhiyun  */
woal_usb_read_data_sync(moal_handle * handle,mlan_buffer * pmbuf,t_u32 endpoint,t_u32 timeout)1544*4882a593Smuzhiyun static mlan_status woal_usb_read_data_sync(moal_handle *handle,
1545*4882a593Smuzhiyun 					   mlan_buffer *pmbuf, t_u32 endpoint,
1546*4882a593Smuzhiyun 					   t_u32 timeout)
1547*4882a593Smuzhiyun {
1548*4882a593Smuzhiyun 	struct usb_card_rec *cardp = handle->card;
1549*4882a593Smuzhiyun 	t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
1550*4882a593Smuzhiyun 	t_u8 ep = endpoint;
1551*4882a593Smuzhiyun 	t_u32 buf_len = pmbuf->data_len;
1552*4882a593Smuzhiyun 	int actual_length;
1553*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1554*4882a593Smuzhiyun 	ENTER();
1555*4882a593Smuzhiyun 	/* Receive the data response */
1556*4882a593Smuzhiyun 	ret = usb_bulk_msg(cardp->udev, usb_rcvbulkpipe(cardp->udev, ep), data,
1557*4882a593Smuzhiyun 			   buf_len, &actual_length, timeout);
1558*4882a593Smuzhiyun 	if (ret) {
1559*4882a593Smuzhiyun 		PRINTM(MERROR, "usb_bulk_msg failed: %d\n", ret);
1560*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1561*4882a593Smuzhiyun 	}
1562*4882a593Smuzhiyun 	pmbuf->data_len = actual_length;
1563*4882a593Smuzhiyun 	DBG_HEXDUMP(MIF_D, "read sync", data, actual_length);
1564*4882a593Smuzhiyun 	LEAVE();
1565*4882a593Smuzhiyun 	return ret;
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun /**
1569*4882a593Smuzhiyun  *  @brief  This function downloads data/command packet to device
1570*4882a593Smuzhiyun  *
1571*4882a593Smuzhiyun  *  @param handle	Pointer to moal_handle structure
1572*4882a593Smuzhiyun  *  @param pmbuf	Pointer to mlan_buffer structure
1573*4882a593Smuzhiyun  *  @param ep		Endpoint to send
1574*4882a593Smuzhiyun  *
1575*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE or
1576*4882a593Smuzhiyun  * MLAN_STATUS_RESOURCE
1577*4882a593Smuzhiyun  */
woal_write_data_async(moal_handle * handle,mlan_buffer * pmbuf,t_u8 ep)1578*4882a593Smuzhiyun mlan_status woal_write_data_async(moal_handle *handle, mlan_buffer *pmbuf,
1579*4882a593Smuzhiyun 				  t_u8 ep)
1580*4882a593Smuzhiyun {
1581*4882a593Smuzhiyun 	struct usb_card_rec *cardp = handle->card;
1582*4882a593Smuzhiyun 	urb_context *context = NULL;
1583*4882a593Smuzhiyun 	t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
1584*4882a593Smuzhiyun 	struct urb *tx_urb = NULL;
1585*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1586*4882a593Smuzhiyun 	t_u32 data_len = pmbuf->data_len;
1587*4882a593Smuzhiyun 	int bulk_out_maxpktsize = 512;
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	ENTER();
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun 	/* Check if device is removed */
1592*4882a593Smuzhiyun 	if (handle->surprise_removed) {
1593*4882a593Smuzhiyun 		PRINTM(MERROR, "Device removed\n");
1594*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1595*4882a593Smuzhiyun 		goto tx_ret;
1596*4882a593Smuzhiyun 	}
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 	if ((ep == cardp->tx_data_ep) &&
1599*4882a593Smuzhiyun 	    (atomic_read(&cardp->tx_data_urb_pending) >= MVUSB_TX_HIGH_WMARK)) {
1600*4882a593Smuzhiyun 		ret = MLAN_STATUS_RESOURCE;
1601*4882a593Smuzhiyun 		goto tx_ret;
1602*4882a593Smuzhiyun 	}
1603*4882a593Smuzhiyun 	PRINTM(MINFO, "woal_write_data_async: ep=%d\n", ep);
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun 	if (ep == cardp->tx_cmd_ep) {
1606*4882a593Smuzhiyun 		context = &cardp->tx_cmd;
1607*4882a593Smuzhiyun 		bulk_out_maxpktsize = cardp->tx_cmd_maxpktsize;
1608*4882a593Smuzhiyun 	} else {
1609*4882a593Smuzhiyun 		if (ep == cardp->tx_data_ep) {
1610*4882a593Smuzhiyun 			bulk_out_maxpktsize = cardp->tx_data_maxpktsize;
1611*4882a593Smuzhiyun 			if (cardp->tx_data_ix >= MVUSB_TX_HIGH_WMARK)
1612*4882a593Smuzhiyun 				cardp->tx_data_ix = 0;
1613*4882a593Smuzhiyun 			context = &cardp->tx_data_list[cardp->tx_data_ix++];
1614*4882a593Smuzhiyun 		}
1615*4882a593Smuzhiyun 	}
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	if (!context) {
1618*4882a593Smuzhiyun 		PRINTM(MERROR, "Cannot allocate Tx urb_context\n");
1619*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1620*4882a593Smuzhiyun 		goto tx_ret;
1621*4882a593Smuzhiyun 	}
1622*4882a593Smuzhiyun 	context->handle = handle;
1623*4882a593Smuzhiyun 	context->ep = ep;
1624*4882a593Smuzhiyun 	context->pmbuf = pmbuf;
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	tx_urb = context->urb;
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	if (data_len % bulk_out_maxpktsize == 0)
1629*4882a593Smuzhiyun 		data_len++;
1630*4882a593Smuzhiyun 
1631*4882a593Smuzhiyun 	/*
1632*4882a593Smuzhiyun 	 * Use USB API usb_fill_bulk_urb() to set the
1633*4882a593Smuzhiyun 	 * configuration information of the Tx bulk URB
1634*4882a593Smuzhiyun 	 * and initialize the Tx callback
1635*4882a593Smuzhiyun 	 */
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun 	if (ep == cardp->tx_cmd_ep &&
1638*4882a593Smuzhiyun 	    cardp->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) {
1639*4882a593Smuzhiyun 		usb_fill_int_urb(tx_urb, cardp->udev,
1640*4882a593Smuzhiyun 				 usb_sndintpipe(cardp->udev, ep), data,
1641*4882a593Smuzhiyun 				 data_len, woal_usb_tx_complete,
1642*4882a593Smuzhiyun 				 (void *)context, cardp->tx_cmd_interval);
1643*4882a593Smuzhiyun 	} else
1644*4882a593Smuzhiyun 		usb_fill_bulk_urb(tx_urb, cardp->udev,
1645*4882a593Smuzhiyun 				  usb_sndbulkpipe(cardp->udev, ep), data,
1646*4882a593Smuzhiyun 				  data_len, woal_usb_tx_complete,
1647*4882a593Smuzhiyun 				  (void *)context);
1648*4882a593Smuzhiyun 	/* We find on Ubuntu 12.10 this flag does not work */
1649*4882a593Smuzhiyun 	// tx_urb->transfer_flags |= URB_ZERO_PACKET;
1650*4882a593Smuzhiyun 
1651*4882a593Smuzhiyun 	if (ep == cardp->tx_cmd_ep)
1652*4882a593Smuzhiyun 		atomic_inc(&cardp->tx_cmd_urb_pending);
1653*4882a593Smuzhiyun 	else if (ep == cardp->tx_data_ep)
1654*4882a593Smuzhiyun 		atomic_inc(&cardp->tx_data_urb_pending);
1655*4882a593Smuzhiyun 	if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
1656*4882a593Smuzhiyun 		/* Submit URB failure */
1657*4882a593Smuzhiyun 		PRINTM(MERROR, "Submit EP %d Tx URB failed: %d\n", ep, ret);
1658*4882a593Smuzhiyun 		if (ep == cardp->tx_cmd_ep)
1659*4882a593Smuzhiyun 			atomic_dec(&cardp->tx_cmd_urb_pending);
1660*4882a593Smuzhiyun 		else {
1661*4882a593Smuzhiyun 			if (ep == cardp->tx_data_ep) {
1662*4882a593Smuzhiyun 				atomic_dec(&cardp->tx_data_urb_pending);
1663*4882a593Smuzhiyun 				if (cardp->tx_data_ix)
1664*4882a593Smuzhiyun 					cardp->tx_data_ix--;
1665*4882a593Smuzhiyun 				else
1666*4882a593Smuzhiyun 					cardp->tx_data_ix = MVUSB_TX_HIGH_WMARK;
1667*4882a593Smuzhiyun 			}
1668*4882a593Smuzhiyun 		}
1669*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1670*4882a593Smuzhiyun 	} else {
1671*4882a593Smuzhiyun 		if (ep == cardp->tx_data_ep &&
1672*4882a593Smuzhiyun 		    (atomic_read(&cardp->tx_data_urb_pending) ==
1673*4882a593Smuzhiyun 		     MVUSB_TX_HIGH_WMARK))
1674*4882a593Smuzhiyun 			ret = MLAN_STATUS_PRESOURCE;
1675*4882a593Smuzhiyun 		else
1676*4882a593Smuzhiyun 			ret = MLAN_STATUS_SUCCESS;
1677*4882a593Smuzhiyun 	}
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun tx_ret:
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	if (!ret)
1682*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
1683*4882a593Smuzhiyun 
1684*4882a593Smuzhiyun 	LEAVE();
1685*4882a593Smuzhiyun 	return ret;
1686*4882a593Smuzhiyun }
1687*4882a593Smuzhiyun 
1688*4882a593Smuzhiyun /**
1689*4882a593Smuzhiyun  *  @brief  This function register usb device and initialize parameter
1690*4882a593Smuzhiyun  *
1691*4882a593Smuzhiyun  *  @param handle	Pointer to moal_handle structure
1692*4882a593Smuzhiyun  *
1693*4882a593Smuzhiyun  *  @return 	   	MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1694*4882a593Smuzhiyun  */
woal_usb_register_dev(moal_handle * handle)1695*4882a593Smuzhiyun static mlan_status woal_usb_register_dev(moal_handle *handle)
1696*4882a593Smuzhiyun {
1697*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1698*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun 	ENTER();
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 	cardp->phandle = handle;
1703*4882a593Smuzhiyun 	LEAVE();
1704*4882a593Smuzhiyun 	return ret;
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun 
woal_usb_unregister_dev(moal_handle * handle)1707*4882a593Smuzhiyun static void woal_usb_unregister_dev(moal_handle *handle)
1708*4882a593Smuzhiyun {
1709*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1710*4882a593Smuzhiyun 	PRINTM(MMSG, "USB: unregister device\n");
1711*4882a593Smuzhiyun 	woal_usb_free(cardp);
1712*4882a593Smuzhiyun 	cardp->phandle = NULL;
1713*4882a593Smuzhiyun 	return;
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun 
1716*4882a593Smuzhiyun /**
1717*4882a593Smuzhiyun  *  @brief This function registers driver.
1718*4882a593Smuzhiyun  *
1719*4882a593Smuzhiyun  *  @return 	 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1720*4882a593Smuzhiyun  */
woal_usb_bus_register(void)1721*4882a593Smuzhiyun mlan_status woal_usb_bus_register(void)
1722*4882a593Smuzhiyun {
1723*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1724*4882a593Smuzhiyun 	ENTER();
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	if (skip_fwdnld) {
1727*4882a593Smuzhiyun 		woal_usb_driver.id_table = woal_usb_table_skip_fwdnld;
1728*4882a593Smuzhiyun 	}
1729*4882a593Smuzhiyun 	/*
1730*4882a593Smuzhiyun 	 * API registers the NXP USB driver
1731*4882a593Smuzhiyun 	 * to the USB system
1732*4882a593Smuzhiyun 	 */
1733*4882a593Smuzhiyun 	if (usb_register(&woal_usb_driver)) {
1734*4882a593Smuzhiyun 		PRINTM(MFATAL, "USB Driver Registration Failed \n");
1735*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1736*4882a593Smuzhiyun 	}
1737*4882a593Smuzhiyun 	LEAVE();
1738*4882a593Smuzhiyun 	return ret;
1739*4882a593Smuzhiyun }
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun /**
1742*4882a593Smuzhiyun  *  @brief This function removes usb driver.
1743*4882a593Smuzhiyun  *
1744*4882a593Smuzhiyun  *  @return 	   	N/A
1745*4882a593Smuzhiyun  */
woal_usb_bus_unregister(void)1746*4882a593Smuzhiyun void woal_usb_bus_unregister(void)
1747*4882a593Smuzhiyun {
1748*4882a593Smuzhiyun 	ENTER();
1749*4882a593Smuzhiyun 	/* API unregisters the driver from USB subsystem */
1750*4882a593Smuzhiyun 	usb_deregister(&woal_usb_driver);
1751*4882a593Smuzhiyun 	LEAVE();
1752*4882a593Smuzhiyun 	return;
1753*4882a593Smuzhiyun }
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun /**
1756*4882a593Smuzhiyun  *  @brief This function check if this is second mac
1757*4882a593Smuzhiyun  *
1758*4882a593Smuzhiyun  *  @param handle   A pointer to moal_handle structure
1759*4882a593Smuzhiyun  *  @return         MTRUE/MFALSE
1760*4882a593Smuzhiyun  *
1761*4882a593Smuzhiyun  */
woal_usb_is_second_mac(moal_handle * handle)1762*4882a593Smuzhiyun static t_u8 woal_usb_is_second_mac(moal_handle *handle)
1763*4882a593Smuzhiyun {
1764*4882a593Smuzhiyun 	return ((struct usb_card_rec *)(handle->card))->second_mac;
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun #ifdef CONFIG_USB_SUSPEND
1768*4882a593Smuzhiyun /**
1769*4882a593Smuzhiyun  *  @brief This function makes USB device to suspend.
1770*4882a593Smuzhiyun  *
1771*4882a593Smuzhiyun  *  @param handle  A pointer to moal_handle structure
1772*4882a593Smuzhiyun  *
1773*4882a593Smuzhiyun  *  @return             0 --success, otherwise fail
1774*4882a593Smuzhiyun  */
woal_enter_usb_suspend(moal_handle * handle)1775*4882a593Smuzhiyun int woal_enter_usb_suspend(moal_handle *handle)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun 	struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
1778*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1779*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1780*4882a593Smuzhiyun 	struct usb_interface *intf =
1781*4882a593Smuzhiyun 		((struct usb_card_rec *)(handle->card))->intf;
1782*4882a593Smuzhiyun #endif /* < 2.6.34 */
1783*4882a593Smuzhiyun #endif /* >= 2.6.24 */
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun 	ENTER();
1786*4882a593Smuzhiyun 
1787*4882a593Smuzhiyun 	PRINTM(MIOCTL, "USB suspend ioctl (state %d)\n", udev->state);
1788*4882a593Smuzhiyun 
1789*4882a593Smuzhiyun 	if (handle->is_suspended == MTRUE) {
1790*4882a593Smuzhiyun 		PRINTM(MERROR, "Device already suspended\n");
1791*4882a593Smuzhiyun 		LEAVE();
1792*4882a593Smuzhiyun 		return -EFAULT;
1793*4882a593Smuzhiyun 	}
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	handle->suspend_wait_q_woken = MFALSE;
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1798*4882a593Smuzhiyun 	/* Enter into USB suspend */
1799*4882a593Smuzhiyun 	usb_lock_device(udev);
1800*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
1801*4882a593Smuzhiyun 	udev->autosuspend_delay = 0; /* Autosuspend delay in jiffies */
1802*4882a593Smuzhiyun #else
1803*4882a593Smuzhiyun 	pm_runtime_set_autosuspend_delay(&udev->dev, 0); /* Autosuspend delay in
1804*4882a593Smuzhiyun 							    jiffies */
1805*4882a593Smuzhiyun #endif /* < 2.6.38 */
1806*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1807*4882a593Smuzhiyun 	udev->autosuspend_disabled = 0; /* /sys/bus/usb/devices/.../power/level
1808*4882a593Smuzhiyun 					   < auto */
1809*4882a593Smuzhiyun #endif /* < 2.6.34 */
1810*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
1811*4882a593Smuzhiyun 	udev->autoresume_disabled = 0;
1812*4882a593Smuzhiyun #endif /* < 2.6.33 */
1813*4882a593Smuzhiyun 	usb_unlock_device(udev);
1814*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1815*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
1816*4882a593Smuzhiyun 	intf->pm_usage_cnt = 1;
1817*4882a593Smuzhiyun #else
1818*4882a593Smuzhiyun 	atomic_set(&intf->pm_usage_cnt, 1);
1819*4882a593Smuzhiyun #endif /* < 2.6.32 */
1820*4882a593Smuzhiyun 	usb_autopm_put_interface(intf);
1821*4882a593Smuzhiyun #else
1822*4882a593Smuzhiyun 	usb_lock_device(udev);
1823*4882a593Smuzhiyun 	atomic_set(&udev->dev.power.usage_count, 1);
1824*4882a593Smuzhiyun 	usb_enable_autosuspend(udev);
1825*4882a593Smuzhiyun 	usb_unlock_device(udev);
1826*4882a593Smuzhiyun #endif /* < 2.6.34 */
1827*4882a593Smuzhiyun #endif /* >= 2.6.24 */
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun 	/* Wait for suspend to complete */
1830*4882a593Smuzhiyun 	wait_event_interruptible(handle->suspend_wait_q,
1831*4882a593Smuzhiyun 				 handle->suspend_wait_q_woken);
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	LEAVE();
1834*4882a593Smuzhiyun 	return 0;
1835*4882a593Smuzhiyun }
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun /**
1838*4882a593Smuzhiyun  *  @brief This function makes USB device to resume.
1839*4882a593Smuzhiyun  *
1840*4882a593Smuzhiyun  *  @param handle  A pointer to moal_handle structure
1841*4882a593Smuzhiyun  *
1842*4882a593Smuzhiyun  *  @return             0 --success, otherwise fail
1843*4882a593Smuzhiyun  */
woal_exit_usb_suspend(moal_handle * handle)1844*4882a593Smuzhiyun int woal_exit_usb_suspend(moal_handle *handle)
1845*4882a593Smuzhiyun {
1846*4882a593Smuzhiyun 	struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
1847*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1848*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1849*4882a593Smuzhiyun 	struct usb_interface *intf =
1850*4882a593Smuzhiyun 		((struct usb_card_rec *)(handle->card))->intf;
1851*4882a593Smuzhiyun #endif /* < 2.6.34 */
1852*4882a593Smuzhiyun #endif /* >= 2.6.24 */
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun 	ENTER();
1855*4882a593Smuzhiyun 
1856*4882a593Smuzhiyun 	PRINTM(MIOCTL, "USB resume ioctl (state %d)\n", udev->state);
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun 	if (handle->is_suspended == MFALSE ||
1859*4882a593Smuzhiyun 	    udev->state != USB_STATE_SUSPENDED) {
1860*4882a593Smuzhiyun 		PRINTM(MERROR, "Device already resumed\n");
1861*4882a593Smuzhiyun 		LEAVE();
1862*4882a593Smuzhiyun 		return -EFAULT;
1863*4882a593Smuzhiyun 	}
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1866*4882a593Smuzhiyun 	/* Exit from USB suspend */
1867*4882a593Smuzhiyun 	usb_lock_device(udev);
1868*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1869*4882a593Smuzhiyun 	udev->autosuspend_disabled = 1; /* /sys/bus/usb/devices/.../power/level
1870*4882a593Smuzhiyun 					   < on */
1871*4882a593Smuzhiyun #endif /* < 2.6.34 */
1872*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
1873*4882a593Smuzhiyun 	udev->autoresume_disabled = 0;
1874*4882a593Smuzhiyun #endif /* < 2.6.33 */
1875*4882a593Smuzhiyun 	usb_unlock_device(udev);
1876*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1877*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
1878*4882a593Smuzhiyun 	intf->pm_usage_cnt = 0;
1879*4882a593Smuzhiyun #else
1880*4882a593Smuzhiyun 	atomic_set(&intf->pm_usage_cnt, 0);
1881*4882a593Smuzhiyun #endif /* < 2.6.32 */
1882*4882a593Smuzhiyun 	usb_autopm_get_interface(intf);
1883*4882a593Smuzhiyun #else
1884*4882a593Smuzhiyun 	usb_lock_device(udev);
1885*4882a593Smuzhiyun 	atomic_set(&udev->dev.power.usage_count, 0);
1886*4882a593Smuzhiyun 	usb_disable_autosuspend(udev);
1887*4882a593Smuzhiyun 	usb_unlock_device(udev);
1888*4882a593Smuzhiyun #endif /* < 2.6.34 */
1889*4882a593Smuzhiyun #endif /* >= 2.6.24 */
1890*4882a593Smuzhiyun 
1891*4882a593Smuzhiyun 	LEAVE();
1892*4882a593Smuzhiyun 	return 0;
1893*4882a593Smuzhiyun }
1894*4882a593Smuzhiyun #endif /* CONFIG_USB_SUSPEND */
1895*4882a593Smuzhiyun 
1896*4882a593Smuzhiyun /**
1897*4882a593Smuzhiyun  *  @brief This function will submit rx urb.
1898*4882a593Smuzhiyun  *
1899*4882a593Smuzhiyun  *  @param handle   Pointer to moal_handle
1900*4882a593Smuzhiyun  *  @param ep       Endpoint to re-submit urb
1901*4882a593Smuzhiyun  *
1902*4882a593Smuzhiyun  *  @return 	   	N/A
1903*4882a593Smuzhiyun  */
woal_submit_rx_urb(moal_handle * handle,t_u8 ep)1904*4882a593Smuzhiyun void woal_submit_rx_urb(moal_handle *handle, t_u8 ep)
1905*4882a593Smuzhiyun {
1906*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	ENTER();
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	if ((ep == cardp->rx_cmd_ep) &&
1911*4882a593Smuzhiyun 	    (!atomic_read(&cardp->rx_cmd_urb_pending))) {
1912*4882a593Smuzhiyun 		woal_usb_submit_rx_urb(&cardp->rx_cmd, MLAN_RX_CMD_BUF_SIZE);
1913*4882a593Smuzhiyun 	}
1914*4882a593Smuzhiyun 
1915*4882a593Smuzhiyun 	LEAVE();
1916*4882a593Smuzhiyun 	return;
1917*4882a593Smuzhiyun }
1918*4882a593Smuzhiyun 
1919*4882a593Smuzhiyun /**
1920*4882a593Smuzhiyun  *  @brief This function dump firmware memory to file
1921*4882a593Smuzhiyun  *
1922*4882a593Smuzhiyun  *  @param phandle   A pointer to moal_handle
1923*4882a593Smuzhiyun  *
1924*4882a593Smuzhiyun  *  @return         N/A
1925*4882a593Smuzhiyun  */
woal_usb_dump_fw_info(moal_handle * phandle)1926*4882a593Smuzhiyun static void woal_usb_dump_fw_info(moal_handle *phandle)
1927*4882a593Smuzhiyun {
1928*4882a593Smuzhiyun 	moal_private *priv = NULL;
1929*4882a593Smuzhiyun 	mlan_ioctl_req *req = NULL;
1930*4882a593Smuzhiyun 	mlan_ds_misc_cfg *pcfg_misc = NULL;
1931*4882a593Smuzhiyun 	mlan_status status = MLAN_STATUS_SUCCESS;
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun 	ENTER();
1934*4882a593Smuzhiyun 
1935*4882a593Smuzhiyun 	priv = woal_get_priv(phandle, MLAN_BSS_ROLE_ANY);
1936*4882a593Smuzhiyun 	if (!priv) {
1937*4882a593Smuzhiyun 		PRINTM(MERROR, "woal_usb_dump_fw_info: priv is NULL!\n");
1938*4882a593Smuzhiyun 		goto done;
1939*4882a593Smuzhiyun 	}
1940*4882a593Smuzhiyun 	/* Allocate an IOCTL request buffer */
1941*4882a593Smuzhiyun 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1942*4882a593Smuzhiyun 	if (req == NULL) {
1943*4882a593Smuzhiyun 		PRINTM(MERROR, "woal_usb_dump_fw_info: alloc req fail!\n");
1944*4882a593Smuzhiyun 		goto done;
1945*4882a593Smuzhiyun 	}
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun 	/* Fill request buffer */
1948*4882a593Smuzhiyun 	pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
1949*4882a593Smuzhiyun 	pcfg_misc->sub_command = MLAN_OID_MISC_FW_DUMP_EVENT;
1950*4882a593Smuzhiyun 	req->req_id = MLAN_IOCTL_MISC_CFG;
1951*4882a593Smuzhiyun 	req->action = MLAN_ACT_GET;
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun 	/* Send IOCTL request to MLAN */
1954*4882a593Smuzhiyun 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	if (status != MLAN_STATUS_PENDING)
1957*4882a593Smuzhiyun 		kfree(req);
1958*4882a593Smuzhiyun 	phandle->is_fw_dump_timer_set = MTRUE;
1959*4882a593Smuzhiyun 	woal_mod_timer(&phandle->fw_dump_timer, MOAL_TIMER_5S);
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun done:
1962*4882a593Smuzhiyun 	LEAVE();
1963*4882a593Smuzhiyun 	return;
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun 
woal_usb_get_fw_name(moal_handle * handle)1966*4882a593Smuzhiyun static mlan_status woal_usb_get_fw_name(moal_handle *handle)
1967*4882a593Smuzhiyun {
1968*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1969*4882a593Smuzhiyun #if defined(USB8997) || defined(USB9098) || defined(USB9097) ||                \
1970*4882a593Smuzhiyun 	defined(USB8978) || defined(USBNW62X)
1971*4882a593Smuzhiyun 	t_u32 revision_id = 0;
1972*4882a593Smuzhiyun 	t_u32 strap = 0;
1973*4882a593Smuzhiyun #endif
1974*4882a593Smuzhiyun 	struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
1975*4882a593Smuzhiyun #if defined(USB9098)
1976*4882a593Smuzhiyun 	moal_handle *ref_handle = NULL;
1977*4882a593Smuzhiyun #endif
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 	ENTER();
1980*4882a593Smuzhiyun 	if (handle->params.fw_name)
1981*4882a593Smuzhiyun 		goto done;
1982*4882a593Smuzhiyun 	if (cardp->boot_state == USB_FW_READY)
1983*4882a593Smuzhiyun 		goto done;
1984*4882a593Smuzhiyun #ifdef USB8801
1985*4882a593Smuzhiyun 	if (IS_USB8801(handle->card_type))
1986*4882a593Smuzhiyun 		goto done;
1987*4882a593Smuzhiyun #endif
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun #if defined(USB8997) || defined(USB9098) || defined(USB9097) ||                \
1990*4882a593Smuzhiyun 	defined(USB8978) || defined(USBNW62X)
1991*4882a593Smuzhiyun 	ret = woal_check_chip_revision(handle, &revision_id, &strap);
1992*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
1993*4882a593Smuzhiyun 		PRINTM(MFATAL, "Chip revision check failure!\n");
1994*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1995*4882a593Smuzhiyun 		goto done;
1996*4882a593Smuzhiyun 	}
1997*4882a593Smuzhiyun 	PRINTM(MCMND, "revision=0x%x, strap=0x%x\n", revision_id, strap);
1998*4882a593Smuzhiyun #endif
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun #ifdef USB8997
2001*4882a593Smuzhiyun 	if (IS_USB8997(handle->card_type)) {
2002*4882a593Smuzhiyun 		if (strap == CARD_TYPE_USB_UART)
2003*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name,
2004*4882a593Smuzhiyun 			       USBUART8997_DEFAULT_COMBO_FW_NAME);
2005*4882a593Smuzhiyun 		else if (strap != 0)
2006*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name,
2007*4882a593Smuzhiyun 			       USBUSB8997_DEFAULT_COMBO_FW_NAME);
2008*4882a593Smuzhiyun 	}
2009*4882a593Smuzhiyun #endif
2010*4882a593Smuzhiyun 
2011*4882a593Smuzhiyun #ifdef USB8978
2012*4882a593Smuzhiyun 	if (IS_USB8978(handle->card_type)) {
2013*4882a593Smuzhiyun 		if (strap == CARD_TYPE_USB_UART)
2014*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name,
2015*4882a593Smuzhiyun 			       USBUART8978_DEFAULT_COMBO_FW_NAME);
2016*4882a593Smuzhiyun 		else if (strap != 0)
2017*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name,
2018*4882a593Smuzhiyun 			       USBUSB8978_DEFAULT_COMBO_FW_NAME);
2019*4882a593Smuzhiyun 	}
2020*4882a593Smuzhiyun #endif
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun #ifdef USB9098
2023*4882a593Smuzhiyun 	if (IS_USB9098(handle->card_type)) {
2024*4882a593Smuzhiyun 		if (cardp->second_mac) {
2025*4882a593Smuzhiyun 			ref_handle = (moal_handle *)handle->pref_mac;
2026*4882a593Smuzhiyun 			if (ref_handle) {
2027*4882a593Smuzhiyun 				strcpy(handle->card_info->fw_name,
2028*4882a593Smuzhiyun 				       ref_handle->card_info->fw_name);
2029*4882a593Smuzhiyun 				strcpy(handle->card_info->fw_name_wlan,
2030*4882a593Smuzhiyun 				       ref_handle->card_info->fw_name_wlan);
2031*4882a593Smuzhiyun 			}
2032*4882a593Smuzhiyun 			goto done;
2033*4882a593Smuzhiyun 		}
2034*4882a593Smuzhiyun 		switch (revision_id) {
2035*4882a593Smuzhiyun 		case USB9098_Z1Z2:
2036*4882a593Smuzhiyun 			if (strap != 0) {
2037*4882a593Smuzhiyun 				if (strap == CARD_TYPE_USB_UART)
2038*4882a593Smuzhiyun 					strcpy(handle->card_info->fw_name,
2039*4882a593Smuzhiyun 					       USBUART9098_DEFAULT_COMBO_FW_NAME);
2040*4882a593Smuzhiyun 				else
2041*4882a593Smuzhiyun 					strcpy(handle->card_info->fw_name,
2042*4882a593Smuzhiyun 					       USBUSB9098_DEFAULT_COMBO_FW_NAME);
2043*4882a593Smuzhiyun 			}
2044*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name_wlan,
2045*4882a593Smuzhiyun 			       USB9098_DEFAULT_WLAN_FW_NAME);
2046*4882a593Smuzhiyun 			break;
2047*4882a593Smuzhiyun 		case USB9098_A0:
2048*4882a593Smuzhiyun 		case USB9098_A1:
2049*4882a593Smuzhiyun 		case USB9098_A2:
2050*4882a593Smuzhiyun 			if (strap != 0) {
2051*4882a593Smuzhiyun 				if (strap == CARD_TYPE_USB_UART)
2052*4882a593Smuzhiyun 					strcpy(handle->card_info->fw_name,
2053*4882a593Smuzhiyun 					       USBUART9098_COMBO_V1_FW_NAME);
2054*4882a593Smuzhiyun 				else
2055*4882a593Smuzhiyun 					strcpy(handle->card_info->fw_name,
2056*4882a593Smuzhiyun 					       USBUSB9098_COMBO_V1_FW_NAME);
2057*4882a593Smuzhiyun 			}
2058*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name_wlan,
2059*4882a593Smuzhiyun 			       USB9098_WLAN_V1_FW_NAME);
2060*4882a593Smuzhiyun 			break;
2061*4882a593Smuzhiyun 		}
2062*4882a593Smuzhiyun 	}
2063*4882a593Smuzhiyun #endif
2064*4882a593Smuzhiyun #ifdef USB9097
2065*4882a593Smuzhiyun 	if (IS_USB9097(handle->card_type)) {
2066*4882a593Smuzhiyun 		switch (revision_id) {
2067*4882a593Smuzhiyun 		case USB9097_B0:
2068*4882a593Smuzhiyun 		case USB9097_B1:
2069*4882a593Smuzhiyun 			if (strap != 0) {
2070*4882a593Smuzhiyun 				if (strap == CARD_TYPE_USB_UART)
2071*4882a593Smuzhiyun 					strcpy(handle->card_info->fw_name,
2072*4882a593Smuzhiyun 					       USBUART9097_COMBO_V1_FW_NAME);
2073*4882a593Smuzhiyun 				else
2074*4882a593Smuzhiyun 					strcpy(handle->card_info->fw_name,
2075*4882a593Smuzhiyun 					       USBUSB9097_COMBO_V1_FW_NAME);
2076*4882a593Smuzhiyun 			}
2077*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name_wlan,
2078*4882a593Smuzhiyun 			       USB9097_WLAN_V1_FW_NAME);
2079*4882a593Smuzhiyun 			break;
2080*4882a593Smuzhiyun 		}
2081*4882a593Smuzhiyun 	}
2082*4882a593Smuzhiyun #endif
2083*4882a593Smuzhiyun #ifdef USBNW62X
2084*4882a593Smuzhiyun 	if (IS_USBNW62X(handle->card_type)) {
2085*4882a593Smuzhiyun 		if (strap == CARD_TYPE_USB_UART)
2086*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name,
2087*4882a593Smuzhiyun 			       USBUARTNW62X_COMBO_FW_NAME);
2088*4882a593Smuzhiyun 		else
2089*4882a593Smuzhiyun 			strcpy(handle->card_info->fw_name,
2090*4882a593Smuzhiyun 			       USBUSBNW62X_COMBO_FW_NAME);
2091*4882a593Smuzhiyun 	}
2092*4882a593Smuzhiyun #endif
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun done:
2095*4882a593Smuzhiyun 	PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
2096*4882a593Smuzhiyun 	       handle->card_info->fw_name_wlan);
2097*4882a593Smuzhiyun 	LEAVE();
2098*4882a593Smuzhiyun 	return ret;
2099*4882a593Smuzhiyun }
2100*4882a593Smuzhiyun 
2101*4882a593Smuzhiyun static moal_if_ops usb_ops = {
2102*4882a593Smuzhiyun 	.register_dev = woal_usb_register_dev,
2103*4882a593Smuzhiyun 	.unregister_dev = woal_usb_unregister_dev,
2104*4882a593Smuzhiyun 	.read_data_sync = woal_usb_read_data_sync,
2105*4882a593Smuzhiyun 	.write_data_sync = woal_usb_write_data_sync,
2106*4882a593Smuzhiyun 	.get_fw_name = woal_usb_get_fw_name,
2107*4882a593Smuzhiyun 	.dump_fw_info = woal_usb_dump_fw_info,
2108*4882a593Smuzhiyun 	.is_second_mac = woal_usb_is_second_mac,
2109*4882a593Smuzhiyun };
2110