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