diff options
author | George <george0505@realtek.com> | 2011-02-11 15:27:49 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-11 16:16:37 -0500 |
commit | 2ca20f79e0d895489ae2f79fa321077e5ee2981d (patch) | |
tree | 7603d7d0d09aa78e92b56e85838a5196d86a366b | |
parent | 62e63975f47fcc0ebcaca04669098fe3ca7b20a2 (diff) |
rtlwifi: Add usb driver
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: George <george0505@realtek.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/rtlwifi/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/usb.c | 1035 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/usb.h | 164 |
3 files changed, 1201 insertions, 1 deletions
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index 2a7a4384f8ee..efbff2f478bf 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile | |||
@@ -8,6 +8,7 @@ rtlwifi-objs := \ | |||
8 | pci.o \ | 8 | pci.o \ |
9 | ps.o \ | 9 | ps.o \ |
10 | rc.o \ | 10 | rc.o \ |
11 | regd.o | 11 | regd.o \ |
12 | usb.o | ||
12 | 13 | ||
13 | obj-$(CONFIG_RTL8192CE) += rtl8192ce/ | 14 | obj-$(CONFIG_RTL8192CE) += rtl8192ce/ |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c new file mode 100644 index 000000000000..fbf24a0f9054 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -0,0 +1,1035 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2009-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 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * wlanfae <wlanfae@realtek.com> | ||
23 | * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, | ||
24 | * Hsinchu 300, Taiwan. | ||
25 | * | ||
26 | *****************************************************************************/ | ||
27 | #include <linux/usb.h> | ||
28 | #include "core.h" | ||
29 | #include "wifi.h" | ||
30 | #include "usb.h" | ||
31 | #include "base.h" | ||
32 | #include "ps.h" | ||
33 | |||
34 | #define REALTEK_USB_VENQT_READ 0xC0 | ||
35 | #define REALTEK_USB_VENQT_WRITE 0x40 | ||
36 | #define REALTEK_USB_VENQT_CMD_REQ 0x05 | ||
37 | #define REALTEK_USB_VENQT_CMD_IDX 0x00 | ||
38 | |||
39 | #define REALTEK_USB_VENQT_MAX_BUF_SIZE 254 | ||
40 | |||
41 | static void usbctrl_async_callback(struct urb *urb) | ||
42 | { | ||
43 | if (urb) | ||
44 | kfree(urb->context); | ||
45 | } | ||
46 | |||
47 | static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, | ||
48 | u16 value, u16 index, void *pdata, | ||
49 | u16 len) | ||
50 | { | ||
51 | int rc; | ||
52 | unsigned int pipe; | ||
53 | u8 reqtype; | ||
54 | struct usb_ctrlrequest *dr; | ||
55 | struct urb *urb; | ||
56 | struct rtl819x_async_write_data { | ||
57 | u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE]; | ||
58 | struct usb_ctrlrequest dr; | ||
59 | } *buf; | ||
60 | |||
61 | pipe = usb_sndctrlpipe(udev, 0); /* write_out */ | ||
62 | reqtype = REALTEK_USB_VENQT_WRITE; | ||
63 | |||
64 | buf = kmalloc(sizeof(*buf), GFP_ATOMIC); | ||
65 | if (!buf) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
69 | if (!urb) { | ||
70 | kfree(buf); | ||
71 | return -ENOMEM; | ||
72 | } | ||
73 | |||
74 | dr = &buf->dr; | ||
75 | |||
76 | dr->bRequestType = reqtype; | ||
77 | dr->bRequest = request; | ||
78 | dr->wValue = cpu_to_le16(value); | ||
79 | dr->wIndex = cpu_to_le16(index); | ||
80 | dr->wLength = cpu_to_le16(len); | ||
81 | memcpy(buf, pdata, len); | ||
82 | usb_fill_control_urb(urb, udev, pipe, | ||
83 | (unsigned char *)dr, buf, len, | ||
84 | usbctrl_async_callback, buf); | ||
85 | rc = usb_submit_urb(urb, GFP_ATOMIC); | ||
86 | if (rc < 0) | ||
87 | kfree(buf); | ||
88 | usb_free_urb(urb); | ||
89 | return rc; | ||
90 | } | ||
91 | |||
92 | static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, | ||
93 | u16 value, u16 index, void *pdata, | ||
94 | u16 len) | ||
95 | { | ||
96 | unsigned int pipe; | ||
97 | int status; | ||
98 | u8 reqtype; | ||
99 | |||
100 | pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ | ||
101 | reqtype = REALTEK_USB_VENQT_READ; | ||
102 | |||
103 | status = usb_control_msg(udev, pipe, request, reqtype, value, index, | ||
104 | pdata, len, 0); /* max. timeout */ | ||
105 | |||
106 | if (status < 0) | ||
107 | printk(KERN_ERR "reg 0x%x, usbctrl_vendorreq TimeOut! " | ||
108 | "status:0x%x value=0x%x\n", value, status, | ||
109 | *(u32 *)pdata); | ||
110 | return status; | ||
111 | } | ||
112 | |||
113 | static u32 _usb_read_sync(struct usb_device *udev, u32 addr, u16 len) | ||
114 | { | ||
115 | u8 request; | ||
116 | u16 wvalue; | ||
117 | u16 index; | ||
118 | u32 *data; | ||
119 | u32 ret; | ||
120 | |||
121 | data = kmalloc(sizeof(u32), GFP_KERNEL); | ||
122 | if (!data) | ||
123 | return -ENOMEM; | ||
124 | request = REALTEK_USB_VENQT_CMD_REQ; | ||
125 | index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ | ||
126 | |||
127 | wvalue = (u16)addr; | ||
128 | _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); | ||
129 | ret = le32_to_cpu(*data); | ||
130 | kfree(data); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr) | ||
135 | { | ||
136 | struct device *dev = rtlpriv->io.dev; | ||
137 | |||
138 | return (u8)_usb_read_sync(to_usb_device(dev), addr, 1); | ||
139 | } | ||
140 | |||
141 | static u16 _usb_read16_sync(struct rtl_priv *rtlpriv, u32 addr) | ||
142 | { | ||
143 | struct device *dev = rtlpriv->io.dev; | ||
144 | |||
145 | return (u16)_usb_read_sync(to_usb_device(dev), addr, 2); | ||
146 | } | ||
147 | |||
148 | static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr) | ||
149 | { | ||
150 | struct device *dev = rtlpriv->io.dev; | ||
151 | |||
152 | return _usb_read_sync(to_usb_device(dev), addr, 4); | ||
153 | } | ||
154 | |||
155 | static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, | ||
156 | u16 len) | ||
157 | { | ||
158 | u8 request; | ||
159 | u16 wvalue; | ||
160 | u16 index; | ||
161 | u32 data; | ||
162 | |||
163 | request = REALTEK_USB_VENQT_CMD_REQ; | ||
164 | index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ | ||
165 | wvalue = (u16)(addr&0x0000ffff); | ||
166 | data = cpu_to_le32(val); | ||
167 | _usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data, | ||
168 | len); | ||
169 | } | ||
170 | |||
171 | static void _usb_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) | ||
172 | { | ||
173 | struct device *dev = rtlpriv->io.dev; | ||
174 | |||
175 | _usb_write_async(to_usb_device(dev), addr, val, 1); | ||
176 | } | ||
177 | |||
178 | static void _usb_write16_async(struct rtl_priv *rtlpriv, u32 addr, u16 val) | ||
179 | { | ||
180 | struct device *dev = rtlpriv->io.dev; | ||
181 | |||
182 | _usb_write_async(to_usb_device(dev), addr, val, 2); | ||
183 | } | ||
184 | |||
185 | static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) | ||
186 | { | ||
187 | struct device *dev = rtlpriv->io.dev; | ||
188 | |||
189 | _usb_write_async(to_usb_device(dev), addr, val, 4); | ||
190 | } | ||
191 | |||
192 | static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr, | ||
193 | u16 len, u8 *pdata) | ||
194 | { | ||
195 | int status; | ||
196 | u8 request; | ||
197 | u16 wvalue; | ||
198 | u16 index; | ||
199 | |||
200 | request = REALTEK_USB_VENQT_CMD_REQ; | ||
201 | index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ | ||
202 | wvalue = (u16)addr; | ||
203 | if (read) | ||
204 | status = _usbctrl_vendorreq_sync_read(udev, request, wvalue, | ||
205 | index, pdata, len); | ||
206 | else | ||
207 | status = _usbctrl_vendorreq_async_write(udev, request, wvalue, | ||
208 | index, pdata, len); | ||
209 | return status; | ||
210 | } | ||
211 | |||
212 | static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len, | ||
213 | u8 *pdata) | ||
214 | { | ||
215 | struct device *dev = rtlpriv->io.dev; | ||
216 | |||
217 | return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len, | ||
218 | pdata); | ||
219 | } | ||
220 | |||
221 | static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len, | ||
222 | u8 *pdata) | ||
223 | { | ||
224 | struct device *dev = rtlpriv->io.dev; | ||
225 | |||
226 | return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len, | ||
227 | pdata); | ||
228 | } | ||
229 | |||
230 | static void _rtl_usb_io_handler_init(struct device *dev, | ||
231 | struct ieee80211_hw *hw) | ||
232 | { | ||
233 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
234 | |||
235 | rtlpriv->io.dev = dev; | ||
236 | mutex_init(&rtlpriv->io.bb_mutex); | ||
237 | rtlpriv->io.write8_async = _usb_write8_async; | ||
238 | rtlpriv->io.write16_async = _usb_write16_async; | ||
239 | rtlpriv->io.write32_async = _usb_write32_async; | ||
240 | rtlpriv->io.writeN_async = _usb_writeN_async; | ||
241 | rtlpriv->io.read8_sync = _usb_read8_sync; | ||
242 | rtlpriv->io.read16_sync = _usb_read16_sync; | ||
243 | rtlpriv->io.read32_sync = _usb_read32_sync; | ||
244 | rtlpriv->io.readN_sync = _usb_readN_sync; | ||
245 | } | ||
246 | |||
247 | static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) | ||
248 | { | ||
249 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
250 | |||
251 | mutex_destroy(&rtlpriv->io.bb_mutex); | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * | ||
256 | * Default aggregation handler. Do nothing and just return the oldest skb. | ||
257 | */ | ||
258 | static struct sk_buff *_none_usb_tx_aggregate_hdl(struct ieee80211_hw *hw, | ||
259 | struct sk_buff_head *list) | ||
260 | { | ||
261 | return skb_dequeue(list); | ||
262 | } | ||
263 | |||
264 | #define IS_HIGH_SPEED_USB(udev) \ | ||
265 | ((USB_SPEED_HIGH == (udev)->speed) ? true : false) | ||
266 | |||
267 | static int _rtl_usb_init_tx(struct ieee80211_hw *hw) | ||
268 | { | ||
269 | u32 i; | ||
270 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
271 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
272 | |||
273 | rtlusb->max_bulk_out_size = IS_HIGH_SPEED_USB(rtlusb->udev) | ||
274 | ? USB_HIGH_SPEED_BULK_SIZE | ||
275 | : USB_FULL_SPEED_BULK_SIZE; | ||
276 | |||
277 | RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("USB Max Bulk-out Size=%d\n", | ||
278 | rtlusb->max_bulk_out_size)); | ||
279 | |||
280 | for (i = 0; i < __RTL_TXQ_NUM; i++) { | ||
281 | u32 ep_num = rtlusb->ep_map.ep_mapping[i]; | ||
282 | if (!ep_num) { | ||
283 | RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, | ||
284 | ("Invalid endpoint map setting!\n")); | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | rtlusb->usb_tx_post_hdl = | ||
290 | rtlpriv->cfg->usb_interface_cfg->usb_tx_post_hdl; | ||
291 | rtlusb->usb_tx_cleanup = | ||
292 | rtlpriv->cfg->usb_interface_cfg->usb_tx_cleanup; | ||
293 | rtlusb->usb_tx_aggregate_hdl = | ||
294 | (rtlpriv->cfg->usb_interface_cfg->usb_tx_aggregate_hdl) | ||
295 | ? rtlpriv->cfg->usb_interface_cfg->usb_tx_aggregate_hdl | ||
296 | : &_none_usb_tx_aggregate_hdl; | ||
297 | |||
298 | init_usb_anchor(&rtlusb->tx_submitted); | ||
299 | for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { | ||
300 | skb_queue_head_init(&rtlusb->tx_skb_queue[i]); | ||
301 | init_usb_anchor(&rtlusb->tx_pending[i]); | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int _rtl_usb_init_rx(struct ieee80211_hw *hw) | ||
307 | { | ||
308 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
309 | struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); | ||
310 | struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); | ||
311 | |||
312 | rtlusb->rx_max_size = rtlpriv->cfg->usb_interface_cfg->rx_max_size; | ||
313 | rtlusb->rx_urb_num = rtlpriv->cfg->usb_interface_cfg->rx_urb_num; | ||
314 | rtlusb->in_ep = rtlpriv->cfg->usb_interface_cfg->in_ep_num; | ||
315 | rtlusb->usb_rx_hdl = rtlpriv->cfg->usb_interface_cfg->usb_rx_hdl; | ||
316 | rtlusb->usb_rx_segregate_hdl = | ||
317 | rtlpriv->cfg->usb_interface_cfg->usb_rx_segregate_hdl; | ||
318 | |||
319 | printk(KERN_INFO "rtl8192cu: rx_max_size %d, rx_urb_num %d, in_ep %d\n", | ||
320 | rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); | ||
321 | init_usb_anchor(&rtlusb->rx_submitted); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int _rtl_usb_init(struct ieee80211_hw *hw) | ||
326 | { | ||
327 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
328 | struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); | ||
329 | struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); | ||
330 | int err; | ||
331 | u8 epidx; | ||
332 | struct usb_interface *usb_intf = rtlusb->intf; | ||
333 | u8 epnums = usb_intf->cur_altsetting->desc.bNumEndpoints; | ||
334 | |||
335 | rtlusb->out_ep_nums = rtlusb->in_ep_nums = 0; | ||
336 | for (epidx = 0; epidx < epnums; epidx++) { | ||
337 | struct usb_endpoint_descriptor *pep_desc; | ||
338 | pep_desc = &usb_intf->cur_altsetting->endpoint[epidx].desc; | ||
339 | |||
340 | if (usb_endpoint_dir_in(pep_desc)) | ||
341 | rtlusb->in_ep_nums++; | ||
342 | else if (usb_endpoint_dir_out(pep_desc)) | ||
343 | rtlusb->out_ep_nums++; | ||
344 | |||
345 | RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, | ||
346 | ("USB EP(0x%02x), MaxPacketSize=%d ,Interval=%d.\n", | ||
347 | pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize, | ||
348 | pep_desc->bInterval)); | ||
349 | } | ||
350 | if (rtlusb->in_ep_nums < rtlpriv->cfg->usb_interface_cfg->in_ep_num) | ||
351 | return -EINVAL ; | ||
352 | |||
353 | /* usb endpoint mapping */ | ||
354 | err = rtlpriv->cfg->usb_interface_cfg->usb_endpoint_mapping(hw); | ||
355 | rtlusb->usb_mq_to_hwq = rtlpriv->cfg->usb_interface_cfg->usb_mq_to_hwq; | ||
356 | _rtl_usb_init_tx(hw); | ||
357 | _rtl_usb_init_rx(hw); | ||
358 | return err; | ||
359 | } | ||
360 | |||
361 | static int _rtl_usb_init_sw(struct ieee80211_hw *hw) | ||
362 | { | ||
363 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | ||
364 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||
365 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | ||
366 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
367 | |||
368 | rtlhal->hw = hw; | ||
369 | ppsc->b_inactiveps = false; | ||
370 | ppsc->b_leisure_ps = false; | ||
371 | ppsc->b_fwctrl_lps = false; | ||
372 | ppsc->b_reg_fwctrl_lps = 3; | ||
373 | ppsc->reg_max_lps_awakeintvl = 5; | ||
374 | ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; | ||
375 | |||
376 | /* IBSS */ | ||
377 | mac->beacon_interval = 100; | ||
378 | |||
379 | /* AMPDU */ | ||
380 | mac->min_space_cfg = 0; | ||
381 | mac->max_mss_density = 0; | ||
382 | |||
383 | /* set sane AMPDU defaults */ | ||
384 | mac->current_ampdu_density = 7; | ||
385 | mac->current_ampdu_factor = 3; | ||
386 | |||
387 | /* QOS */ | ||
388 | rtlusb->acm_method = eAcmWay2_SW; | ||
389 | |||
390 | /* IRQ */ | ||
391 | /* HIMR - turn all on */ | ||
392 | rtlusb->irq_mask[0] = 0xFFFFFFFF; | ||
393 | /* HIMR_EX - turn all on */ | ||
394 | rtlusb->irq_mask[1] = 0xFFFFFFFF; | ||
395 | rtlusb->disableHWSM = true; | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | #define __RADIO_TAP_SIZE_RSV 32 | ||
400 | |||
401 | static void _rtl_rx_completed(struct urb *urb); | ||
402 | |||
403 | static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw, | ||
404 | struct rtl_usb *rtlusb, | ||
405 | struct urb *urb, | ||
406 | gfp_t gfp_mask) | ||
407 | { | ||
408 | struct sk_buff *skb; | ||
409 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
410 | |||
411 | skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV), | ||
412 | gfp_mask); | ||
413 | if (!skb) { | ||
414 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
415 | ("Failed to __dev_alloc_skb!!\n")) | ||
416 | return ERR_PTR(-ENOMEM); | ||
417 | } | ||
418 | |||
419 | /* reserve some space for mac80211's radiotap */ | ||
420 | skb_reserve(skb, __RADIO_TAP_SIZE_RSV); | ||
421 | usb_fill_bulk_urb(urb, rtlusb->udev, | ||
422 | usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep), | ||
423 | skb->data, min(skb_tailroom(skb), | ||
424 | (int)rtlusb->rx_max_size), | ||
425 | _rtl_rx_completed, skb); | ||
426 | |||
427 | _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); | ||
428 | return skb; | ||
429 | } | ||
430 | |||
431 | #undef __RADIO_TAP_SIZE_RSV | ||
432 | |||
433 | static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, | ||
434 | struct sk_buff *skb) | ||
435 | { | ||
436 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
437 | u8 *rxdesc = skb->data; | ||
438 | struct ieee80211_hdr *hdr; | ||
439 | bool unicast = false; | ||
440 | u16 fc; | ||
441 | struct ieee80211_rx_status rx_status = {0}; | ||
442 | struct rtl_stats stats = { | ||
443 | .signal = 0, | ||
444 | .noise = -98, | ||
445 | .rate = 0, | ||
446 | }; | ||
447 | |||
448 | skb_pull(skb, RTL_RX_DESC_SIZE); | ||
449 | rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); | ||
450 | skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); | ||
451 | hdr = (struct ieee80211_hdr *)(skb->data); | ||
452 | fc = le16_to_cpu(hdr->frame_control); | ||
453 | if (!stats.b_crc) { | ||
454 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); | ||
455 | |||
456 | if (is_broadcast_ether_addr(hdr->addr1)) { | ||
457 | /*TODO*/; | ||
458 | } else if (is_multicast_ether_addr(hdr->addr1)) { | ||
459 | /*TODO*/ | ||
460 | } else { | ||
461 | unicast = true; | ||
462 | rtlpriv->stats.rxbytesunicast += skb->len; | ||
463 | } | ||
464 | |||
465 | rtl_is_special_data(hw, skb, false); | ||
466 | |||
467 | if (ieee80211_is_data(fc)) { | ||
468 | rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); | ||
469 | |||
470 | if (unicast) | ||
471 | rtlpriv->link_info.num_rx_inperiod++; | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | |||
476 | static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, | ||
477 | struct sk_buff *skb) | ||
478 | { | ||
479 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
480 | u8 *rxdesc = skb->data; | ||
481 | struct ieee80211_hdr *hdr; | ||
482 | bool unicast = false; | ||
483 | u16 fc; | ||
484 | struct ieee80211_rx_status rx_status = {0}; | ||
485 | struct rtl_stats stats = { | ||
486 | .signal = 0, | ||
487 | .noise = -98, | ||
488 | .rate = 0, | ||
489 | }; | ||
490 | |||
491 | skb_pull(skb, RTL_RX_DESC_SIZE); | ||
492 | rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); | ||
493 | skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); | ||
494 | hdr = (struct ieee80211_hdr *)(skb->data); | ||
495 | fc = le16_to_cpu(hdr->frame_control); | ||
496 | if (!stats.b_crc) { | ||
497 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); | ||
498 | |||
499 | if (is_broadcast_ether_addr(hdr->addr1)) { | ||
500 | /*TODO*/; | ||
501 | } else if (is_multicast_ether_addr(hdr->addr1)) { | ||
502 | /*TODO*/ | ||
503 | } else { | ||
504 | unicast = true; | ||
505 | rtlpriv->stats.rxbytesunicast += skb->len; | ||
506 | } | ||
507 | |||
508 | rtl_is_special_data(hw, skb, false); | ||
509 | |||
510 | if (ieee80211_is_data(fc)) { | ||
511 | rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); | ||
512 | |||
513 | if (unicast) | ||
514 | rtlpriv->link_info.num_rx_inperiod++; | ||
515 | } | ||
516 | if (likely(rtl_action_proc(hw, skb, false))) { | ||
517 | struct sk_buff *uskb = NULL; | ||
518 | u8 *pdata; | ||
519 | |||
520 | uskb = dev_alloc_skb(skb->len + 128); | ||
521 | memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, | ||
522 | sizeof(rx_status)); | ||
523 | pdata = (u8 *)skb_put(uskb, skb->len); | ||
524 | memcpy(pdata, skb->data, skb->len); | ||
525 | dev_kfree_skb_any(skb); | ||
526 | ieee80211_rx_irqsafe(hw, uskb); | ||
527 | } else { | ||
528 | dev_kfree_skb_any(skb); | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | |||
533 | static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
534 | { | ||
535 | struct sk_buff *_skb; | ||
536 | struct sk_buff_head rx_queue; | ||
537 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
538 | |||
539 | skb_queue_head_init(&rx_queue); | ||
540 | if (rtlusb->usb_rx_segregate_hdl) | ||
541 | rtlusb->usb_rx_segregate_hdl(hw, skb, &rx_queue); | ||
542 | WARN_ON(skb_queue_empty(&rx_queue)); | ||
543 | while (!skb_queue_empty(&rx_queue)) { | ||
544 | _skb = skb_dequeue(&rx_queue); | ||
545 | _rtl_usb_rx_process_agg(hw, skb); | ||
546 | ieee80211_rx_irqsafe(hw, skb); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | static void _rtl_rx_completed(struct urb *_urb) | ||
551 | { | ||
552 | struct sk_buff *skb = (struct sk_buff *)_urb->context; | ||
553 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
554 | struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; | ||
555 | struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); | ||
556 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
557 | int err = 0; | ||
558 | |||
559 | if (unlikely(IS_USB_STOP(rtlusb))) | ||
560 | goto free; | ||
561 | |||
562 | if (likely(0 == _urb->status)) { | ||
563 | /* If this code were moved to work queue, would CPU | ||
564 | * utilization be improved? NOTE: We shall allocate another skb | ||
565 | * and reuse the original one. | ||
566 | */ | ||
567 | skb_put(skb, _urb->actual_length); | ||
568 | |||
569 | if (likely(!rtlusb->usb_rx_segregate_hdl)) { | ||
570 | struct sk_buff *_skb; | ||
571 | _rtl_usb_rx_process_noagg(hw, skb); | ||
572 | _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC); | ||
573 | if (IS_ERR(_skb)) { | ||
574 | err = PTR_ERR(_skb); | ||
575 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
576 | ("Can't allocate skb for bulk IN!\n")); | ||
577 | return; | ||
578 | } | ||
579 | skb = _skb; | ||
580 | } else{ | ||
581 | /* TO DO */ | ||
582 | _rtl_rx_pre_process(hw, skb); | ||
583 | printk(KERN_ERR "rtlwifi: rx agg not supported\n"); | ||
584 | } | ||
585 | goto resubmit; | ||
586 | } | ||
587 | |||
588 | switch (_urb->status) { | ||
589 | /* disconnect */ | ||
590 | case -ENOENT: | ||
591 | case -ECONNRESET: | ||
592 | case -ENODEV: | ||
593 | case -ESHUTDOWN: | ||
594 | goto free; | ||
595 | default: | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | resubmit: | ||
600 | skb_reset_tail_pointer(skb); | ||
601 | skb_trim(skb, 0); | ||
602 | |||
603 | usb_anchor_urb(_urb, &rtlusb->rx_submitted); | ||
604 | err = usb_submit_urb(_urb, GFP_ATOMIC); | ||
605 | if (unlikely(err)) { | ||
606 | usb_unanchor_urb(_urb); | ||
607 | goto free; | ||
608 | } | ||
609 | return; | ||
610 | |||
611 | free: | ||
612 | dev_kfree_skb_irq(skb); | ||
613 | } | ||
614 | |||
615 | static int _rtl_usb_receive(struct ieee80211_hw *hw) | ||
616 | { | ||
617 | struct urb *urb; | ||
618 | struct sk_buff *skb; | ||
619 | int err; | ||
620 | int i; | ||
621 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
622 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
623 | |||
624 | WARN_ON(0 == rtlusb->rx_urb_num); | ||
625 | /* 1600 == 1514 + max WLAN header + rtk info */ | ||
626 | WARN_ON(rtlusb->rx_max_size < 1600); | ||
627 | |||
628 | for (i = 0; i < rtlusb->rx_urb_num; i++) { | ||
629 | err = -ENOMEM; | ||
630 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
631 | if (!urb) { | ||
632 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
633 | ("Failed to alloc URB!!\n")) | ||
634 | goto err_out; | ||
635 | } | ||
636 | |||
637 | skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); | ||
638 | if (IS_ERR(skb)) { | ||
639 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
640 | ("Failed to prep_rx_urb!!\n")) | ||
641 | err = PTR_ERR(skb); | ||
642 | goto err_out; | ||
643 | } | ||
644 | |||
645 | usb_anchor_urb(urb, &rtlusb->rx_submitted); | ||
646 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
647 | if (err) | ||
648 | goto err_out; | ||
649 | usb_free_urb(urb); | ||
650 | } | ||
651 | return 0; | ||
652 | |||
653 | err_out: | ||
654 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); | ||
655 | return err; | ||
656 | } | ||
657 | |||
658 | static int rtl_usb_start(struct ieee80211_hw *hw) | ||
659 | { | ||
660 | int err; | ||
661 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
662 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||
663 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
664 | |||
665 | err = rtlpriv->cfg->ops->hw_init(hw); | ||
666 | rtl_init_rx_config(hw); | ||
667 | |||
668 | /* Enable software */ | ||
669 | SET_USB_START(rtlusb); | ||
670 | /* should after adapter start and interrupt enable. */ | ||
671 | set_hal_start(rtlhal); | ||
672 | |||
673 | /* Start bulk IN */ | ||
674 | _rtl_usb_receive(hw); | ||
675 | |||
676 | return err; | ||
677 | } | ||
678 | /** | ||
679 | * | ||
680 | * | ||
681 | */ | ||
682 | |||
683 | /*======================= tx =========================================*/ | ||
684 | static void rtl_usb_cleanup(struct ieee80211_hw *hw) | ||
685 | { | ||
686 | u32 i; | ||
687 | struct sk_buff *_skb; | ||
688 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
689 | struct ieee80211_tx_info *txinfo; | ||
690 | |||
691 | SET_USB_STOP(rtlusb); | ||
692 | |||
693 | /* clean up rx stuff. */ | ||
694 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); | ||
695 | |||
696 | /* clean up tx stuff */ | ||
697 | for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { | ||
698 | while ((_skb = skb_dequeue(&rtlusb->tx_skb_queue[i]))) { | ||
699 | rtlusb->usb_tx_cleanup(hw, _skb); | ||
700 | txinfo = IEEE80211_SKB_CB(_skb); | ||
701 | ieee80211_tx_info_clear_status(txinfo); | ||
702 | txinfo->flags |= IEEE80211_TX_STAT_ACK; | ||
703 | ieee80211_tx_status_irqsafe(hw, _skb); | ||
704 | } | ||
705 | usb_kill_anchored_urbs(&rtlusb->tx_pending[i]); | ||
706 | } | ||
707 | usb_kill_anchored_urbs(&rtlusb->tx_submitted); | ||
708 | } | ||
709 | |||
710 | /** | ||
711 | * | ||
712 | * We may add some struct into struct rtl_usb later. Do deinit here. | ||
713 | * | ||
714 | */ | ||
715 | static void rtl_usb_deinit(struct ieee80211_hw *hw) | ||
716 | { | ||
717 | rtl_usb_cleanup(hw); | ||
718 | } | ||
719 | |||
720 | static void rtl_usb_stop(struct ieee80211_hw *hw) | ||
721 | { | ||
722 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
723 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||
724 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
725 | |||
726 | /* should after adapter start and interrupt enable. */ | ||
727 | set_hal_stop(rtlhal); | ||
728 | /* Enable software */ | ||
729 | SET_USB_STOP(rtlusb); | ||
730 | rtl_usb_deinit(hw); | ||
731 | rtlpriv->cfg->ops->hw_disable(hw); | ||
732 | } | ||
733 | |||
734 | static void _rtl_submit_tx_urb(struct ieee80211_hw *hw, struct urb *_urb) | ||
735 | { | ||
736 | int err; | ||
737 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
738 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
739 | |||
740 | usb_anchor_urb(_urb, &rtlusb->tx_submitted); | ||
741 | err = usb_submit_urb(_urb, GFP_ATOMIC); | ||
742 | if (err < 0) { | ||
743 | struct sk_buff *skb; | ||
744 | |||
745 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
746 | ("Failed to submit urb.\n")); | ||
747 | usb_unanchor_urb(_urb); | ||
748 | skb = (struct sk_buff *)_urb->context; | ||
749 | kfree_skb(skb); | ||
750 | } | ||
751 | usb_free_urb(_urb); | ||
752 | } | ||
753 | |||
754 | static int _usb_tx_post(struct ieee80211_hw *hw, struct urb *urb, | ||
755 | struct sk_buff *skb) | ||
756 | { | ||
757 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
758 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
759 | struct ieee80211_tx_info *txinfo; | ||
760 | |||
761 | rtlusb->usb_tx_post_hdl(hw, urb, skb); | ||
762 | skb_pull(skb, RTL_TX_HEADER_SIZE); | ||
763 | txinfo = IEEE80211_SKB_CB(skb); | ||
764 | ieee80211_tx_info_clear_status(txinfo); | ||
765 | txinfo->flags |= IEEE80211_TX_STAT_ACK; | ||
766 | |||
767 | if (urb->status) { | ||
768 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
769 | ("Urb has error status 0x%X\n", urb->status)); | ||
770 | goto out; | ||
771 | } | ||
772 | /* TODO: statistics */ | ||
773 | out: | ||
774 | ieee80211_tx_status_irqsafe(hw, skb); | ||
775 | return urb->status; | ||
776 | } | ||
777 | |||
778 | static void _rtl_tx_complete(struct urb *urb) | ||
779 | { | ||
780 | struct sk_buff *skb = (struct sk_buff *)urb->context; | ||
781 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
782 | struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; | ||
783 | struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); | ||
784 | int err; | ||
785 | |||
786 | if (unlikely(IS_USB_STOP(rtlusb))) | ||
787 | return; | ||
788 | err = _usb_tx_post(hw, urb, skb); | ||
789 | if (err) { | ||
790 | /* Ignore error and keep issuiing other urbs */ | ||
791 | return; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | static struct urb *_rtl_usb_tx_urb_setup(struct ieee80211_hw *hw, | ||
796 | struct sk_buff *skb, u32 ep_num) | ||
797 | { | ||
798 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
799 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
800 | struct urb *_urb; | ||
801 | |||
802 | WARN_ON(NULL == skb); | ||
803 | _urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
804 | if (!_urb) { | ||
805 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
806 | ("Can't allocate URB for bulk out!\n")); | ||
807 | kfree_skb(skb); | ||
808 | return NULL; | ||
809 | } | ||
810 | _rtl_install_trx_info(rtlusb, skb, ep_num); | ||
811 | usb_fill_bulk_urb(_urb, rtlusb->udev, usb_sndbulkpipe(rtlusb->udev, | ||
812 | ep_num), skb->data, skb->len, _rtl_tx_complete, skb); | ||
813 | _urb->transfer_flags |= URB_ZERO_PACKET; | ||
814 | return _urb; | ||
815 | } | ||
816 | |||
817 | static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
818 | enum rtl_txq qnum) | ||
819 | { | ||
820 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
821 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
822 | u32 ep_num; | ||
823 | struct urb *_urb = NULL; | ||
824 | struct sk_buff *_skb = NULL; | ||
825 | struct sk_buff_head *skb_list; | ||
826 | struct usb_anchor *urb_list; | ||
827 | |||
828 | WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); | ||
829 | if (unlikely(IS_USB_STOP(rtlusb))) { | ||
830 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
831 | ("USB device is stopping...\n")); | ||
832 | kfree_skb(skb); | ||
833 | return; | ||
834 | } | ||
835 | ep_num = rtlusb->ep_map.ep_mapping[qnum]; | ||
836 | skb_list = &rtlusb->tx_skb_queue[ep_num]; | ||
837 | _skb = skb; | ||
838 | _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num); | ||
839 | if (unlikely(!_urb)) { | ||
840 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
841 | ("Can't allocate urb. Drop skb!\n")); | ||
842 | return; | ||
843 | } | ||
844 | urb_list = &rtlusb->tx_pending[ep_num]; | ||
845 | _rtl_submit_tx_urb(hw, _urb); | ||
846 | } | ||
847 | |||
848 | static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
849 | u16 hw_queue) | ||
850 | { | ||
851 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
852 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | ||
853 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
854 | struct rtl_tx_desc *pdesc = NULL; | ||
855 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); | ||
856 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
857 | u8 *pda_addr = hdr->addr1; | ||
858 | /* ssn */ | ||
859 | u8 *qc = NULL; | ||
860 | u8 tid = 0; | ||
861 | u16 seq_number = 0; | ||
862 | |||
863 | if (ieee80211_is_mgmt(fc)) | ||
864 | rtl_tx_mgmt_proc(hw, skb); | ||
865 | rtl_action_proc(hw, skb, true); | ||
866 | if (is_multicast_ether_addr(pda_addr)) | ||
867 | rtlpriv->stats.txbytesmulticast += skb->len; | ||
868 | else if (is_broadcast_ether_addr(pda_addr)) | ||
869 | rtlpriv->stats.txbytesbroadcast += skb->len; | ||
870 | else | ||
871 | rtlpriv->stats.txbytesunicast += skb->len; | ||
872 | if (ieee80211_is_data_qos(fc)) { | ||
873 | qc = ieee80211_get_qos_ctl(hdr); | ||
874 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
875 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & | ||
876 | IEEE80211_SCTL_SEQ) >> 4; | ||
877 | seq_number += 1; | ||
878 | seq_number <<= 4; | ||
879 | } | ||
880 | rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, | ||
881 | hw_queue); | ||
882 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||
883 | if (qc) | ||
884 | mac->tids[tid].seq_number = seq_number; | ||
885 | } | ||
886 | if (ieee80211_is_data(fc)) | ||
887 | rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); | ||
888 | } | ||
889 | |||
890 | static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
891 | { | ||
892 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
893 | struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); | ||
894 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); | ||
895 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
896 | u16 hw_queue; | ||
897 | |||
898 | if (unlikely(is_hal_stop(rtlhal))) | ||
899 | goto err_free; | ||
900 | hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb)); | ||
901 | _rtl_usb_tx_preprocess(hw, skb, hw_queue); | ||
902 | _rtl_usb_transmit(hw, skb, hw_queue); | ||
903 | return NETDEV_TX_OK; | ||
904 | |||
905 | err_free: | ||
906 | dev_kfree_skb_any(skb); | ||
907 | return NETDEV_TX_OK; | ||
908 | } | ||
909 | |||
910 | static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, | ||
911 | struct sk_buff *skb) | ||
912 | { | ||
913 | return false; | ||
914 | } | ||
915 | |||
916 | static struct rtl_intf_ops rtl_usb_ops = { | ||
917 | .adapter_start = rtl_usb_start, | ||
918 | .adapter_stop = rtl_usb_stop, | ||
919 | .adapter_tx = rtl_usb_tx, | ||
920 | .waitq_insert = rtl_usb_tx_chk_waitq_insert, | ||
921 | }; | ||
922 | |||
923 | int __devinit rtl_usb_probe(struct usb_interface *intf, | ||
924 | const struct usb_device_id *id) | ||
925 | { | ||
926 | int err; | ||
927 | struct ieee80211_hw *hw = NULL; | ||
928 | struct rtl_priv *rtlpriv = NULL; | ||
929 | struct usb_device *udev; | ||
930 | struct rtl_usb_priv *usb_priv; | ||
931 | |||
932 | hw = ieee80211_alloc_hw(sizeof(struct rtl_priv) + | ||
933 | sizeof(struct rtl_usb_priv), &rtl_ops); | ||
934 | if (!hw) { | ||
935 | RT_ASSERT(false, ("%s : ieee80211 alloc failed\n", __func__)); | ||
936 | return -ENOMEM; | ||
937 | } | ||
938 | rtlpriv = hw->priv; | ||
939 | SET_IEEE80211_DEV(hw, &intf->dev); | ||
940 | udev = interface_to_usbdev(intf); | ||
941 | usb_get_dev(udev); | ||
942 | usb_priv = rtl_usbpriv(hw); | ||
943 | memset(usb_priv, 0, sizeof(*usb_priv)); | ||
944 | usb_priv->dev.intf = intf; | ||
945 | usb_priv->dev.udev = udev; | ||
946 | usb_set_intfdata(intf, hw); | ||
947 | /* init cfg & intf_ops */ | ||
948 | rtlpriv->rtlhal.interface = INTF_USB; | ||
949 | rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info); | ||
950 | rtlpriv->intf_ops = &rtl_usb_ops; | ||
951 | rtl_dbgp_flag_init(hw); | ||
952 | /* Init IO handler */ | ||
953 | _rtl_usb_io_handler_init(&udev->dev, hw); | ||
954 | rtlpriv->cfg->ops->read_chip_version(hw); | ||
955 | /*like read eeprom and so on */ | ||
956 | rtlpriv->cfg->ops->read_eeprom_info(hw); | ||
957 | if (rtlpriv->cfg->ops->init_sw_vars(hw)) { | ||
958 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
959 | ("Can't init_sw_vars.\n")); | ||
960 | goto error_out; | ||
961 | } | ||
962 | rtlpriv->cfg->ops->init_sw_leds(hw); | ||
963 | err = _rtl_usb_init(hw); | ||
964 | err = _rtl_usb_init_sw(hw); | ||
965 | /* Init mac80211 sw */ | ||
966 | err = rtl_init_core(hw); | ||
967 | if (err) { | ||
968 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
969 | ("Can't allocate sw for mac80211.\n")); | ||
970 | goto error_out; | ||
971 | } | ||
972 | |||
973 | /*init rfkill */ | ||
974 | /* rtl_init_rfkill(hw); */ | ||
975 | |||
976 | err = ieee80211_register_hw(hw); | ||
977 | if (err) { | ||
978 | RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, | ||
979 | ("Can't register mac80211 hw.\n")); | ||
980 | goto error_out; | ||
981 | } else { | ||
982 | rtlpriv->mac80211.mac80211_registered = 1; | ||
983 | } | ||
984 | set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); | ||
985 | return 0; | ||
986 | error_out: | ||
987 | rtl_deinit_core(hw); | ||
988 | _rtl_usb_io_handler_release(hw); | ||
989 | ieee80211_free_hw(hw); | ||
990 | usb_put_dev(udev); | ||
991 | return -ENODEV; | ||
992 | } | ||
993 | EXPORT_SYMBOL(rtl_usb_probe); | ||
994 | |||
995 | void rtl_usb_disconnect(struct usb_interface *intf) | ||
996 | { | ||
997 | struct ieee80211_hw *hw = usb_get_intfdata(intf); | ||
998 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
999 | struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); | ||
1000 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
1001 | |||
1002 | if (unlikely(!rtlpriv)) | ||
1003 | return; | ||
1004 | /*ieee80211_unregister_hw will call ops_stop */ | ||
1005 | if (rtlmac->mac80211_registered == 1) { | ||
1006 | ieee80211_unregister_hw(hw); | ||
1007 | rtlmac->mac80211_registered = 0; | ||
1008 | } else { | ||
1009 | rtl_deinit_deferred_work(hw); | ||
1010 | rtlpriv->intf_ops->adapter_stop(hw); | ||
1011 | } | ||
1012 | /*deinit rfkill */ | ||
1013 | /* rtl_deinit_rfkill(hw); */ | ||
1014 | rtl_usb_deinit(hw); | ||
1015 | rtl_deinit_core(hw); | ||
1016 | rtlpriv->cfg->ops->deinit_sw_leds(hw); | ||
1017 | rtlpriv->cfg->ops->deinit_sw_vars(hw); | ||
1018 | _rtl_usb_io_handler_release(hw); | ||
1019 | usb_put_dev(rtlusb->udev); | ||
1020 | usb_set_intfdata(intf, NULL); | ||
1021 | ieee80211_free_hw(hw); | ||
1022 | } | ||
1023 | EXPORT_SYMBOL(rtl_usb_disconnect); | ||
1024 | |||
1025 | int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message) | ||
1026 | { | ||
1027 | return 0; | ||
1028 | } | ||
1029 | EXPORT_SYMBOL(rtl_usb_suspend); | ||
1030 | |||
1031 | int rtl_usb_resume(struct usb_interface *pusb_intf) | ||
1032 | { | ||
1033 | return 0; | ||
1034 | } | ||
1035 | EXPORT_SYMBOL(rtl_usb_resume); | ||
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h new file mode 100644 index 000000000000..c83311655104 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/usb.h | |||
@@ -0,0 +1,164 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2009-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 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * wlanfae <wlanfae@realtek.com> | ||
23 | * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, | ||
24 | * Hsinchu 300, Taiwan. | ||
25 | * | ||
26 | *****************************************************************************/ | ||
27 | |||
28 | #ifndef __RTL_USB_H__ | ||
29 | #define __RTL_USB_H__ | ||
30 | |||
31 | #include <linux/usb.h> | ||
32 | #include <linux/skbuff.h> | ||
33 | |||
34 | #define RTL_USB_DEVICE(vend, prod, cfg) \ | ||
35 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ | ||
36 | .idVendor = (vend), \ | ||
37 | .idProduct = (prod), \ | ||
38 | .driver_info = (kernel_ulong_t)&(cfg) | ||
39 | |||
40 | #define USB_HIGH_SPEED_BULK_SIZE 512 | ||
41 | #define USB_FULL_SPEED_BULK_SIZE 64 | ||
42 | |||
43 | |||
44 | #define RTL_USB_MAX_TXQ_NUM 4 /* max tx queue */ | ||
45 | #define RTL_USB_MAX_EP_NUM 6 /* max ep number */ | ||
46 | #define RTL_USB_MAX_TX_URBS_NUM 8 | ||
47 | |||
48 | enum rtl_txq { | ||
49 | /* These definitions shall be consistent with value | ||
50 | * returned by skb_get_queue_mapping | ||
51 | *------------------------------------*/ | ||
52 | RTL_TXQ_BK, | ||
53 | RTL_TXQ_BE, | ||
54 | RTL_TXQ_VI, | ||
55 | RTL_TXQ_VO, | ||
56 | /*------------------------------------*/ | ||
57 | RTL_TXQ_BCN, | ||
58 | RTL_TXQ_MGT, | ||
59 | RTL_TXQ_HI, | ||
60 | |||
61 | /* Must be last */ | ||
62 | __RTL_TXQ_NUM, | ||
63 | }; | ||
64 | |||
65 | struct rtl_ep_map { | ||
66 | u32 ep_mapping[__RTL_TXQ_NUM]; | ||
67 | }; | ||
68 | |||
69 | struct _trx_info { | ||
70 | struct rtl_usb *rtlusb; | ||
71 | u32 ep_num; | ||
72 | }; | ||
73 | |||
74 | static inline void _rtl_install_trx_info(struct rtl_usb *rtlusb, | ||
75 | struct sk_buff *skb, | ||
76 | u32 ep_num) | ||
77 | { | ||
78 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
79 | info->rate_driver_data[0] = rtlusb; | ||
80 | info->rate_driver_data[1] = (void *)(__kernel_size_t)ep_num; | ||
81 | } | ||
82 | |||
83 | |||
84 | /* Add suspend/resume later */ | ||
85 | enum rtl_usb_state { | ||
86 | USB_STATE_STOP = 0, | ||
87 | USB_STATE_START = 1, | ||
88 | }; | ||
89 | |||
90 | #define IS_USB_STOP(rtlusb_ptr) (USB_STATE_STOP == (rtlusb_ptr)->state) | ||
91 | #define IS_USB_START(rtlusb_ptr) (USB_STATE_START == (rtlusb_ptr)->state) | ||
92 | #define SET_USB_STOP(rtlusb_ptr) \ | ||
93 | do { \ | ||
94 | (rtlusb_ptr)->state = USB_STATE_STOP; \ | ||
95 | } while (0) | ||
96 | |||
97 | #define SET_USB_START(rtlusb_ptr) \ | ||
98 | do { \ | ||
99 | (rtlusb_ptr)->state = USB_STATE_START; \ | ||
100 | } while (0) | ||
101 | |||
102 | struct rtl_usb { | ||
103 | struct usb_device *udev; | ||
104 | struct usb_interface *intf; | ||
105 | enum rtl_usb_state state; | ||
106 | |||
107 | /* Bcn control register setting */ | ||
108 | u32 reg_bcn_ctrl_val; | ||
109 | /* for 88/92cu card disable */ | ||
110 | u8 disableHWSM; | ||
111 | /*QOS & EDCA */ | ||
112 | enum acm_method acm_method; | ||
113 | /* irq . HIMR,HIMR_EX */ | ||
114 | u32 irq_mask[2]; | ||
115 | bool irq_enabled; | ||
116 | |||
117 | u16 (*usb_mq_to_hwq)(u16 fc, u16 mac80211_queue_index); | ||
118 | |||
119 | /* Tx */ | ||
120 | u8 out_ep_nums ; | ||
121 | u8 out_queue_sel; | ||
122 | struct rtl_ep_map ep_map; | ||
123 | |||
124 | u32 max_bulk_out_size; | ||
125 | u32 tx_submitted_urbs; | ||
126 | struct sk_buff_head tx_skb_queue[RTL_USB_MAX_EP_NUM]; | ||
127 | |||
128 | struct usb_anchor tx_pending[RTL_USB_MAX_EP_NUM]; | ||
129 | struct usb_anchor tx_submitted; | ||
130 | |||
131 | struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *, | ||
132 | struct sk_buff_head *); | ||
133 | int (*usb_tx_post_hdl)(struct ieee80211_hw *, | ||
134 | struct urb *, struct sk_buff *); | ||
135 | void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); | ||
136 | |||
137 | /* Rx */ | ||
138 | u8 in_ep_nums ; | ||
139 | u32 in_ep; /* Bulk IN endpoint number */ | ||
140 | u32 rx_max_size; /* Bulk IN max buffer size */ | ||
141 | u32 rx_urb_num; /* How many Bulk INs are submitted to host. */ | ||
142 | struct usb_anchor rx_submitted; | ||
143 | void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, | ||
144 | struct sk_buff_head *); | ||
145 | void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); | ||
146 | }; | ||
147 | |||
148 | struct rtl_usb_priv { | ||
149 | struct rtl_usb dev; | ||
150 | struct rtl_led_ctl ledctl; | ||
151 | }; | ||
152 | |||
153 | #define rtl_usbpriv(hw) (((struct rtl_usb_priv *)(rtl_priv(hw))->priv)) | ||
154 | #define rtl_usbdev(usbpriv) (&((usbpriv)->dev)) | ||
155 | |||
156 | |||
157 | |||
158 | int __devinit rtl_usb_probe(struct usb_interface *intf, | ||
159 | const struct usb_device_id *id); | ||
160 | void rtl_usb_disconnect(struct usb_interface *intf); | ||
161 | int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message); | ||
162 | int rtl_usb_resume(struct usb_interface *pusb_intf); | ||
163 | |||
164 | #endif | ||