Commit | Line | Data |
---|---|---|
b1925ad8 LF |
1 | /****************************************************************************** |
2 | * | |
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | ******************************************************************************/ | |
15 | #define _HCI_INTF_C_ | |
16 | ||
17 | #include <osdep_service.h> | |
18 | #include <drv_types.h> | |
19 | #include <recv_osdep.h> | |
20 | #include <xmit_osdep.h> | |
21 | #include <hal_intf.h> | |
22 | #include <rtw_version.h> | |
23 | #include <osdep_intf.h> | |
b1925ad8 | 24 | #include <usb_ops.h> |
1f4746f1 | 25 | #include <rtl8723a_hal.h> |
b1925ad8 LF |
26 | |
27 | static int rtw_suspend(struct usb_interface *intf, pm_message_t message); | |
28 | static int rtw_resume(struct usb_interface *intf); | |
29 | static int rtw_drv_init(struct usb_interface *pusb_intf, | |
30 | const struct usb_device_id *pdid); | |
31 | static void rtw_disconnect(struct usb_interface *pusb_intf); | |
32 | ||
33 | #define USB_VENDER_ID_REALTEK 0x0BDA | |
34 | ||
35 | #define RTL8723A_USB_IDS \ | |
36 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x8724, \ | |
37 | 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \ | |
38 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x1724, \ | |
39 | 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \ | |
40 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0724, \ | |
41 | 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ | |
42 | ||
43 | static struct usb_device_id rtl8723a_usb_id_tbl[] = { | |
44 | RTL8723A_USB_IDS | |
45 | {} /* Terminating entry */ | |
46 | }; | |
47 | ||
48 | MODULE_DEVICE_TABLE(usb, rtl8723a_usb_id_tbl); | |
49 | ||
50 | static struct usb_driver rtl8723a_usb_drv = { | |
51 | .name = (char *)"rtl8723au", | |
52 | .probe = rtw_drv_init, | |
53 | .disconnect = rtw_disconnect, | |
54 | .id_table = rtl8723a_usb_id_tbl, | |
55 | .suspend = rtw_suspend, | |
56 | .resume = rtw_resume, | |
57 | .reset_resume = rtw_resume, | |
58 | }; | |
59 | ||
60 | static struct usb_driver *usb_drv = &rtl8723a_usb_drv; | |
61 | ||
62 | static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) | |
63 | { | |
64 | return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; | |
65 | } | |
66 | ||
67 | static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) | |
68 | { | |
69 | return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; | |
70 | } | |
71 | ||
72 | static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) | |
73 | { | |
74 | return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT; | |
75 | } | |
76 | ||
77 | static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) | |
78 | { | |
79 | return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK; | |
80 | } | |
81 | ||
82 | static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) | |
83 | { | |
84 | return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd); | |
85 | } | |
86 | ||
87 | static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) | |
88 | { | |
89 | return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd); | |
90 | } | |
91 | ||
92 | static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) | |
93 | { | |
94 | return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd); | |
95 | } | |
96 | ||
97 | static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) | |
98 | { | |
99 | return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | |
100 | } | |
101 | ||
86c3e3f1 | 102 | static int rtw_init_intf_priv(struct dvobj_priv *dvobj) |
b1925ad8 | 103 | { |
b1925ad8 | 104 | mutex_init(&dvobj->usb_vendor_req_mutex); |
2786faa3 JS |
105 | |
106 | return _SUCCESS; | |
b1925ad8 LF |
107 | } |
108 | ||
86c3e3f1 | 109 | static int rtw_deinit_intf_priv(struct dvobj_priv *dvobj) |
b1925ad8 | 110 | { |
b1925ad8 LF |
111 | mutex_destroy(&dvobj->usb_vendor_req_mutex); |
112 | ||
2786faa3 | 113 | return _SUCCESS; |
b1925ad8 LF |
114 | } |
115 | ||
116 | static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) | |
117 | { | |
118 | struct dvobj_priv *pdvobjpriv; | |
119 | struct usb_device_descriptor *pdev_desc; | |
120 | struct usb_host_config *phost_conf; | |
121 | struct usb_config_descriptor *pconf_desc; | |
122 | struct usb_host_interface *phost_iface; | |
123 | struct usb_interface_descriptor *piface_desc; | |
124 | struct usb_host_endpoint *phost_endp; | |
125 | struct usb_endpoint_descriptor *pendp_desc; | |
126 | struct usb_device *pusbd; | |
127 | int i; | |
128 | int status = _FAIL; | |
129 | ||
130 | pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); | |
131 | if (!pdvobjpriv) | |
132 | goto exit; | |
133 | ||
134 | mutex_init(&pdvobjpriv->hw_init_mutex); | |
135 | mutex_init(&pdvobjpriv->h2c_fwcmd_mutex); | |
136 | mutex_init(&pdvobjpriv->setch_mutex); | |
137 | mutex_init(&pdvobjpriv->setbw_mutex); | |
138 | ||
139 | pdvobjpriv->pusbintf = usb_intf; | |
140 | pusbd = interface_to_usbdev(usb_intf); | |
141 | pdvobjpriv->pusbdev = pusbd; | |
142 | usb_set_intfdata(usb_intf, pdvobjpriv); | |
143 | ||
144 | pdvobjpriv->RtNumInPipes = 0; | |
145 | pdvobjpriv->RtNumOutPipes = 0; | |
146 | ||
147 | pdev_desc = &pusbd->descriptor; | |
148 | ||
149 | phost_conf = pusbd->actconfig; | |
150 | pconf_desc = &phost_conf->desc; | |
151 | ||
152 | phost_iface = &usb_intf->altsetting[0]; | |
153 | piface_desc = &phost_iface->desc; | |
154 | ||
155 | pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces; | |
156 | pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber; | |
157 | pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; | |
158 | ||
159 | for (i = 0; i < pdvobjpriv->nr_endpoint; i++) { | |
160 | phost_endp = phost_iface->endpoint + i; | |
161 | if (phost_endp) { | |
162 | pendp_desc = &phost_endp->desc; | |
163 | ||
164 | DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i); | |
165 | DBG_8723A("bLength =%x\n", pendp_desc->bLength); | |
166 | DBG_8723A("bDescriptorType =%x\n", | |
167 | pendp_desc->bDescriptorType); | |
168 | DBG_8723A("bEndpointAddress =%x\n", | |
169 | pendp_desc->bEndpointAddress); | |
170 | DBG_8723A("wMaxPacketSize =%d\n", | |
171 | le16_to_cpu(pendp_desc->wMaxPacketSize)); | |
172 | DBG_8723A("bInterval =%x\n", pendp_desc->bInterval); | |
173 | ||
174 | if (RT_usb_endpoint_is_bulk_in(pendp_desc)) { | |
175 | DBG_8723A("RT_usb_endpoint_is_bulk_in = %x\n", | |
176 | RT_usb_endpoint_num(pendp_desc)); | |
177 | pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = | |
178 | RT_usb_endpoint_num(pendp_desc); | |
179 | pdvobjpriv->RtNumInPipes++; | |
180 | } else if (RT_usb_endpoint_is_int_in(pendp_desc)) { | |
181 | DBG_8723A("RT_usb_endpoint_is_int_in = %x, Interval = %x\n", | |
182 | RT_usb_endpoint_num(pendp_desc), | |
183 | pendp_desc->bInterval); | |
184 | pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = | |
185 | RT_usb_endpoint_num(pendp_desc); | |
186 | pdvobjpriv->RtNumInPipes++; | |
187 | } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) { | |
188 | DBG_8723A("RT_usb_endpoint_is_bulk_out = %x\n", | |
189 | RT_usb_endpoint_num(pendp_desc)); | |
190 | pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = | |
191 | RT_usb_endpoint_num(pendp_desc); | |
192 | pdvobjpriv->RtNumOutPipes++; | |
193 | } | |
194 | pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc); | |
195 | } | |
196 | } | |
197 | DBG_8723A("nr_endpoint =%d, in_num =%d, out_num =%d\n\n", | |
198 | pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, | |
199 | pdvobjpriv->RtNumOutPipes); | |
200 | ||
201 | if (pusbd->speed == USB_SPEED_HIGH) { | |
202 | pdvobjpriv->ishighspeed = true; | |
203 | DBG_8723A("USB_SPEED_HIGH\n"); | |
204 | } else { | |
205 | pdvobjpriv->ishighspeed = false; | |
206 | DBG_8723A("NON USB_SPEED_HIGH\n"); | |
207 | } | |
208 | ||
209 | if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) { | |
210 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | |
211 | ("\n Can't INIT rtw_init_intf_priv\n")); | |
212 | goto free_dvobj; | |
213 | } | |
214 | /* 3 misc */ | |
b1925ad8 LF |
215 | rtw_reset_continual_urb_error(pdvobjpriv); |
216 | usb_get_dev(pusbd); | |
217 | status = _SUCCESS; | |
218 | free_dvobj: | |
219 | if (status != _SUCCESS && pdvobjpriv) { | |
220 | usb_set_intfdata(usb_intf, NULL); | |
221 | mutex_destroy(&pdvobjpriv->hw_init_mutex); | |
222 | mutex_destroy(&pdvobjpriv->h2c_fwcmd_mutex); | |
223 | mutex_destroy(&pdvobjpriv->setch_mutex); | |
224 | mutex_destroy(&pdvobjpriv->setbw_mutex); | |
225 | kfree(pdvobjpriv); | |
226 | pdvobjpriv = NULL; | |
227 | } | |
228 | exit: | |
229 | return pdvobjpriv; | |
230 | } | |
231 | ||
232 | static void usb_dvobj_deinit(struct usb_interface *usb_intf) | |
233 | { | |
234 | struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); | |
235 | ||
236 | usb_set_intfdata(usb_intf, NULL); | |
237 | if (dvobj) { | |
238 | /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */ | |
239 | if ((dvobj->NumInterfaces != 2 && dvobj->NumInterfaces != 3) || | |
240 | (dvobj->InterfaceNumber == 1)) { | |
241 | if (interface_to_usbdev(usb_intf)->state != | |
242 | USB_STATE_NOTATTACHED) { | |
243 | /* If we didn't unplug usb dongle and | |
244 | * remove/insert module, driver fails on | |
245 | * sitesurvey for the first time when | |
246 | * device is up . | |
247 | * Reset usb port for sitesurvey fail issue. | |
248 | */ | |
249 | DBG_8723A("usb attached..., try to reset usb device\n"); | |
250 | usb_reset_device(interface_to_usbdev(usb_intf)); | |
251 | } | |
252 | } | |
253 | rtw_deinit_intf_priv(dvobj); | |
254 | mutex_destroy(&dvobj->hw_init_mutex); | |
255 | mutex_destroy(&dvobj->h2c_fwcmd_mutex); | |
256 | mutex_destroy(&dvobj->setch_mutex); | |
257 | mutex_destroy(&dvobj->setbw_mutex); | |
258 | kfree(dvobj); | |
259 | } | |
260 | usb_put_dev(interface_to_usbdev(usb_intf)); | |
261 | } | |
262 | ||
596f85ad | 263 | void rtl8723a_usb_intf_stop(struct rtw_adapter *padapter) |
b1925ad8 LF |
264 | { |
265 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_stop\n")); | |
266 | ||
267 | /* disable_hw_interrupt */ | |
268 | if (!padapter->bSurpriseRemoved) { | |
269 | /* device still exists, so driver can do i/o operation | |
270 | * TODO: | |
271 | */ | |
272 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | |
273 | ("SurpriseRemoved == false\n")); | |
274 | } | |
275 | ||
276 | /* cancel in irp */ | |
1aaa3761 | 277 | rtl8723au_inirp_deinit(padapter); |
b1925ad8 LF |
278 | |
279 | /* cancel out irp */ | |
68552a90 | 280 | rtl8723au_write_port_cancel(padapter); |
b1925ad8 LF |
281 | |
282 | /* todo:cancel other irps */ | |
283 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_stop\n")); | |
284 | } | |
285 | ||
286 | static void rtw_dev_unload(struct rtw_adapter *padapter) | |
287 | { | |
288 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n")); | |
289 | ||
290 | if (padapter->bup) { | |
291 | DBG_8723A("===> rtw_dev_unload\n"); | |
292 | ||
293 | padapter->bDriverStopped = true; | |
294 | if (padapter->xmitpriv.ack_tx) | |
295 | rtw_ack_tx_done23a(&padapter->xmitpriv, | |
296 | RTW_SCTX_DONE_DRV_STOP); | |
297 | ||
298 | /* s3. */ | |
596f85ad | 299 | rtl8723a_usb_intf_stop(padapter); |
b1925ad8 LF |
300 | |
301 | /* s4. */ | |
32dfcb1b | 302 | flush_workqueue(padapter->cmdpriv.wq); |
b1925ad8 LF |
303 | |
304 | /* s5. */ | |
305 | if (!padapter->bSurpriseRemoved) { | |
dc20d1da | 306 | rtl8723au_hal_deinit(padapter); |
b1925ad8 LF |
307 | padapter->bSurpriseRemoved = true; |
308 | } | |
309 | padapter->bup = false; | |
310 | } else { | |
311 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | |
312 | ("r871x_dev_unload():padapter->bup == false\n")); | |
313 | } | |
314 | DBG_8723A("<=== rtw_dev_unload\n"); | |
315 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n")); | |
316 | } | |
317 | ||
318 | int rtw_hw_suspend23a(struct rtw_adapter *padapter) | |
319 | { | |
320 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
321 | struct net_device *pnetdev = padapter->pnetdev; | |
90102edc | 322 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
b1925ad8 LF |
323 | |
324 | if ((!padapter->bup) || (padapter->bDriverStopped) || | |
325 | (padapter->bSurpriseRemoved)) { | |
326 | DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", | |
327 | padapter->bup, padapter->bDriverStopped, | |
328 | padapter->bSurpriseRemoved); | |
329 | goto error_exit; | |
330 | } | |
331 | ||
332 | if (padapter) { /* system suspend */ | |
333 | LeaveAllPowerSaveMode23a(padapter); | |
334 | ||
335 | DBG_8723A("==> rtw_hw_suspend23a\n"); | |
336 | down(&pwrpriv->lock); | |
337 | pwrpriv->bips_processing = true; | |
338 | /* padapter->net_closed = true; */ | |
339 | /* s1. */ | |
340 | if (pnetdev) { | |
341 | netif_carrier_off(pnetdev); | |
342 | netif_tx_stop_all_queues(pnetdev); | |
343 | } | |
344 | ||
345 | /* s2. */ | |
346 | rtw_disassoc_cmd23a(padapter, 500, false); | |
347 | ||
348 | /* s2-2. indicate disconnect to os */ | |
349 | /* rtw_indicate_disconnect23a(padapter); */ | |
90102edc JS |
350 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { |
351 | _clr_fwstate_(pmlmepriv, _FW_LINKED); | |
b1925ad8 | 352 | |
90102edc | 353 | rtw_led_control(padapter, LED_CTL_NO_LINK); |
b1925ad8 | 354 | |
90102edc | 355 | rtw_os_indicate_disconnect23a(padapter); |
b1925ad8 | 356 | |
90102edc JS |
357 | /* donnot enqueue cmd */ |
358 | rtw_lps_ctrl_wk_cmd23a(padapter, | |
359 | LPS_CTRL_DISCONNECT, 0); | |
b1925ad8 LF |
360 | } |
361 | /* s2-3. */ | |
362 | rtw_free_assoc_resources23a(padapter, 1); | |
363 | ||
364 | /* s2-4. */ | |
528e5c1d | 365 | rtw_free_network_queue23a(padapter); |
b1925ad8 LF |
366 | rtw_ips_dev_unload23a(padapter); |
367 | pwrpriv->rf_pwrstate = rf_off; | |
368 | pwrpriv->bips_processing = false; | |
369 | up(&pwrpriv->lock); | |
370 | } else { | |
371 | goto error_exit; | |
372 | } | |
373 | return 0; | |
374 | error_exit: | |
375 | DBG_8723A("%s, failed\n", __func__); | |
376 | return -1; | |
377 | } | |
378 | ||
379 | int rtw_hw_resume23a(struct rtw_adapter *padapter) | |
380 | { | |
381 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
382 | struct net_device *pnetdev = padapter->pnetdev; | |
383 | ||
384 | if (padapter) { /* system resume */ | |
385 | DBG_8723A("==> rtw_hw_resume23a\n"); | |
386 | down(&pwrpriv->lock); | |
387 | pwrpriv->bips_processing = true; | |
388 | rtw_reset_drv_sw23a(padapter); | |
389 | ||
390 | if (pm_netdev_open23a(pnetdev, false)) { | |
391 | up(&pwrpriv->lock); | |
392 | goto error_exit; | |
393 | } | |
394 | ||
395 | netif_device_attach(pnetdev); | |
396 | netif_carrier_on(pnetdev); | |
397 | ||
398 | if (!rtw_netif_queue_stopped(pnetdev)) | |
399 | netif_tx_start_all_queues(pnetdev); | |
400 | else | |
401 | netif_tx_wake_all_queues(pnetdev); | |
402 | ||
403 | pwrpriv->bkeepfwalive = false; | |
b1925ad8 LF |
404 | |
405 | pwrpriv->rf_pwrstate = rf_on; | |
406 | pwrpriv->bips_processing = false; | |
407 | ||
408 | up(&pwrpriv->lock); | |
409 | } else { | |
410 | goto error_exit; | |
411 | } | |
412 | return 0; | |
413 | error_exit: | |
414 | DBG_8723A("%s, Open net dev failed\n", __func__); | |
415 | return -1; | |
416 | } | |
417 | ||
418 | static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) | |
419 | { | |
420 | struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); | |
421 | struct rtw_adapter *padapter = dvobj->if1; | |
422 | struct net_device *pnetdev = padapter->pnetdev; | |
423 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
424 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
425 | int ret = 0; | |
426 | unsigned long start_time = jiffies; | |
427 | ||
428 | DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid); | |
429 | ||
430 | if ((!padapter->bup) || (padapter->bDriverStopped) || | |
431 | (padapter->bSurpriseRemoved)) { | |
432 | DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", | |
433 | padapter->bup, padapter->bDriverStopped, | |
434 | padapter->bSurpriseRemoved); | |
435 | goto exit; | |
436 | } | |
437 | pwrpriv->bInSuspend = true; | |
438 | rtw_cancel_all_timer23a(padapter); | |
439 | LeaveAllPowerSaveMode23a(padapter); | |
440 | ||
441 | down(&pwrpriv->lock); | |
442 | /* padapter->net_closed = true; */ | |
443 | /* s1. */ | |
444 | if (pnetdev) { | |
445 | netif_carrier_off(pnetdev); | |
446 | netif_tx_stop_all_queues(pnetdev); | |
447 | } | |
448 | ||
449 | /* s2. */ | |
450 | rtw_disassoc_cmd23a(padapter, 0, false); | |
451 | ||
452 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && | |
453 | check_fwstate(pmlmepriv, _FW_LINKED)) { | |
454 | DBG_8723A("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", | |
455 | __func__, __LINE__, | |
456 | pmlmepriv->cur_network.network.Ssid.ssid, | |
457 | pmlmepriv->cur_network.network.MacAddress, | |
458 | pmlmepriv->cur_network.network.Ssid.ssid_len, | |
459 | pmlmepriv->assoc_ssid.ssid_len); | |
460 | ||
461 | rtw_set_roaming(padapter, 1); | |
462 | } | |
463 | /* s2-2. indicate disconnect to os */ | |
464 | rtw_indicate_disconnect23a(padapter); | |
465 | /* s2-3. */ | |
466 | rtw_free_assoc_resources23a(padapter, 1); | |
467 | /* s2-4. */ | |
528e5c1d | 468 | rtw_free_network_queue23a(padapter); |
b1925ad8 LF |
469 | |
470 | rtw_dev_unload(padapter); | |
471 | up(&pwrpriv->lock); | |
472 | ||
473 | if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) | |
810c832f JS |
474 | rtw_cfg80211_indicate_scan_done( |
475 | wdev_to_priv(padapter->rtw_wdev), true); | |
b1925ad8 LF |
476 | |
477 | if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) | |
478 | rtw_indicate_disconnect23a(padapter); | |
479 | ||
480 | exit: | |
481 | DBG_8723A("<=== %s return %d.............. in %dms\n", __func__, | |
482 | ret, jiffies_to_msecs(jiffies - start_time)); | |
483 | ||
484 | return ret; | |
485 | } | |
486 | ||
487 | static int rtw_resume(struct usb_interface *pusb_intf) | |
488 | { | |
489 | struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); | |
490 | struct rtw_adapter *padapter = dvobj->if1; | |
b1925ad8 LF |
491 | struct net_device *pnetdev; |
492 | struct pwrctrl_priv *pwrpriv = NULL; | |
493 | int ret = -1; | |
494 | unsigned long start_time = jiffies; | |
495 | ||
496 | DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid); | |
497 | ||
498 | if (!padapter) | |
499 | goto exit; | |
500 | pnetdev = padapter->pnetdev; | |
501 | pwrpriv = &padapter->pwrctrlpriv; | |
502 | ||
503 | down(&pwrpriv->lock); | |
504 | rtw_reset_drv_sw23a(padapter); | |
505 | pwrpriv->bkeepfwalive = false; | |
506 | ||
507 | DBG_8723A("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); | |
508 | if (pm_netdev_open23a(pnetdev, true) != 0) | |
509 | goto exit; | |
510 | ||
511 | netif_device_attach(pnetdev); | |
512 | netif_carrier_on(pnetdev); | |
513 | ||
514 | up(&pwrpriv->lock); | |
515 | ||
516 | if (padapter->pid[1] != 0) { | |
517 | DBG_8723A("pid[1]:%d\n", padapter->pid[1]); | |
ce16d2f1 | 518 | kill_pid(find_vpid(padapter->pid[1]), SIGUSR2, 1); |
b1925ad8 LF |
519 | } |
520 | ||
521 | rtw23a_roaming(padapter, NULL); | |
522 | ||
523 | ret = 0; | |
524 | exit: | |
525 | if (pwrpriv) | |
526 | pwrpriv->bInSuspend = false; | |
527 | DBG_8723A("<=== %s return %d.............. in %dms\n", __func__, | |
528 | ret, jiffies_to_msecs(jiffies - start_time)); | |
529 | ||
530 | return ret; | |
531 | } | |
532 | ||
533 | /* | |
534 | * drv_init() - a device potentially for us | |
535 | * | |
536 | * notes: drv_init() is called when the bus driver has located a card | |
537 | * for us to support. | |
538 | * We accept the new device by returning 0. | |
539 | */ | |
540 | static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, | |
541 | struct usb_interface *pusb_intf, | |
542 | const struct usb_device_id *pdid) | |
543 | { | |
544 | struct rtw_adapter *padapter = NULL; | |
545 | struct net_device *pnetdev = NULL; | |
546 | int status = _FAIL; | |
547 | ||
548 | pnetdev = rtw_init_netdev23a(padapter); | |
549 | if (!pnetdev) | |
e3916153 | 550 | goto free_adapter; |
b1925ad8 LF |
551 | padapter = netdev_priv(pnetdev); |
552 | ||
553 | padapter->dvobj = dvobj; | |
554 | padapter->bDriverStopped = true; | |
555 | dvobj->if1 = padapter; | |
556 | dvobj->padapters[dvobj->iface_nums++] = padapter; | |
557 | padapter->iface_id = IFACE_ID0; | |
558 | ||
c174eae6 | 559 | rtl8723au_set_hw_type(padapter); |
b1925ad8 | 560 | |
b1925ad8 LF |
561 | SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); |
562 | ||
563 | if (rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj))) | |
e3916153 | 564 | goto free_adapter; |
b1925ad8 | 565 | |
9385d861 JS |
566 | /* step 2. allocate HalData */ |
567 | padapter->HalData = kzalloc(sizeof(struct hal_data_8723a), GFP_KERNEL); | |
568 | if (!padapter->HalData) | |
569 | goto free_wdev; | |
b1925ad8 | 570 | |
b1925ad8 | 571 | /* step read_chip_version */ |
44e621c7 | 572 | rtl8723a_read_chip_version(padapter); |
b1925ad8 LF |
573 | |
574 | /* step usb endpoint mapping */ | |
82ccb597 | 575 | rtl8723au_chip_configure(padapter); |
b1925ad8 LF |
576 | |
577 | /* step read efuse/eeprom data and get mac_addr */ | |
1f4746f1 | 578 | rtl8723a_read_adapter_info(padapter); |
b1925ad8 LF |
579 | |
580 | /* step 5. */ | |
581 | if (rtw_init_drv_sw23a(padapter) == _FAIL) { | |
582 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | |
583 | ("Initialize driver software resource Failed!\n")); | |
584 | goto free_hal_data; | |
585 | } | |
586 | ||
587 | #ifdef CONFIG_PM | |
588 | if (padapter->pwrctrlpriv.bSupportRemoteWakeup) { | |
589 | dvobj->pusbdev->do_remote_wakeup = 1; | |
590 | pusb_intf->needs_remote_wakeup = 1; | |
591 | device_init_wakeup(&pusb_intf->dev, 1); | |
592 | DBG_8723A("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); | |
593 | DBG_8723A("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", | |
594 | device_may_wakeup(&pusb_intf->dev)); | |
595 | } | |
596 | #endif | |
597 | /* 2012-07-11 Move here to prevent the 8723AS-VAU BT | |
598 | * auto suspend influence | |
599 | */ | |
600 | if (usb_autopm_get_interface(pusb_intf) < 0) | |
601 | DBG_8723A("can't get autopm:\n"); | |
602 | #ifdef CONFIG_8723AU_BT_COEXIST | |
603 | padapter->pwrctrlpriv.autopm_cnt = 1; | |
604 | #endif | |
605 | ||
9d85833d JS |
606 | /* If the eeprom mac address is corrupted, assign a random address */ |
607 | if (is_broadcast_ether_addr(padapter->eeprompriv.mac_addr) || | |
608 | is_zero_ether_addr(padapter->eeprompriv.mac_addr)) | |
609 | eth_random_addr(padapter->eeprompriv.mac_addr); | |
b1925ad8 LF |
610 | |
611 | DBG_8723A("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n", | |
612 | padapter->bDriverStopped, padapter->bSurpriseRemoved, | |
613 | padapter->bup, padapter->hw_init_completed | |
614 | ); | |
615 | status = _SUCCESS; | |
616 | ||
617 | free_hal_data: | |
618 | if (status != _SUCCESS) | |
619 | kfree(padapter->HalData); | |
9385d861 | 620 | free_wdev: |
b1925ad8 LF |
621 | if (status != _SUCCESS) { |
622 | rtw_wdev_unregister(padapter->rtw_wdev); | |
623 | rtw_wdev_free(padapter->rtw_wdev); | |
624 | } | |
b1925ad8 LF |
625 | free_adapter: |
626 | if (status != _SUCCESS) { | |
627 | if (pnetdev) | |
628 | free_netdev(pnetdev); | |
629 | padapter = NULL; | |
630 | } | |
631 | return padapter; | |
632 | } | |
633 | ||
634 | static void rtw_usb_if1_deinit(struct rtw_adapter *if1) | |
635 | { | |
636 | struct net_device *pnetdev = if1->pnetdev; | |
637 | struct mlme_priv *pmlmepriv = &if1->mlmepriv; | |
638 | ||
639 | if (check_fwstate(pmlmepriv, _FW_LINKED)) | |
640 | rtw_disassoc_cmd23a(if1, 0, false); | |
641 | ||
642 | #ifdef CONFIG_8723AU_AP_MODE | |
643 | free_mlme_ap_info23a(if1); | |
644 | #endif | |
645 | ||
646 | if (pnetdev) | |
647 | unregister_netdev(pnetdev); /* will call netdev_close() */ | |
648 | ||
649 | rtw_cancel_all_timer23a(if1); | |
650 | ||
651 | rtw_dev_unload(if1); | |
652 | ||
653 | DBG_8723A("+r871xu_dev_remove, hw_init_completed =%d\n", | |
654 | if1->hw_init_completed); | |
655 | ||
b1925ad8 LF |
656 | if (if1->rtw_wdev) { |
657 | rtw_wdev_unregister(if1->rtw_wdev); | |
658 | rtw_wdev_free(if1->rtw_wdev); | |
659 | } | |
660 | ||
661 | #ifdef CONFIG_8723AU_BT_COEXIST | |
662 | if (1 == if1->pwrctrlpriv.autopm_cnt) { | |
663 | usb_autopm_put_interface(adapter_to_dvobj(if1)->pusbintf); | |
664 | if1->pwrctrlpriv.autopm_cnt--; | |
665 | } | |
666 | #endif | |
667 | ||
668 | rtw_free_drv_sw23a(if1); | |
669 | ||
670 | if (pnetdev) | |
671 | free_netdev(pnetdev); | |
672 | } | |
673 | ||
674 | static int rtw_drv_init(struct usb_interface *pusb_intf, | |
675 | const struct usb_device_id *pdid) | |
676 | { | |
677 | struct rtw_adapter *if1 = NULL; | |
678 | struct dvobj_priv *dvobj; | |
679 | int status = _FAIL; | |
680 | ||
681 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); | |
682 | ||
683 | /* Initialize dvobj_priv */ | |
684 | dvobj = usb_dvobj_init(pusb_intf); | |
685 | if (!dvobj) { | |
686 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | |
687 | ("initialize device object priv Failed!\n")); | |
688 | goto exit; | |
689 | } | |
690 | ||
691 | if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid); | |
692 | if (!if1) { | |
693 | DBG_8723A("rtw_init_primary_adapter Failed!\n"); | |
694 | goto free_dvobj; | |
695 | } | |
696 | ||
697 | /* dev_alloc_name && register_netdev */ | |
698 | status = rtw_drv_register_netdev(if1); | |
699 | if (status != _SUCCESS) | |
700 | goto free_if1; | |
701 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | |
702 | ("-871x_drv - drv_init, success!\n")); | |
703 | ||
704 | status = _SUCCESS; | |
705 | ||
706 | free_if1: | |
707 | if (status != _SUCCESS && if1) | |
708 | rtw_usb_if1_deinit(if1); | |
709 | free_dvobj: | |
710 | if (status != _SUCCESS) | |
711 | usb_dvobj_deinit(pusb_intf); | |
712 | exit: | |
713 | return status == _SUCCESS ? 0 : -ENODEV; | |
714 | } | |
715 | ||
716 | /* dev_remove() - our device is being removed */ | |
717 | static void rtw_disconnect(struct usb_interface *pusb_intf) | |
718 | { | |
719 | struct dvobj_priv *dvobj; | |
720 | struct rtw_adapter *padapter; | |
721 | struct net_device *pnetdev; | |
722 | struct mlme_priv *pmlmepriv; | |
723 | ||
724 | dvobj = usb_get_intfdata(pusb_intf); | |
725 | if (!dvobj) | |
726 | return; | |
727 | ||
728 | padapter = dvobj->if1; | |
729 | pnetdev = padapter->pnetdev; | |
730 | pmlmepriv = &padapter->mlmepriv; | |
731 | ||
732 | usb_set_intfdata(pusb_intf, NULL); | |
733 | ||
734 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n")); | |
735 | ||
736 | rtw_pm_set_ips23a(padapter, IPS_NONE); | |
737 | rtw_pm_set_lps23a(padapter, PS_MODE_ACTIVE); | |
738 | ||
739 | LeaveAllPowerSaveMode23a(padapter); | |
740 | ||
741 | rtw_usb_if1_deinit(padapter); | |
742 | ||
743 | usb_dvobj_deinit(pusb_intf); | |
744 | ||
745 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n")); | |
746 | DBG_8723A("-r871xu_dev_remove, done\n"); | |
747 | ||
748 | return; | |
749 | } | |
750 | ||
b1925ad8 LF |
751 | static int __init rtw_drv_entry(void) |
752 | { | |
753 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n")); | |
b1925ad8 LF |
754 | return usb_register(usb_drv); |
755 | } | |
756 | ||
757 | static void __exit rtw_drv_halt(void) | |
758 | { | |
759 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n")); | |
760 | DBG_8723A("+rtw_drv_halt\n"); | |
761 | ||
b1925ad8 LF |
762 | usb_deregister(usb_drv); |
763 | ||
764 | DBG_8723A("-rtw_drv_halt\n"); | |
765 | } | |
766 | ||
767 | module_init(rtw_drv_entry); | |
768 | module_exit(rtw_drv_halt); |