| @@ -1,1044 +1,1044 @@ | | | @@ -1,1044 +1,1044 @@ |
1 | /* $NetBSD: if_urtwn.c,v 1.59.2.11 2020/04/16 17:24:49 nat Exp $ */ | | 1 | /* $NetBSD: if_urtwn.c,v 1.59.2.12 2020/04/17 13:44:37 martin Exp $ */ |
2 | /* $OpenBSD: if_urtwn.c,v 1.42 2015/02/10 23:25:46 mpi Exp $ */ | | 2 | /* $OpenBSD: if_urtwn.c,v 1.42 2015/02/10 23:25:46 mpi Exp $ */ |
3 | | | 3 | |
4 | /*- | | 4 | /*- |
5 | * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> | | 5 | * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> |
6 | * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> | | 6 | * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> |
7 | * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> | | 7 | * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> |
8 | * | | 8 | * |
9 | * Permission to use, copy, modify, and distribute this software for any | | 9 | * Permission to use, copy, modify, and distribute this software for any |
10 | * purpose with or without fee is hereby granted, provided that the above | | 10 | * purpose with or without fee is hereby granted, provided that the above |
11 | * copyright notice and this permission notice appear in all copies. | | 11 | * copyright notice and this permission notice appear in all copies. |
12 | * | | 12 | * |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
20 | */ | | 20 | */ |
21 | | | 21 | |
22 | /* Some code taken from FreeBSD dev/usb/wlan/if_urtw.c with copyright */ | | 22 | /* Some code taken from FreeBSD dev/usb/wlan/if_urtw.c with copyright */ |
23 | /*- | | 23 | /*- |
24 | * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org> | | 24 | * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org> |
25 | * | | 25 | * |
26 | * Permission to use, copy, modify, and distribute this software for any | | 26 | * Permission to use, copy, modify, and distribute this software for any |
27 | * purpose with or without fee is hereby granted, provided that the above | | 27 | * purpose with or without fee is hereby granted, provided that the above |
28 | * copyright notice and this permission notice appear in all copies. | | 28 | * copyright notice and this permission notice appear in all copies. |
29 | * | | 29 | * |
30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | /*- | | 39 | /*- |
40 | * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU | | 40 | * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU |
41 | * RTL8192EU. | | 41 | * RTL8192EU. |
42 | */ | | 42 | */ |
43 | | | 43 | |
44 | #include <sys/cdefs.h> | | 44 | #include <sys/cdefs.h> |
45 | __KERNEL_RCSID(0, "$NetBSD: if_urtwn.c,v 1.59.2.11 2020/04/16 17:24:49 nat Exp $"); | | 45 | __KERNEL_RCSID(0, "$NetBSD: if_urtwn.c,v 1.59.2.12 2020/04/17 13:44:37 martin Exp $"); |
46 | | | 46 | |
47 | #ifdef _KERNEL_OPT | | 47 | #ifdef _KERNEL_OPT |
48 | #include "opt_inet.h" | | 48 | #include "opt_inet.h" |
49 | #include "opt_usb.h" | | 49 | #include "opt_usb.h" |
50 | #endif | | 50 | #endif |
51 | | | 51 | |
52 | #include <sys/param.h> | | 52 | #include <sys/param.h> |
53 | #include <sys/sockio.h> | | 53 | #include <sys/sockio.h> |
54 | #include <sys/sysctl.h> | | 54 | #include <sys/sysctl.h> |
55 | #include <sys/mbuf.h> | | 55 | #include <sys/mbuf.h> |
56 | #include <sys/kernel.h> | | 56 | #include <sys/kernel.h> |
57 | #include <sys/kmem.h> | | 57 | #include <sys/kmem.h> |
58 | #include <sys/socket.h> | | 58 | #include <sys/socket.h> |
59 | #include <sys/systm.h> | | 59 | #include <sys/systm.h> |
60 | #include <sys/module.h> | | 60 | #include <sys/module.h> |
61 | #include <sys/conf.h> | | 61 | #include <sys/conf.h> |
62 | #include <sys/device.h> | | 62 | #include <sys/device.h> |
63 | | | 63 | |
64 | #include <sys/bus.h> | | 64 | #include <sys/bus.h> |
65 | #include <machine/endian.h> | | 65 | #include <machine/endian.h> |
66 | #include <sys/intr.h> | | 66 | #include <sys/intr.h> |
67 | | | 67 | |
68 | #include <net/bpf.h> | | 68 | #include <net/bpf.h> |
69 | #include <net/if.h> | | 69 | #include <net/if.h> |
70 | #include <net/if_arp.h> | | 70 | #include <net/if_arp.h> |
71 | #include <net/if_dl.h> | | 71 | #include <net/if_dl.h> |
72 | #include <net/if_ether.h> | | 72 | #include <net/if_ether.h> |
73 | #include <net/if_media.h> | | 73 | #include <net/if_media.h> |
74 | #include <net/if_types.h> | | 74 | #include <net/if_types.h> |
75 | | | 75 | |
76 | #include <netinet/in.h> | | 76 | #include <netinet/in.h> |
77 | #include <netinet/in_systm.h> | | 77 | #include <netinet/in_systm.h> |
78 | #include <netinet/in_var.h> | | 78 | #include <netinet/in_var.h> |
79 | #include <netinet/ip.h> | | 79 | #include <netinet/ip.h> |
80 | #include <netinet/if_inarp.h> | | 80 | #include <netinet/if_inarp.h> |
81 | | | 81 | |
82 | #include <net80211/ieee80211_netbsd.h> | | 82 | #include <net80211/ieee80211_netbsd.h> |
83 | #include <net80211/ieee80211_var.h> | | 83 | #include <net80211/ieee80211_var.h> |
84 | #include <net80211/ieee80211_radiotap.h> | | 84 | #include <net80211/ieee80211_radiotap.h> |
85 | | | 85 | |
86 | #include <dev/firmload.h> | | 86 | #include <dev/firmload.h> |
87 | | | 87 | |
88 | #include <dev/usb/usb.h> | | 88 | #include <dev/usb/usb.h> |
89 | #include <dev/usb/usbdi.h> | | 89 | #include <dev/usb/usbdi.h> |
90 | #include <dev/usb/usbdivar.h> | | 90 | #include <dev/usb/usbdivar.h> |
91 | #include <dev/usb/usbdi_util.h> | | 91 | #include <dev/usb/usbdi_util.h> |
92 | #include <dev/usb/usbdevs.h> | | 92 | #include <dev/usb/usbdevs.h> |
93 | | | 93 | |
94 | #include <dev/ic/rtwnreg.h> | | 94 | #include <dev/ic/rtwnreg.h> |
95 | #include <dev/ic/rtwn_data.h> | | 95 | #include <dev/ic/rtwn_data.h> |
96 | #include <dev/usb/if_urtwnreg.h> | | 96 | #include <dev/usb/if_urtwnreg.h> |
97 | #include <dev/usb/if_urtwnvar.h> | | 97 | #include <dev/usb/if_urtwnvar.h> |
98 | | | 98 | |
99 | /* | | 99 | /* |
100 | * The sc_write_mtx locking is to prevent sequences of writes from | | 100 | * The sc_write_mtx locking is to prevent sequences of writes from |
101 | * being intermingled with each other. I don't know if this is really | | 101 | * being intermingled with each other. I don't know if this is really |
102 | * needed. I have added it just to be on the safe side. | | 102 | * needed. I have added it just to be on the safe side. |
103 | */ | | 103 | */ |
104 | | | 104 | |
105 | #ifdef URTWN_DEBUG | | 105 | #ifdef URTWN_DEBUG |
106 | #define DBG_INIT __BIT(0) | | 106 | #define DBG_INIT __BIT(0) |
107 | #define DBG_FN __BIT(1) | | 107 | #define DBG_FN __BIT(1) |
108 | #define DBG_TX __BIT(2) | | 108 | #define DBG_TX __BIT(2) |
109 | #define DBG_RX __BIT(3) | | 109 | #define DBG_RX __BIT(3) |
110 | #define DBG_STM __BIT(4) | | 110 | #define DBG_STM __BIT(4) |
111 | #define DBG_RF __BIT(5) | | 111 | #define DBG_RF __BIT(5) |
112 | #define DBG_REG __BIT(6) | | 112 | #define DBG_REG __BIT(6) |
113 | #define DBG_ALL 0xffffffffU | | 113 | #define DBG_ALL 0xffffffffU |
114 | /* NNN Reset urtwn_debug to 0 when done debugging. */ | | 114 | /* NNN Reset urtwn_debug to 0 when done debugging. */ |
115 | u_int urtwn_debug = 0; | | 115 | u_int urtwn_debug = 0; |
116 | #define DPRINTFN(n, s) \ | | 116 | #define DPRINTFN(n, s) \ |
117 | do { if (urtwn_debug & (n)) printf s; } while (/*CONSTCOND*/0) | | 117 | do { if (urtwn_debug & (n)) printf s; } while (/*CONSTCOND*/0) |
118 | #else | | 118 | #else |
119 | #define DPRINTFN(n, s) | | 119 | #define DPRINTFN(n, s) |
120 | #endif | | 120 | #endif |
121 | | | 121 | |
122 | #define URTWN_DEV(v,p) { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, 0 } | | 122 | #define URTWN_DEV(v,p) { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, 0 } |
123 | #define URTWN_RTL8188E_DEV(v,p) \ | | 123 | #define URTWN_RTL8188E_DEV(v,p) \ |
124 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8188E } | | 124 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8188E } |
125 | #define URTWN_RTL8192EU_DEV(v,p) \ | | 125 | #define URTWN_RTL8192EU_DEV(v,p) \ |
126 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8192E } | | 126 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8192E } |
127 | static const struct urtwn_dev { | | 127 | static const struct urtwn_dev { |
128 | struct usb_devno dev; | | 128 | struct usb_devno dev; |
129 | uint32_t flags; | | 129 | uint32_t flags; |
130 | #define FLAG_RTL8188E __BIT(0) | | 130 | #define FLAG_RTL8188E __BIT(0) |
131 | #define FLAG_RTL8192E __BIT(1) | | 131 | #define FLAG_RTL8192E __BIT(1) |
132 | } urtwn_devs[] = { | | 132 | } urtwn_devs[] = { |
133 | URTWN_DEV(ABOCOM, RTL8188CU_1), | | 133 | URTWN_DEV(ABOCOM, RTL8188CU_1), |
134 | URTWN_DEV(ABOCOM, RTL8188CU_2), | | 134 | URTWN_DEV(ABOCOM, RTL8188CU_2), |
135 | URTWN_DEV(ABOCOM, RTL8192CU), | | 135 | URTWN_DEV(ABOCOM, RTL8192CU), |
136 | URTWN_DEV(ASUSTEK, RTL8192CU), | | 136 | URTWN_DEV(ASUSTEK, RTL8192CU), |
137 | URTWN_DEV(ASUSTEK, RTL8192CU_3), | | 137 | URTWN_DEV(ASUSTEK, RTL8192CU_3), |
138 | URTWN_DEV(ASUSTEK, USBN10NANO), | | 138 | URTWN_DEV(ASUSTEK, USBN10NANO), |
139 | URTWN_DEV(ASUSTEK, RTL8192CU_3), | | 139 | URTWN_DEV(ASUSTEK, RTL8192CU_3), |
140 | URTWN_DEV(AZUREWAVE, RTL8188CE_1), | | 140 | URTWN_DEV(AZUREWAVE, RTL8188CE_1), |
141 | URTWN_DEV(AZUREWAVE, RTL8188CE_2), | | 141 | URTWN_DEV(AZUREWAVE, RTL8188CE_2), |
142 | URTWN_DEV(AZUREWAVE, RTL8188CU), | | 142 | URTWN_DEV(AZUREWAVE, RTL8188CU), |
143 | URTWN_DEV(BELKIN, F7D2102), | | 143 | URTWN_DEV(BELKIN, F7D2102), |
144 | URTWN_DEV(BELKIN, RTL8188CU), | | 144 | URTWN_DEV(BELKIN, RTL8188CU), |
145 | URTWN_DEV(BELKIN, RTL8188CUS), | | 145 | URTWN_DEV(BELKIN, RTL8188CUS), |
146 | URTWN_DEV(BELKIN, RTL8192CU), | | 146 | URTWN_DEV(BELKIN, RTL8192CU), |
147 | URTWN_DEV(BELKIN, RTL8192CU_1), | | 147 | URTWN_DEV(BELKIN, RTL8192CU_1), |
148 | URTWN_DEV(BELKIN, RTL8192CU_2), | | 148 | URTWN_DEV(BELKIN, RTL8192CU_2), |
149 | URTWN_DEV(CHICONY, RTL8188CUS_1), | | 149 | URTWN_DEV(CHICONY, RTL8188CUS_1), |
150 | URTWN_DEV(CHICONY, RTL8188CUS_2), | | 150 | URTWN_DEV(CHICONY, RTL8188CUS_2), |
151 | URTWN_DEV(CHICONY, RTL8188CUS_3), | | 151 | URTWN_DEV(CHICONY, RTL8188CUS_3), |
152 | URTWN_DEV(CHICONY, RTL8188CUS_4), | | 152 | URTWN_DEV(CHICONY, RTL8188CUS_4), |
153 | URTWN_DEV(CHICONY, RTL8188CUS_5), | | 153 | URTWN_DEV(CHICONY, RTL8188CUS_5), |
154 | URTWN_DEV(CHICONY, RTL8188CUS_6), | | 154 | URTWN_DEV(CHICONY, RTL8188CUS_6), |
155 | URTWN_DEV(COMPARE, RTL8192CU), | | 155 | URTWN_DEV(COMPARE, RTL8192CU), |
156 | URTWN_DEV(COREGA, RTL8192CU), | | 156 | URTWN_DEV(COREGA, RTL8192CU), |
157 | URTWN_DEV(DLINK, DWA131B), | | 157 | URTWN_DEV(DLINK, DWA131B), |
158 | URTWN_DEV(DLINK, RTL8188CU), | | 158 | URTWN_DEV(DLINK, RTL8188CU), |
159 | URTWN_DEV(DLINK, RTL8192CU_1), | | 159 | URTWN_DEV(DLINK, RTL8192CU_1), |
160 | URTWN_DEV(DLINK, RTL8192CU_2), | | 160 | URTWN_DEV(DLINK, RTL8192CU_2), |
161 | URTWN_DEV(DLINK, RTL8192CU_3), | | 161 | URTWN_DEV(DLINK, RTL8192CU_3), |
162 | URTWN_DEV(DLINK, RTL8192CU_4), | | 162 | URTWN_DEV(DLINK, RTL8192CU_4), |
163 | URTWN_DEV(EDIMAX, RTL8188CU), | | 163 | URTWN_DEV(EDIMAX, RTL8188CU), |
164 | URTWN_DEV(EDIMAX, RTL8192CU), | | 164 | URTWN_DEV(EDIMAX, RTL8192CU), |
165 | URTWN_DEV(FEIXUN, RTL8188CU), | | 165 | URTWN_DEV(FEIXUN, RTL8188CU), |
166 | URTWN_DEV(FEIXUN, RTL8192CU), | | 166 | URTWN_DEV(FEIXUN, RTL8192CU), |
167 | URTWN_DEV(GUILLEMOT, HWNUP150), | | 167 | URTWN_DEV(GUILLEMOT, HWNUP150), |
168 | URTWN_DEV(GUILLEMOT, RTL8192CU), | | 168 | URTWN_DEV(GUILLEMOT, RTL8192CU), |
169 | URTWN_DEV(HAWKING, RTL8192CU), | | 169 | URTWN_DEV(HAWKING, RTL8192CU), |
170 | URTWN_DEV(HAWKING, RTL8192CU_2), | | 170 | URTWN_DEV(HAWKING, RTL8192CU_2), |
171 | URTWN_DEV(HP3, RTL8188CU), | | 171 | URTWN_DEV(HP3, RTL8188CU), |
172 | URTWN_DEV(IODATA, WNG150UM), | | 172 | URTWN_DEV(IODATA, WNG150UM), |
173 | URTWN_DEV(IODATA, RTL8192CU), | | 173 | URTWN_DEV(IODATA, RTL8192CU), |
174 | URTWN_DEV(NETGEAR, WNA1000M), | | 174 | URTWN_DEV(NETGEAR, WNA1000M), |
175 | URTWN_DEV(NETGEAR, RTL8192CU), | | 175 | URTWN_DEV(NETGEAR, RTL8192CU), |
176 | URTWN_DEV(NETGEAR4, RTL8188CU), | | 176 | URTWN_DEV(NETGEAR4, RTL8188CU), |
177 | URTWN_DEV(NOVATECH, RTL8188CU), | | 177 | URTWN_DEV(NOVATECH, RTL8188CU), |
178 | URTWN_DEV(PLANEX2, RTL8188CU_1), | | 178 | URTWN_DEV(PLANEX2, RTL8188CU_1), |
179 | URTWN_DEV(PLANEX2, RTL8188CU_2), | | 179 | URTWN_DEV(PLANEX2, RTL8188CU_2), |
180 | URTWN_DEV(PLANEX2, RTL8192CU), | | 180 | URTWN_DEV(PLANEX2, RTL8192CU), |
181 | URTWN_DEV(PLANEX2, RTL8188CU_3), | | 181 | URTWN_DEV(PLANEX2, RTL8188CU_3), |
182 | URTWN_DEV(PLANEX2, RTL8188CU_4), | | 182 | URTWN_DEV(PLANEX2, RTL8188CU_4), |
183 | URTWN_DEV(PLANEX2, RTL8188CUS), | | 183 | URTWN_DEV(PLANEX2, RTL8188CUS), |
184 | URTWN_DEV(REALTEK, RTL8188CE_0), | | 184 | URTWN_DEV(REALTEK, RTL8188CE_0), |
185 | URTWN_DEV(REALTEK, RTL8188CE_1), | | 185 | URTWN_DEV(REALTEK, RTL8188CE_1), |
186 | URTWN_DEV(REALTEK, RTL8188CTV), | | 186 | URTWN_DEV(REALTEK, RTL8188CTV), |
187 | URTWN_DEV(REALTEK, RTL8188CU_0), | | 187 | URTWN_DEV(REALTEK, RTL8188CU_0), |
188 | URTWN_DEV(REALTEK, RTL8188CU_1), | | 188 | URTWN_DEV(REALTEK, RTL8188CU_1), |
189 | URTWN_DEV(REALTEK, RTL8188CU_2), | | 189 | URTWN_DEV(REALTEK, RTL8188CU_2), |
190 | URTWN_DEV(REALTEK, RTL8188CU_3), | | 190 | URTWN_DEV(REALTEK, RTL8188CU_3), |
191 | URTWN_DEV(REALTEK, RTL8188CU_COMBO), | | 191 | URTWN_DEV(REALTEK, RTL8188CU_COMBO), |
192 | URTWN_DEV(REALTEK, RTL8188CUS), | | 192 | URTWN_DEV(REALTEK, RTL8188CUS), |
193 | URTWN_DEV(REALTEK, RTL8188RU), | | 193 | URTWN_DEV(REALTEK, RTL8188RU), |
194 | URTWN_DEV(REALTEK, RTL8188RU_2), | | 194 | URTWN_DEV(REALTEK, RTL8188RU_2), |
195 | URTWN_DEV(REALTEK, RTL8188RU_3), | | 195 | URTWN_DEV(REALTEK, RTL8188RU_3), |
196 | URTWN_DEV(REALTEK, RTL8191CU), | | 196 | URTWN_DEV(REALTEK, RTL8191CU), |
197 | URTWN_DEV(REALTEK, RTL8192CE), | | 197 | URTWN_DEV(REALTEK, RTL8192CE), |
198 | URTWN_DEV(REALTEK, RTL8192CU), | | 198 | URTWN_DEV(REALTEK, RTL8192CU), |
199 | URTWN_DEV(SITECOMEU, RTL8188CU), | | 199 | URTWN_DEV(SITECOMEU, RTL8188CU), |
200 | URTWN_DEV(SITECOMEU, RTL8188CU_2), | | 200 | URTWN_DEV(SITECOMEU, RTL8188CU_2), |
201 | URTWN_DEV(SITECOMEU, RTL8192CU), | | 201 | URTWN_DEV(SITECOMEU, RTL8192CU), |
202 | URTWN_DEV(SITECOMEU, RTL8192CUR2), | | 202 | URTWN_DEV(SITECOMEU, RTL8192CUR2), |
203 | URTWN_DEV(TPLINK, RTL8192CU), | | 203 | URTWN_DEV(TPLINK, RTL8192CU), |
204 | URTWN_DEV(TRENDNET, RTL8188CU), | | 204 | URTWN_DEV(TRENDNET, RTL8188CU), |
205 | URTWN_DEV(TRENDNET, RTL8192CU), | | 205 | URTWN_DEV(TRENDNET, RTL8192CU), |
206 | URTWN_DEV(ZYXEL, RTL8192CU), | | 206 | URTWN_DEV(ZYXEL, RTL8192CU), |
207 | | | 207 | |
208 | /* URTWN_RTL8188E */ | | 208 | /* URTWN_RTL8188E */ |
209 | URTWN_RTL8188E_DEV(DLINK, DWA125D1), | | 209 | URTWN_RTL8188E_DEV(DLINK, DWA125D1), |
210 | URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), | | 210 | URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), |
211 | URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), | | 211 | URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), |
212 | URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), | | 212 | URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), |
213 | URTWN_RTL8188E_DEV(ABOCOM, RTL8188EU), | | 213 | URTWN_RTL8188E_DEV(ABOCOM, RTL8188EU), |
214 | URTWN_RTL8188E_DEV(TPLINK, RTL8188EU), | | 214 | URTWN_RTL8188E_DEV(TPLINK, RTL8188EU), |
215 | URTWN_RTL8188E_DEV(DLINK, DWA121B1), | | 215 | URTWN_RTL8188E_DEV(DLINK, DWA121B1), |
216 | | | 216 | |
217 | /* URTWN_RTL8192EU */ | | 217 | /* URTWN_RTL8192EU */ |
218 | URTWN_RTL8192EU_DEV(DLINK, DWA131E), | | 218 | URTWN_RTL8192EU_DEV(DLINK, DWA131E), |
219 | URTWN_RTL8192EU_DEV(REALTEK, RTL8192EU), | | 219 | URTWN_RTL8192EU_DEV(REALTEK, RTL8192EU), |
220 | URTWN_RTL8192EU_DEV(TPLINK, RTL8192EU), | | 220 | URTWN_RTL8192EU_DEV(TPLINK, RTL8192EU), |
221 | }; | | 221 | }; |
222 | #undef URTWN_DEV | | 222 | #undef URTWN_DEV |
223 | #undef URTWN_RTL8188E_DEV | | 223 | #undef URTWN_RTL8188E_DEV |
224 | #undef URTWN_RTL8192EU_DEV | | 224 | #undef URTWN_RTL8192EU_DEV |
225 | | | 225 | |
226 | /* urtwn data */ | | 226 | /* urtwn data */ |
227 | static const uint8_t urtwn_chan_2ghz[] = | | 227 | static const uint8_t urtwn_chan_2ghz[] = |
228 | { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; | | 228 | { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; |
229 | | | 229 | |
230 | | | 230 | |
231 | static int urtwn_match(device_t, cfdata_t, void *); | | 231 | static int urtwn_match(device_t, cfdata_t, void *); |
232 | static void urtwn_attach(device_t, device_t, void *); | | 232 | static void urtwn_attach(device_t, device_t, void *); |
233 | static int urtwn_detach(device_t, int); | | 233 | static int urtwn_detach(device_t, int); |
234 | static int urtwn_activate(device_t, enum devact); | | 234 | static int urtwn_activate(device_t, enum devact); |
235 | | | 235 | |
236 | CFATTACH_DECL_NEW(urtwn, sizeof(struct urtwn_softc), urtwn_match, | | 236 | CFATTACH_DECL_NEW(urtwn, sizeof(struct urtwn_softc), urtwn_match, |
237 | urtwn_attach, urtwn_detach, urtwn_activate); | | 237 | urtwn_attach, urtwn_detach, urtwn_activate); |
238 | | | 238 | |
239 | static int urtwn_open_pipes(struct urtwn_softc *); | | 239 | static int urtwn_open_pipes(struct urtwn_softc *); |
240 | static void urtwn_close_pipes(struct urtwn_softc *); | | 240 | static void urtwn_close_pipes(struct urtwn_softc *); |
241 | static int urtwn_alloc_rx_list(struct urtwn_softc *); | | 241 | static int urtwn_alloc_rx_list(struct urtwn_softc *); |
242 | static void urtwn_free_rx_list(struct urtwn_softc *); | | 242 | static void urtwn_free_rx_list(struct urtwn_softc *); |
243 | static int urtwn_alloc_tx_list(struct urtwn_softc *); | | 243 | static int urtwn_alloc_tx_list(struct urtwn_softc *); |
244 | static void urtwn_free_tx_list(struct urtwn_softc *); | | 244 | static void urtwn_free_tx_list(struct urtwn_softc *); |
245 | static void urtwn_task(void *); | | 245 | static void urtwn_task(void *); |
246 | static void urtwn_do_async(struct urtwn_softc *, | | 246 | static void urtwn_do_async(struct urtwn_softc *, |
247 | void (*)(struct urtwn_softc *, void *), void *, int); | | 247 | void (*)(struct urtwn_softc *, void *), void *, int); |
248 | static void urtwn_wait_async(struct urtwn_softc *); | | 248 | static void urtwn_wait_async(struct urtwn_softc *); |
249 | static int urtwn_write_region_1(struct urtwn_softc *, uint16_t, uint8_t *, | | 249 | static int urtwn_write_region_1(struct urtwn_softc *, uint16_t, uint8_t *, |
250 | int); | | 250 | int); |
251 | static void urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); | | 251 | static void urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); |
252 | static void urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); | | 252 | static void urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); |
253 | static void urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); | | 253 | static void urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); |
254 | static int urtwn_write_region(struct urtwn_softc *, uint16_t, uint8_t *, | | 254 | static int urtwn_write_region(struct urtwn_softc *, uint16_t, uint8_t *, |
255 | int); | | 255 | int); |
256 | static int urtwn_read_region_1(struct urtwn_softc *, uint16_t, uint8_t *, | | 256 | static int urtwn_read_region_1(struct urtwn_softc *, uint16_t, uint8_t *, |
257 | int); | | 257 | int); |
258 | static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); | | 258 | static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); |
259 | static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); | | 259 | static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); |
260 | static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); | | 260 | static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); |
261 | static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, const void *, int); | | 261 | static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, const void *, int); |
262 | static void urtwn_r92c_rf_write(struct urtwn_softc *, int, uint8_t, | | 262 | static void urtwn_r92c_rf_write(struct urtwn_softc *, int, uint8_t, |
263 | uint32_t); | | 263 | uint32_t); |
264 | static void urtwn_r88e_rf_write(struct urtwn_softc *, int, uint8_t, | | 264 | static void urtwn_r88e_rf_write(struct urtwn_softc *, int, uint8_t, |
265 | uint32_t); | | 265 | uint32_t); |
266 | static void urtwn_r92e_rf_write(struct urtwn_softc *, int, uint8_t, | | 266 | static void urtwn_r92e_rf_write(struct urtwn_softc *, int, uint8_t, |
267 | uint32_t); | | 267 | uint32_t); |
268 | static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); | | 268 | static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); |
269 | static int urtwn_llt_write(struct urtwn_softc *, uint32_t, uint32_t); | | 269 | static int urtwn_llt_write(struct urtwn_softc *, uint32_t, uint32_t); |
270 | static uint8_t urtwn_efuse_read_1(struct urtwn_softc *, uint16_t); | | 270 | static uint8_t urtwn_efuse_read_1(struct urtwn_softc *, uint16_t); |
271 | static void urtwn_efuse_read(struct urtwn_softc *); | | 271 | static void urtwn_efuse_read(struct urtwn_softc *); |
272 | static void urtwn_efuse_switch_power(struct urtwn_softc *); | | 272 | static void urtwn_efuse_switch_power(struct urtwn_softc *); |
273 | static int urtwn_read_chipid(struct urtwn_softc *); | | 273 | static int urtwn_read_chipid(struct urtwn_softc *); |
274 | #ifdef URTWN_DEBUG | | 274 | #ifdef URTWN_DEBUG |
275 | static void urtwn_dump_rom(struct urtwn_softc *, struct r92c_rom *); | | 275 | static void urtwn_dump_rom(struct urtwn_softc *, struct r92c_rom *); |
276 | #endif | | 276 | #endif |
277 | static void urtwn_read_rom(struct urtwn_softc *); | | 277 | static void urtwn_read_rom(struct urtwn_softc *); |
278 | static void urtwn_r88e_read_rom(struct urtwn_softc *); | | 278 | static void urtwn_r88e_read_rom(struct urtwn_softc *); |
279 | static int urtwn_media_change(struct ifnet *); | | 279 | static int urtwn_media_change(struct ifnet *); |
280 | static int urtwn_ra_init(struct ieee80211vap *); | | 280 | static int urtwn_ra_init(struct ieee80211vap *); |
281 | static int urtwn_get_nettype(struct urtwn_softc *); | | 281 | static int urtwn_get_nettype(struct urtwn_softc *); |
282 | static void urtwn_set_nettype0_msr(struct urtwn_softc *, uint8_t); | | 282 | static void urtwn_set_nettype0_msr(struct urtwn_softc *, uint8_t); |
283 | static void urtwn_tsf_sync_enable(struct urtwn_softc *); | | 283 | static void urtwn_tsf_sync_enable(struct urtwn_softc *); |
284 | static void urtwn_set_led(struct urtwn_softc *, int, int); | | 284 | static void urtwn_set_led(struct urtwn_softc *, int, int); |
285 | static void urtwn_calib_to(void *); | | 285 | static void urtwn_calib_to(void *); |
286 | static void urtwn_calib_to_cb(struct urtwn_softc *, void *); | | 286 | static void urtwn_calib_to_cb(struct urtwn_softc *, void *); |
287 | static void urtwn_next_scan(void *); | | 287 | static void urtwn_next_scan(void *); |
288 | static int urtwn_newstate(struct ieee80211vap *, enum ieee80211_state, | | 288 | static int urtwn_newstate(struct ieee80211vap *, enum ieee80211_state, |
289 | int); | | 289 | int); |
290 | //static void urtwn_newstate_cb(struct urtwn_softc *, void *); | | 290 | //static void urtwn_newstate_cb(struct urtwn_softc *, void *); |
291 | static int urtwn_wme_update(struct ieee80211com *); | | 291 | static int urtwn_wme_update(struct ieee80211com *); |
292 | static void urtwn_wme_update_cb(struct urtwn_softc *, void *); | | 292 | static void urtwn_wme_update_cb(struct urtwn_softc *, void *); |
293 | static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); | | 293 | static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); |
294 | static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); | | 294 | static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); |
295 | static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); | | 295 | static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); |
296 | static void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int); | | 296 | static void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int); |
297 | static void urtwn_rxeof(struct usbd_xfer *, void *, usbd_status); | | 297 | static void urtwn_rxeof(struct usbd_xfer *, void *, usbd_status); |
298 | static void urtwn_txeof(struct usbd_xfer *, void *, usbd_status); | | 298 | static void urtwn_txeof(struct usbd_xfer *, void *, usbd_status); |
299 | static int urtwn_tx(struct urtwn_softc *, struct mbuf *, | | 299 | static int urtwn_tx(struct urtwn_softc *, struct mbuf *, |
300 | struct ieee80211_node *, struct urtwn_tx_data *); | | 300 | struct ieee80211_node *, struct urtwn_tx_data *); |
301 | static struct urtwn_tx_data * | | 301 | static struct urtwn_tx_data * |
302 | urtwn_get_tx_data(struct urtwn_softc *, size_t); | | 302 | urtwn_get_tx_data(struct urtwn_softc *, size_t); |
303 | static void urtwn_start(struct ifnet *); | | 303 | static void urtwn_start(struct ifnet *); |
304 | static void urtwn_watchdog(struct ifnet *); | | 304 | static void urtwn_watchdog(struct ifnet *); |
305 | static int urtwn_r92c_power_on(struct urtwn_softc *); | | 305 | static int urtwn_r92c_power_on(struct urtwn_softc *); |
306 | static int urtwn_r92e_power_on(struct urtwn_softc *); | | 306 | static int urtwn_r92e_power_on(struct urtwn_softc *); |
307 | static int urtwn_r88e_power_on(struct urtwn_softc *); | | 307 | static int urtwn_r88e_power_on(struct urtwn_softc *); |
308 | static int urtwn_llt_init(struct urtwn_softc *); | | 308 | static int urtwn_llt_init(struct urtwn_softc *); |
309 | static void urtwn_fw_reset(struct urtwn_softc *); | | 309 | static void urtwn_fw_reset(struct urtwn_softc *); |
310 | static void urtwn_r88e_fw_reset(struct urtwn_softc *); | | 310 | static void urtwn_r88e_fw_reset(struct urtwn_softc *); |
311 | static int urtwn_fw_loadpage(struct urtwn_softc *, int, uint8_t *, int); | | 311 | static int urtwn_fw_loadpage(struct urtwn_softc *, int, uint8_t *, int); |
312 | static int urtwn_load_firmware(struct urtwn_softc *); | | 312 | static int urtwn_load_firmware(struct urtwn_softc *); |
313 | static int urtwn_r92c_dma_init(struct urtwn_softc *); | | 313 | static int urtwn_r92c_dma_init(struct urtwn_softc *); |
314 | static int urtwn_r88e_dma_init(struct urtwn_softc *); | | 314 | static int urtwn_r88e_dma_init(struct urtwn_softc *); |
315 | static void urtwn_mac_init(struct urtwn_softc *); | | 315 | static void urtwn_mac_init(struct urtwn_softc *); |
316 | static void urtwn_bb_init(struct urtwn_softc *); | | 316 | static void urtwn_bb_init(struct urtwn_softc *); |
317 | static void urtwn_rf_init(struct urtwn_softc *); | | 317 | static void urtwn_rf_init(struct urtwn_softc *); |
318 | static void urtwn_cam_init(struct urtwn_softc *); | | 318 | static void urtwn_cam_init(struct urtwn_softc *); |
319 | static void urtwn_pa_bias_init(struct urtwn_softc *); | | 319 | static void urtwn_pa_bias_init(struct urtwn_softc *); |
320 | static void urtwn_rxfilter_init(struct urtwn_softc *); | | 320 | static void urtwn_rxfilter_init(struct urtwn_softc *); |
321 | static void urtwn_edca_init(struct urtwn_softc *); | | 321 | static void urtwn_edca_init(struct urtwn_softc *); |
322 | static void urtwn_write_txpower(struct urtwn_softc *, int, uint16_t[]); | | 322 | static void urtwn_write_txpower(struct urtwn_softc *, int, uint16_t[]); |
323 | static void urtwn_get_txpower(struct urtwn_softc *, size_t, u_int, u_int, | | 323 | static void urtwn_get_txpower(struct urtwn_softc *, size_t, u_int, u_int, |
324 | uint16_t[]); | | 324 | uint16_t[]); |
325 | static void urtwn_r88e_get_txpower(struct urtwn_softc *, size_t, u_int, | | 325 | static void urtwn_r88e_get_txpower(struct urtwn_softc *, size_t, u_int, |
326 | u_int, uint16_t[]); | | 326 | u_int, uint16_t[]); |
327 | static void urtwn_set_txpower(struct urtwn_softc *, u_int, u_int); | | 327 | static void urtwn_set_txpower(struct urtwn_softc *, u_int, u_int); |
328 | static void urtwn_set_chan(struct urtwn_softc *, struct ieee80211_channel *, | | 328 | static void urtwn_set_chan(struct urtwn_softc *, struct ieee80211_channel *, |
329 | u_int); | | 329 | u_int); |
330 | static void urtwn_iq_calib(struct urtwn_softc *, bool); | | 330 | static void urtwn_iq_calib(struct urtwn_softc *, bool); |
331 | static void urtwn_lc_calib(struct urtwn_softc *); | | 331 | static void urtwn_lc_calib(struct urtwn_softc *); |
332 | static void urtwn_temp_calib(struct urtwn_softc *); | | 332 | static void urtwn_temp_calib(struct urtwn_softc *); |
333 | static int urtwn_init(struct ifnet *); | | 333 | static int urtwn_init(struct ifnet *); |
334 | static void urtwn_stop(struct ifnet *, int); | | 334 | static void urtwn_stop(struct ifnet *, int); |
335 | static int urtwn_reset(struct ieee80211vap *, u_long); | | 335 | static int urtwn_reset(struct ieee80211vap *, u_long); |
336 | static void urtwn_chip_stop(struct urtwn_softc *); | | 336 | static void urtwn_chip_stop(struct urtwn_softc *); |
337 | static void urtwn_newassoc(struct ieee80211_node *, int); | | 337 | static void urtwn_newassoc(struct ieee80211_node *, int); |
338 | static void urtwn_delay_ms(struct urtwn_softc *, int ms); | | 338 | static void urtwn_delay_ms(struct urtwn_softc *, int ms); |
339 | /* Functions for wifi refresh */ | | 339 | /* Functions for wifi refresh */ |
340 | static struct ieee80211vap * | | 340 | static struct ieee80211vap * |
341 | urtwn_vap_create(struct ieee80211com *, | | 341 | urtwn_vap_create(struct ieee80211com *, |
342 | const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | | 342 | const char [IFNAMSIZ], int, enum ieee80211_opmode, int, |
343 | const uint8_t [IEEE80211_ADDR_LEN], | | 343 | const uint8_t [IEEE80211_ADDR_LEN], |
344 | const uint8_t [IEEE80211_ADDR_LEN]); | | 344 | const uint8_t [IEEE80211_ADDR_LEN]); |
345 | static void urtwn_vap_delete(struct ieee80211vap *); | | 345 | static void urtwn_vap_delete(struct ieee80211vap *); |
346 | static int urtwn_ioctl(struct ifnet *, u_long, void *); | | 346 | static int urtwn_ioctl(struct ifnet *, u_long, void *); |
347 | static void urtwn_parent(struct ieee80211com *); | | 347 | static void urtwn_parent(struct ieee80211com *); |
348 | static void urtwn_getradiocaps(struct ieee80211com *, int, int *, | | 348 | static void urtwn_getradiocaps(struct ieee80211com *, int, int *, |
349 | struct ieee80211_channel []); | | 349 | struct ieee80211_channel []); |
350 | static void urtwn_scan_start(struct ieee80211com *); | | 350 | static void urtwn_scan_start(struct ieee80211com *); |
351 | static void urtwn_scan_end(struct ieee80211com *); | | 351 | static void urtwn_scan_end(struct ieee80211com *); |
352 | static void urtwn_set_channel(struct ieee80211com *); | | 352 | static void urtwn_set_channel(struct ieee80211com *); |
353 | static int urtwn_transmit(struct ieee80211com *, struct mbuf *); | | 353 | static int urtwn_transmit(struct ieee80211com *, struct mbuf *); |
354 | static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, | | 354 | static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, |
355 | const struct ieee80211_bpf_params *); | | 355 | const struct ieee80211_bpf_params *); |
356 | //static int urtwn_send_mgmt(struct ieee80211_node *, int, int); | | 356 | //static int urtwn_send_mgmt(struct ieee80211_node *, int, int); |
357 | | | 357 | |
358 | /* Aliases. */ | | 358 | /* Aliases. */ |
359 | #define urtwn_bb_write urtwn_write_4 | | 359 | #define urtwn_bb_write urtwn_write_4 |
360 | #define urtwn_bb_read urtwn_read_4 | | 360 | #define urtwn_bb_read urtwn_read_4 |
361 | | | 361 | |
362 | #define urtwn_lookup(d,v,p) ((const struct urtwn_dev *)usb_lookup(d,v,p)) | | 362 | #define urtwn_lookup(d,v,p) ((const struct urtwn_dev *)usb_lookup(d,v,p)) |
363 | | | 363 | |
364 | static const uint16_t addaReg[] = { | | 364 | static const uint16_t addaReg[] = { |
365 | R92C_FPGA0_XCD_SWITCHCTL, R92C_BLUETOOTH, R92C_RX_WAIT_CCA, | | 365 | R92C_FPGA0_XCD_SWITCHCTL, R92C_BLUETOOTH, R92C_RX_WAIT_CCA, |
366 | R92C_TX_CCK_RFON, R92C_TX_CCK_BBON, R92C_TX_OFDM_RFON, | | 366 | R92C_TX_CCK_RFON, R92C_TX_CCK_BBON, R92C_TX_OFDM_RFON, |
367 | R92C_TX_OFDM_BBON, R92C_TX_TO_RX, R92C_TX_TO_TX, R92C_RX_CCK, | | 367 | R92C_TX_OFDM_BBON, R92C_TX_TO_RX, R92C_TX_TO_TX, R92C_RX_CCK, |
368 | R92C_RX_OFDM, R92C_RX_WAIT_RIFS, R92C_RX_TO_RX, | | 368 | R92C_RX_OFDM, R92C_RX_WAIT_RIFS, R92C_RX_TO_RX, |
369 | R92C_STANDBY, R92C_SLEEP, R92C_PMPD_ANAEN | | 369 | R92C_STANDBY, R92C_SLEEP, R92C_PMPD_ANAEN |
370 | }; | | 370 | }; |
371 | | | 371 | |
372 | static int | | 372 | static int |
373 | urtwn_match(device_t parent, cfdata_t match, void *aux) | | 373 | urtwn_match(device_t parent, cfdata_t match, void *aux) |
374 | { | | 374 | { |
375 | struct usb_attach_arg *uaa = aux; | | 375 | struct usb_attach_arg *uaa = aux; |
376 | | | 376 | |
377 | return urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product) != | | 377 | return urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product) != |
378 | NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | | 378 | NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; |
379 | } | | 379 | } |
380 | | | 380 | |
381 | static void | | 381 | static void |
382 | urtwn_attach(device_t parent, device_t self, void *aux) | | 382 | urtwn_attach(device_t parent, device_t self, void *aux) |
383 | { | | 383 | { |
384 | struct urtwn_softc *sc = device_private(self); | | 384 | struct urtwn_softc *sc = device_private(self); |
385 | struct ieee80211com *ic = &sc->sc_ic; | | 385 | struct ieee80211com *ic = &sc->sc_ic; |
386 | struct usb_attach_arg *uaa = aux; | | 386 | struct usb_attach_arg *uaa = aux; |
387 | char *devinfop; | | 387 | char *devinfop; |
388 | const struct urtwn_dev *dev; | | 388 | const struct urtwn_dev *dev; |
389 | usb_device_request_t req; | | 389 | usb_device_request_t req; |
390 | // NNN loop below size_t i; | | 390 | // NNN loop below size_t i; |
391 | int error; | | 391 | int error; |
392 | | | 392 | |
393 | sc->sc_dev = self; | | 393 | sc->sc_dev = self; |
394 | sc->sc_udev = uaa->uaa_device; | | 394 | sc->sc_udev = uaa->uaa_device; |
395 | | | 395 | |
396 | /* Name the ic. */ | | 396 | /* Name the ic. */ |
397 | ic->ic_name = "urtwn"; | | 397 | ic->ic_name = "urtwn"; |
398 | | | 398 | |
399 | /* Driver Send queue, separate from the if send queue*/ | | 399 | /* Driver Send queue, separate from the if send queue*/ |
400 | sc->sc_sendq.ifq_maxlen = 32; | | 400 | sc->sc_sendq.ifq_maxlen = 32; |
401 | /* NNN how should this be initialized? */ | | 401 | /* NNN how should this be initialized? */ |
402 | sc->sc_sendq.ifq_head = sc->sc_sendq.ifq_tail = NULL; | | 402 | sc->sc_sendq.ifq_head = sc->sc_sendq.ifq_tail = NULL; |
403 | sc->sc_sendq.ifq_len = 0; | | 403 | sc->sc_sendq.ifq_len = 0; |
404 | sc->sc_sendq.ifq_drops = 0; | | 404 | sc->sc_sendq.ifq_drops = 0; |
405 | IFQ_LOCK_INIT(&sc->sc_sendq); | | 405 | IFQ_LOCK_INIT(&sc->sc_sendq); |
406 | | | 406 | |
407 | sc->chip = 0; | | 407 | sc->chip = 0; |
408 | dev = urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product); | | 408 | dev = urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product); |
409 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8188E)) | | 409 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8188E)) |
410 | SET(sc->chip, URTWN_CHIP_88E); | | 410 | SET(sc->chip, URTWN_CHIP_88E); |
411 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8192E)) | | 411 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8192E)) |
412 | SET(sc->chip, URTWN_CHIP_92EU); | | 412 | SET(sc->chip, URTWN_CHIP_92EU); |
413 | | | 413 | |
414 | aprint_naive("\n"); | | 414 | aprint_naive("\n"); |
415 | aprint_normal("\n"); | | 415 | aprint_normal("\n"); |
416 | | | 416 | |
417 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 417 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
418 | | | 418 | |
419 | devinfop = usbd_devinfo_alloc(sc->sc_udev, 0); | | 419 | devinfop = usbd_devinfo_alloc(sc->sc_udev, 0); |
420 | aprint_normal_dev(self, "%s\n", devinfop); | | 420 | aprint_normal_dev(self, "%s\n", devinfop); |
421 | usbd_devinfo_free(devinfop); | | 421 | usbd_devinfo_free(devinfop); |
422 | | | 422 | |
423 | req.bmRequestType = UT_WRITE_DEVICE; | | 423 | req.bmRequestType = UT_WRITE_DEVICE; |
424 | req.bRequest = UR_SET_FEATURE; | | 424 | req.bRequest = UR_SET_FEATURE; |
425 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); | | 425 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); |
426 | USETW(req.wIndex, UHF_PORT_SUSPEND); | | 426 | USETW(req.wIndex, UHF_PORT_SUSPEND); |
427 | USETW(req.wLength, 0); | | 427 | USETW(req.wLength, 0); |
428 | | | 428 | |
429 | (void) usbd_do_request(sc->sc_udev, &req, 0); | | 429 | (void) usbd_do_request(sc->sc_udev, &req, 0); |
430 | | | 430 | |
431 | mutex_init(&sc->sc_task_mtx, MUTEX_DEFAULT, IPL_NET); | | 431 | mutex_init(&sc->sc_task_mtx, MUTEX_DEFAULT, IPL_NET); |
432 | mutex_init(&sc->sc_tx_mtx, MUTEX_DEFAULT, IPL_SOFTNET); | | 432 | mutex_init(&sc->sc_tx_mtx, MUTEX_DEFAULT, IPL_SOFTNET); |
433 | mutex_init(&sc->sc_rx_mtx, MUTEX_DEFAULT, IPL_SOFTNET); | | 433 | mutex_init(&sc->sc_rx_mtx, MUTEX_DEFAULT, IPL_SOFTNET); |
434 | mutex_init(&sc->sc_fwcmd_mtx, MUTEX_DEFAULT, IPL_NONE); | | 434 | mutex_init(&sc->sc_fwcmd_mtx, MUTEX_DEFAULT, IPL_NONE); |
435 | mutex_init(&sc->sc_write_mtx, MUTEX_DEFAULT, IPL_NONE); | | 435 | mutex_init(&sc->sc_write_mtx, MUTEX_DEFAULT, IPL_NONE); |
436 | | | 436 | |
437 | usb_init_task(&sc->sc_task, urtwn_task, sc, 0); | | 437 | usb_init_task(&sc->sc_task, urtwn_task, sc, 0); |
438 | | | 438 | |
439 | /* NNN make these callouts use a vap ... in vap create??? */ | | 439 | /* NNN make these callouts use a vap ... in vap create??? */ |
440 | callout_init(&sc->sc_scan_to, 0); | | 440 | callout_init(&sc->sc_scan_to, 0); |
441 | callout_setfunc(&sc->sc_scan_to, urtwn_next_scan, sc); | | 441 | callout_setfunc(&sc->sc_scan_to, urtwn_next_scan, sc); |
442 | callout_init(&sc->sc_calib_to, 0); | | 442 | callout_init(&sc->sc_calib_to, 0); |
443 | callout_setfunc(&sc->sc_calib_to, urtwn_calib_to, sc); | | 443 | callout_setfunc(&sc->sc_calib_to, urtwn_calib_to, sc); |
444 | | | 444 | |
445 | error = usbd_set_config_no(sc->sc_udev, 1, 0); | | 445 | error = usbd_set_config_no(sc->sc_udev, 1, 0); |
446 | if (error != 0) { | | 446 | if (error != 0) { |
447 | aprint_error_dev(self, "failed to set configuration" | | 447 | aprint_error_dev(self, "failed to set configuration" |
448 | ", err=%s\n", usbd_errstr(error)); | | 448 | ", err=%s\n", usbd_errstr(error)); |
449 | goto fail; | | 449 | goto fail; |
450 | } | | 450 | } |
451 | | | 451 | |
452 | /* Get the first interface handle. */ | | 452 | /* Get the first interface handle. */ |
453 | error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); | | 453 | error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); |
454 | if (error != 0) { | | 454 | if (error != 0) { |
455 | aprint_error_dev(self, "could not get interface handle\n"); | | 455 | aprint_error_dev(self, "could not get interface handle\n"); |
456 | goto fail; | | 456 | goto fail; |
457 | } | | 457 | } |
458 | | | 458 | |
459 | error = urtwn_read_chipid(sc); | | 459 | error = urtwn_read_chipid(sc); |
460 | if (error != 0) { | | 460 | if (error != 0) { |
461 | aprint_error_dev(self, "unsupported test chip\n"); | | 461 | aprint_error_dev(self, "unsupported test chip\n"); |
462 | goto fail; | | 462 | goto fail; |
463 | } | | 463 | } |
464 | | | 464 | |
465 | /* Determine number of Tx/Rx chains. */ | | 465 | /* Determine number of Tx/Rx chains. */ |
466 | if (sc->chip & URTWN_CHIP_92C) { | | 466 | if (sc->chip & URTWN_CHIP_92C) { |
467 | sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; | | 467 | sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; |
468 | sc->nrxchains = 2; | | 468 | sc->nrxchains = 2; |
469 | } else if (sc->chip & URTWN_CHIP_92EU) { | | 469 | } else if (sc->chip & URTWN_CHIP_92EU) { |
470 | sc->ntxchains = 2; | | 470 | sc->ntxchains = 2; |
471 | sc->nrxchains = 2; | | 471 | sc->nrxchains = 2; |
472 | } else { | | 472 | } else { |
473 | sc->ntxchains = 1; | | 473 | sc->ntxchains = 1; |
474 | sc->nrxchains = 1; | | 474 | sc->nrxchains = 1; |
475 | } | | 475 | } |
476 | | | 476 | |
477 | if (ISSET(sc->chip, URTWN_CHIP_88E) || | | 477 | if (ISSET(sc->chip, URTWN_CHIP_88E) || |
478 | ISSET(sc->chip, URTWN_CHIP_92EU)) | | 478 | ISSET(sc->chip, URTWN_CHIP_92EU)) |
479 | urtwn_r88e_read_rom(sc); | | 479 | urtwn_r88e_read_rom(sc); |
480 | else | | 480 | else |
481 | urtwn_read_rom(sc); | | 481 | urtwn_read_rom(sc); |
482 | | | 482 | |
483 | aprint_normal_dev(self, "MAC/BB RTL%s, RF 6052 %zdT%zdR, address %s\n", | | 483 | aprint_normal_dev(self, "MAC/BB RTL%s, RF 6052 %zdT%zdR, address %s\n", |
484 | (sc->chip & URTWN_CHIP_92EU) ? "8192EU" : | | 484 | (sc->chip & URTWN_CHIP_92EU) ? "8192EU" : |
485 | (sc->chip & URTWN_CHIP_92C) ? "8192CU" : | | 485 | (sc->chip & URTWN_CHIP_92C) ? "8192CU" : |
486 | (sc->chip & URTWN_CHIP_88E) ? "8188EU" : | | 486 | (sc->chip & URTWN_CHIP_88E) ? "8188EU" : |
487 | (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : | | 487 | (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : |
488 | (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : | | 488 | (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : |
489 | "8188CUS", sc->ntxchains, sc->nrxchains, | | 489 | "8188CUS", sc->ntxchains, sc->nrxchains, |
490 | ether_sprintf(ic->ic_macaddr)); | | 490 | ether_sprintf(ic->ic_macaddr)); |
491 | | | 491 | |
492 | error = urtwn_open_pipes(sc); | | 492 | error = urtwn_open_pipes(sc); |
493 | if (error != 0) { | | 493 | if (error != 0) { |
494 | aprint_error_dev(sc->sc_dev, "could not open pipes\n"); | | 494 | aprint_error_dev(sc->sc_dev, "could not open pipes\n"); |
495 | goto fail; | | 495 | goto fail; |
496 | } | | 496 | } |
497 | aprint_normal_dev(self, "%d rx pipe%s, %d tx pipe%s\n", | | 497 | aprint_normal_dev(self, "%d rx pipe%s, %d tx pipe%s\n", |
498 | sc->rx_npipe, sc->rx_npipe > 1 ? "s" : "", | | 498 | sc->rx_npipe, sc->rx_npipe > 1 ? "s" : "", |
499 | sc->tx_npipe, sc->tx_npipe > 1 ? "s" : ""); | | 499 | sc->tx_npipe, sc->tx_npipe > 1 ? "s" : ""); |
500 | | | 500 | |
501 | /* | | 501 | /* |
502 | * Setup the 802.11 device. | | 502 | * Setup the 802.11 device. |
503 | */ | | 503 | */ |
504 | ic->ic_softc = sc; | | 504 | ic->ic_softc = sc; |
505 | ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */ | | 505 | ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */ |
506 | ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */ | | 506 | ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */ |
507 | | | 507 | |
508 | /* Set device capabilities. */ | | 508 | /* Set device capabilities. */ |
509 | ic->ic_caps = | | 509 | ic->ic_caps = |
510 | IEEE80211_C_MONITOR | /* Monitor mode supported. */ | | 510 | IEEE80211_C_MONITOR | /* Monitor mode supported. */ |
511 | IEEE80211_C_IBSS | /* IBSS mode supported */ | | 511 | IEEE80211_C_IBSS | /* IBSS mode supported */ |
512 | IEEE80211_C_HOSTAP | /* HostAp mode supported */ | | 512 | IEEE80211_C_HOSTAP | /* HostAp mode supported */ |
513 | IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ | | 513 | IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ |
514 | IEEE80211_C_SHSLOT | /* Short slot time supported. */ | | 514 | IEEE80211_C_SHSLOT | /* Short slot time supported. */ |
515 | IEEE80211_C_WME | /* 802.11e */ | | 515 | IEEE80211_C_WME | /* 802.11e */ |
516 | IEEE80211_C_WPA; /* 802.11i */ | | 516 | IEEE80211_C_WPA; /* 802.11i */ |
517 | | | 517 | |
518 | ic->ic_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 518 | ic->ic_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
519 | | | 519 | |
520 | #ifdef should_delete_NNN | | 520 | #ifdef should_delete_NNN |
521 | /* Set supported .11b and .11g channels (1 through 14). */ | | 521 | /* Set supported .11b and .11g channels (1 through 14). */ |
522 | ic->ic_nchans = 14; /* NNN ? get this from somewhere? */ | | 522 | ic->ic_nchans = 14; /* NNN ? get this from somewhere? */ |
523 | for (i = 0; i < 14; i++) { | | 523 | for (i = 0; i < 14; i++) { |
524 | ic->ic_channels[i].ic_freq = | | 524 | ic->ic_channels[i].ic_freq = |
525 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); | | 525 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); |
526 | ic->ic_channels[i].ic_flags = | | 526 | ic->ic_channels[i].ic_flags = |
527 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | | | 527 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | |
528 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; | | 528 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; |
529 | } | | 529 | } |
530 | #else | | 530 | #else |
531 | urtwn_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, | | 531 | urtwn_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, |
532 | ic->ic_channels); | | 532 | ic->ic_channels); |
533 | #endif | | 533 | #endif |
534 | /* XXX issues here ... Figure out proper attach and vap creation */ | | 534 | /* XXX issues here ... Figure out proper attach and vap creation */ |
535 | ieee80211_ifattach(ic); | | 535 | ieee80211_ifattach(ic); |
536 | | | 536 | |
537 | /* override default methods NNN Need more here? */ | | 537 | /* override default methods NNN Need more here? */ |
538 | ic->ic_newassoc = urtwn_newassoc; | | 538 | ic->ic_newassoc = urtwn_newassoc; |
539 | ic->ic_wme.wme_update = urtwn_wme_update; | | 539 | ic->ic_wme.wme_update = urtwn_wme_update; |
540 | ic->ic_vap_create = urtwn_vap_create; | | 540 | ic->ic_vap_create = urtwn_vap_create; |
541 | ic->ic_vap_delete = urtwn_vap_delete; | | 541 | ic->ic_vap_delete = urtwn_vap_delete; |
542 | ic->ic_parent = urtwn_parent; | | 542 | ic->ic_parent = urtwn_parent; |
543 | ic->ic_scan_start = urtwn_scan_start; | | 543 | ic->ic_scan_start = urtwn_scan_start; |
544 | ic->ic_scan_end = urtwn_scan_end; | | 544 | ic->ic_scan_end = urtwn_scan_end; |
545 | ic->ic_set_channel = urtwn_set_channel; | | 545 | ic->ic_set_channel = urtwn_set_channel; |
546 | ic->ic_transmit = urtwn_transmit; | | 546 | ic->ic_transmit = urtwn_transmit; |
547 | // ic->ic_send_mgmt = urtwn_send_mgmt; | | 547 | // ic->ic_send_mgmt = urtwn_send_mgmt; |
548 | ic->ic_raw_xmit = urtwn_raw_xmit; | | 548 | ic->ic_raw_xmit = urtwn_raw_xmit; |
549 | ic->ic_getradiocaps = urtwn_getradiocaps; | | 549 | ic->ic_getradiocaps = urtwn_getradiocaps; |
550 | | | 550 | |
551 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu); | | 551 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu); |
552 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); | | 552 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); |
553 | sc->sc_rxtap.wr_ihdr.it_present = htole32(URTWN_RX_RADIOTAP_PRESENT); | | 553 | sc->sc_rxtap.wr_ihdr.it_present = htole32(URTWN_RX_RADIOTAP_PRESENT); |
554 | | | 554 | |
555 | sc->sc_txtap_len = sizeof(sc->sc_txtapu); | | 555 | sc->sc_txtap_len = sizeof(sc->sc_txtapu); |
556 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); | | 556 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); |
557 | sc->sc_txtap.wt_ihdr.it_present = htole32(URTWN_TX_RADIOTAP_PRESENT); | | 557 | sc->sc_txtap.wt_ihdr.it_present = htole32(URTWN_TX_RADIOTAP_PRESENT); |
558 | | | 558 | |
559 | ieee80211_announce(ic); | | 559 | ieee80211_announce(ic); |
560 | | | 560 | |
561 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); | | 561 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); |
562 | | | 562 | |
563 | if (!pmf_device_register(self, NULL, NULL)) | | 563 | if (!pmf_device_register(self, NULL, NULL)) |
564 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 564 | aprint_error_dev(self, "couldn't establish power handler\n"); |
565 | | | 565 | |
566 | SET(sc->sc_flags, URTWN_FLAG_ATTACHED); | | 566 | SET(sc->sc_flags, URTWN_FLAG_ATTACHED); |
567 | | | 567 | |
568 | /* Should be called via an IOCTL. Temp call here for now. */ | | 568 | /* Should be called via an IOCTL. Temp call here for now. */ |
569 | | | 569 | |
570 | struct ieee80211vap *vap = | | 570 | struct ieee80211vap *vap = |
571 | urtwn_vap_create(ic, device_xname(sc->sc_dev), | | 571 | urtwn_vap_create(ic, device_xname(sc->sc_dev), |
572 | device_unit(sc->sc_dev), IEEE80211_M_STA, | | 572 | device_unit(sc->sc_dev), IEEE80211_M_STA, |
573 | IEEE80211_CLONE_MACADDR, ic->ic_macaddr, ic->ic_macaddr); | | 573 | IEEE80211_CLONE_MACADDR, ic->ic_macaddr, ic->ic_macaddr); |
574 | | | 574 | |
575 | if (vap == NULL) { | | 575 | if (vap == NULL) { |
576 | /* Didn't work ... now what! */ | | 576 | /* Didn't work ... now what! */ |
577 | printf ("NNN vap_create didn't work ...\n"); | | 577 | printf ("NNN vap_create didn't work ...\n"); |
578 | ieee80211_ifdetach(ic); | | 578 | ieee80211_ifdetach(ic); |
579 | goto fail; | | 579 | goto fail; |
580 | } | | 580 | } |
581 | | | 581 | |
582 | return; | | 582 | return; |
583 | | | 583 | |
584 | fail: | | 584 | fail: |
585 | sc->sc_dying = 1; | | 585 | sc->sc_dying = 1; |
586 | aprint_error_dev(self, "attach failed\n"); | | 586 | aprint_error_dev(self, "attach failed\n"); |
587 | } | | 587 | } |
588 | | | 588 | |
589 | static int | | 589 | static int |
590 | urtwn_detach(device_t self, int flags) | | 590 | urtwn_detach(device_t self, int flags) |
591 | { | | 591 | { |
592 | struct urtwn_softc *sc = device_private(self); | | 592 | struct urtwn_softc *sc = device_private(self); |
593 | struct ieee80211com *ic = &sc->sc_ic; | | 593 | struct ieee80211com *ic = &sc->sc_ic; |
594 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | | 594 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); |
595 | struct ifnet *ifp = vap->iv_ifp; | | 595 | struct ifnet *ifp = vap->iv_ifp; |
596 | int s; | | 596 | int s; |
597 | | | 597 | |
598 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 598 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
599 | | | 599 | |
600 | pmf_device_deregister(self); | | 600 | pmf_device_deregister(self); |
601 | | | 601 | |
602 | s = splusb(); | | 602 | s = splusb(); |
603 | | | 603 | |
604 | sc->sc_dying = 1; | | 604 | sc->sc_dying = 1; |
605 | | | 605 | |
606 | callout_halt(&sc->sc_scan_to, NULL); | | 606 | callout_halt(&sc->sc_scan_to, NULL); |
607 | callout_halt(&sc->sc_calib_to, NULL); | | 607 | callout_halt(&sc->sc_calib_to, NULL); |
608 | | | 608 | |
609 | if (ISSET(sc->sc_flags, URTWN_FLAG_ATTACHED)) { | | 609 | if (ISSET(sc->sc_flags, URTWN_FLAG_ATTACHED)) { |
610 | usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER, | | 610 | usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER, |
611 | NULL); | | 611 | NULL); |
612 | urtwn_stop(ifp, 0); | | 612 | urtwn_stop(ifp, 0); |
613 | // vap_detach(...) ?? | | 613 | // vap_detach(...) ?? |
614 | | | 614 | |
615 | ieee80211_ifdetach(&sc->sc_ic); | | 615 | ieee80211_ifdetach(&sc->sc_ic); |
616 | | | 616 | |
617 | /* Close Tx/Rx pipes. Abort done by urtwn_stop. */ | | 617 | /* Close Tx/Rx pipes. Abort done by urtwn_stop. */ |
618 | urtwn_close_pipes(sc); | | 618 | urtwn_close_pipes(sc); |
619 | } | | 619 | } |
620 | | | 620 | |
621 | /* sendq destroy */ | | 621 | /* sendq destroy */ |
622 | IFQ_PURGE(&sc->sc_sendq); | | 622 | IFQ_PURGE(&sc->sc_sendq); |
623 | IFQ_LOCK_DESTROY(&sc->sc_sendq); | | 623 | IFQ_LOCK_DESTROY(&sc->sc_sendq); |
624 | | | 624 | |
625 | splx(s); | | 625 | splx(s); |
626 | | | 626 | |
627 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); | | 627 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); |
628 | | | 628 | |
629 | callout_destroy(&sc->sc_scan_to); | | 629 | callout_destroy(&sc->sc_scan_to); |
630 | callout_destroy(&sc->sc_calib_to); | | 630 | callout_destroy(&sc->sc_calib_to); |
631 | | | 631 | |
632 | mutex_destroy(&sc->sc_write_mtx); | | 632 | mutex_destroy(&sc->sc_write_mtx); |
633 | mutex_destroy(&sc->sc_fwcmd_mtx); | | 633 | mutex_destroy(&sc->sc_fwcmd_mtx); |
634 | mutex_destroy(&sc->sc_tx_mtx); | | 634 | mutex_destroy(&sc->sc_tx_mtx); |
635 | mutex_destroy(&sc->sc_rx_mtx); | | 635 | mutex_destroy(&sc->sc_rx_mtx); |
636 | mutex_destroy(&sc->sc_task_mtx); | | 636 | mutex_destroy(&sc->sc_task_mtx); |
637 | | | 637 | |
638 | return 0; | | 638 | return 0; |
639 | } | | 639 | } |
640 | | | 640 | |
641 | static int | | 641 | static int |
642 | urtwn_activate(device_t self, enum devact act) | | 642 | urtwn_activate(device_t self, enum devact act) |
643 | { | | 643 | { |
644 | struct urtwn_softc *sc = device_private(self); | | 644 | struct urtwn_softc *sc = device_private(self); |
645 | | | 645 | |
646 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 646 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
647 | | | 647 | |
648 | switch (act) { | | 648 | switch (act) { |
649 | case DVACT_DEACTIVATE: | | 649 | case DVACT_DEACTIVATE: |
650 | if_deactivate(TAILQ_FIRST(&(sc->sc_ic.ic_vaps))->iv_ifp); | | 650 | if_deactivate(TAILQ_FIRST(&(sc->sc_ic.ic_vaps))->iv_ifp); |
651 | | | 651 | |
652 | return 0; | | 652 | return 0; |
653 | default: | | 653 | default: |
654 | return EOPNOTSUPP; | | 654 | return EOPNOTSUPP; |
655 | } | | 655 | } |
656 | } | | 656 | } |
657 | | | 657 | |
658 | static int | | 658 | static int |
659 | urtwn_open_pipes(struct urtwn_softc *sc) | | 659 | urtwn_open_pipes(struct urtwn_softc *sc) |
660 | { | | 660 | { |
661 | /* Bulk-out endpoints addresses (from highest to lowest prio). */ | | 661 | /* Bulk-out endpoints addresses (from highest to lowest prio). */ |
662 | static uint8_t epaddr[R92C_MAX_EPOUT]; | | 662 | static uint8_t epaddr[R92C_MAX_EPOUT]; |
663 | static uint8_t rxepaddr[R92C_MAX_EPIN]; | | 663 | static uint8_t rxepaddr[R92C_MAX_EPIN]; |
664 | usb_interface_descriptor_t *id; | | 664 | usb_interface_descriptor_t *id; |
665 | usb_endpoint_descriptor_t *ed; | | 665 | usb_endpoint_descriptor_t *ed; |
666 | size_t i, ntx = 0, nrx = 0; | | 666 | size_t i, ntx = 0, nrx = 0; |
667 | int error; | | 667 | int error; |
668 | | | 668 | |
669 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 669 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
670 | | | 670 | |
671 | /* Determine the number of bulk-out pipes. */ | | 671 | /* Determine the number of bulk-out pipes. */ |
672 | id = usbd_get_interface_descriptor(sc->sc_iface); | | 672 | id = usbd_get_interface_descriptor(sc->sc_iface); |
673 | for (i = 0; i < id->bNumEndpoints; i++) { | | 673 | for (i = 0; i < id->bNumEndpoints; i++) { |
674 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | | 674 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); |
675 | if (ed == NULL || UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK) { | | 675 | if (ed == NULL || UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK) { |
676 | continue; | | 676 | continue; |
677 | } | | 677 | } |
678 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) { | | 678 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) { |
679 | if (ntx < sizeof(epaddr)) | | 679 | if (ntx < sizeof(epaddr)) |
680 | epaddr[ntx] = ed->bEndpointAddress; | | 680 | epaddr[ntx] = ed->bEndpointAddress; |
681 | ntx++; | | 681 | ntx++; |
682 | } | | 682 | } |
683 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { | | 683 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { |
684 | if (nrx < sizeof(rxepaddr)) | | 684 | if (nrx < sizeof(rxepaddr)) |
685 | rxepaddr[nrx] = ed->bEndpointAddress; | | 685 | rxepaddr[nrx] = ed->bEndpointAddress; |
686 | nrx++; | | 686 | nrx++; |
687 | } | | 687 | } |
688 | } | | 688 | } |
689 | if (nrx == 0 || nrx > R92C_MAX_EPIN) { | | 689 | if (nrx == 0 || nrx > R92C_MAX_EPIN) { |
690 | aprint_error_dev(sc->sc_dev, | | 690 | aprint_error_dev(sc->sc_dev, |
691 | "%zd: invalid number of Rx bulk pipes\n", nrx); | | 691 | "%zd: invalid number of Rx bulk pipes\n", nrx); |
692 | return EIO; | | 692 | return EIO; |
693 | } | | 693 | } |
694 | if (ntx == 0 || ntx > R92C_MAX_EPOUT) { | | 694 | if (ntx == 0 || ntx > R92C_MAX_EPOUT) { |
695 | aprint_error_dev(sc->sc_dev, | | 695 | aprint_error_dev(sc->sc_dev, |
696 | "%zd: invalid number of Tx bulk pipes\n", ntx); | | 696 | "%zd: invalid number of Tx bulk pipes\n", ntx); |
697 | return EIO; | | 697 | return EIO; |
698 | } | | 698 | } |
699 | DPRINTFN(DBG_INIT, ("%s: %s: found %zd/%zd bulk-in/out pipes\n", | | 699 | DPRINTFN(DBG_INIT, ("%s: %s: found %zd/%zd bulk-in/out pipes\n", |
700 | device_xname(sc->sc_dev), __func__, nrx, ntx)); | | 700 | device_xname(sc->sc_dev), __func__, nrx, ntx)); |
701 | sc->rx_npipe = nrx; | | 701 | sc->rx_npipe = nrx; |
702 | sc->tx_npipe = ntx; | | 702 | sc->tx_npipe = ntx; |
703 | | | 703 | |
704 | /* Open bulk-in pipe at address 0x81. */ | | 704 | /* Open bulk-in pipe at address 0x81. */ |
705 | for (i = 0; i < nrx; i++) { | | 705 | for (i = 0; i < nrx; i++) { |
706 | error = usbd_open_pipe(sc->sc_iface, rxepaddr[i], | | 706 | error = usbd_open_pipe(sc->sc_iface, rxepaddr[i], |
707 | USBD_EXCLUSIVE_USE, &sc->rx_pipe[i]); | | 707 | USBD_EXCLUSIVE_USE, &sc->rx_pipe[i]); |
708 | if (error != 0) { | | 708 | if (error != 0) { |
709 | aprint_error_dev(sc->sc_dev, | | 709 | aprint_error_dev(sc->sc_dev, |
710 | "could not open Rx bulk pipe 0x%02x: %d\n", | | 710 | "could not open Rx bulk pipe 0x%02x: %d\n", |
711 | rxepaddr[i], error); | | 711 | rxepaddr[i], error); |
712 | goto fail; | | 712 | goto fail; |
713 | } | | 713 | } |
714 | } | | 714 | } |
715 | | | 715 | |
716 | /* Open bulk-out pipes (up to 3). */ | | 716 | /* Open bulk-out pipes (up to 3). */ |
717 | for (i = 0; i < ntx; i++) { | | 717 | for (i = 0; i < ntx; i++) { |
718 | error = usbd_open_pipe(sc->sc_iface, epaddr[i], | | 718 | error = usbd_open_pipe(sc->sc_iface, epaddr[i], |
719 | USBD_EXCLUSIVE_USE, &sc->tx_pipe[i]); | | 719 | USBD_EXCLUSIVE_USE, &sc->tx_pipe[i]); |
720 | if (error != 0) { | | 720 | if (error != 0) { |
721 | aprint_error_dev(sc->sc_dev, | | 721 | aprint_error_dev(sc->sc_dev, |
722 | "could not open Tx bulk pipe 0x%02x: %d\n", | | 722 | "could not open Tx bulk pipe 0x%02x: %d\n", |
723 | epaddr[i], error); | | 723 | epaddr[i], error); |
724 | goto fail; | | 724 | goto fail; |
725 | } | | 725 | } |
726 | } | | 726 | } |
727 | | | 727 | |
728 | /* Map 802.11 access categories to USB pipes. */ | | 728 | /* Map 802.11 access categories to USB pipes. */ |
729 | sc->ac2idx[WME_AC_BK] = | | 729 | sc->ac2idx[WME_AC_BK] = |
730 | sc->ac2idx[WME_AC_BE] = (ntx == 3) ? 2 : ((ntx == 2) ? 1 : 0); | | 730 | sc->ac2idx[WME_AC_BE] = (ntx == 3) ? 2 : ((ntx == 2) ? 1 : 0); |
731 | sc->ac2idx[WME_AC_VI] = (ntx == 3) ? 1 : 0; | | 731 | sc->ac2idx[WME_AC_VI] = (ntx == 3) ? 1 : 0; |
732 | sc->ac2idx[WME_AC_VO] = 0; /* Always use highest prio. */ | | 732 | sc->ac2idx[WME_AC_VO] = 0; /* Always use highest prio. */ |
733 | | | 733 | |
734 | fail: | | 734 | fail: |
735 | if (error != 0) | | 735 | if (error != 0) |
736 | urtwn_close_pipes(sc); | | 736 | urtwn_close_pipes(sc); |
737 | return error; | | 737 | return error; |
738 | } | | 738 | } |
739 | | | 739 | |
740 | static void | | 740 | static void |
741 | urtwn_close_pipes(struct urtwn_softc *sc) | | 741 | urtwn_close_pipes(struct urtwn_softc *sc) |
742 | { | | 742 | { |
743 | struct usbd_pipe *pipe; | | 743 | struct usbd_pipe *pipe; |
744 | size_t i; | | 744 | size_t i; |
745 | | | 745 | |
746 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 746 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
747 | | | 747 | |
748 | /* Close Rx pipes. */ | | 748 | /* Close Rx pipes. */ |
749 | CTASSERT(sizeof(pipe) == sizeof(void *)); | | 749 | CTASSERT(sizeof(pipe) == sizeof(void *)); |
750 | for (i = 0; i < sc->rx_npipe; i++) { | | 750 | for (i = 0; i < sc->rx_npipe; i++) { |
751 | pipe = atomic_swap_ptr(&sc->rx_pipe[i], NULL); | | 751 | pipe = atomic_swap_ptr(&sc->rx_pipe[i], NULL); |
752 | if (pipe != NULL) { | | 752 | if (pipe != NULL) { |
753 | usbd_close_pipe(pipe); | | 753 | usbd_close_pipe(pipe); |
754 | } | | 754 | } |
755 | } | | 755 | } |
756 | | | 756 | |
757 | /* Close Tx pipes. */ | | 757 | /* Close Tx pipes. */ |
758 | for (i = 0; i < sc->tx_npipe; i++) { | | 758 | for (i = 0; i < sc->tx_npipe; i++) { |
759 | pipe = atomic_swap_ptr(&sc->tx_pipe[i], NULL); | | 759 | pipe = atomic_swap_ptr(&sc->tx_pipe[i], NULL); |
760 | if (pipe != NULL) { | | 760 | if (pipe != NULL) { |
761 | usbd_close_pipe(pipe); | | 761 | usbd_close_pipe(pipe); |
762 | } | | 762 | } |
763 | } | | 763 | } |
764 | } | | 764 | } |
765 | | | 765 | |
766 | static int | | 766 | static int |
767 | urtwn_alloc_rx_list(struct urtwn_softc *sc) | | 767 | urtwn_alloc_rx_list(struct urtwn_softc *sc) |
768 | { | | 768 | { |
769 | struct urtwn_rx_data *data; | | 769 | struct urtwn_rx_data *data; |
770 | size_t i; | | 770 | size_t i; |
771 | int error = 0; | | 771 | int error = 0; |
772 | | | 772 | |
773 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 773 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
774 | | | 774 | |
775 | for (size_t j = 0; j < sc->rx_npipe; j++) { | | 775 | for (size_t j = 0; j < sc->rx_npipe; j++) { |
776 | TAILQ_INIT(&sc->rx_free_list[j]); | | 776 | TAILQ_INIT(&sc->rx_free_list[j]); |
777 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { | | 777 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { |
778 | data = &sc->rx_data[j][i]; | | 778 | data = &sc->rx_data[j][i]; |
779 | | | 779 | |
780 | data->sc = sc; /* Backpointer for callbacks. */ | | 780 | data->sc = sc; /* Backpointer for callbacks. */ |
781 | | | 781 | |
782 | error = usbd_create_xfer(sc->rx_pipe[j], URTWN_RXBUFSZ, | | 782 | error = usbd_create_xfer(sc->rx_pipe[j], URTWN_RXBUFSZ, |
783 | 0, 0, &data->xfer); | | 783 | 0, 0, &data->xfer); |
784 | if (error) { | | 784 | if (error) { |
785 | aprint_error_dev(sc->sc_dev, | | 785 | aprint_error_dev(sc->sc_dev, |
786 | "could not allocate xfer\n"); | | 786 | "could not allocate xfer\n"); |
787 | break; | | 787 | break; |
788 | } | | 788 | } |
789 | | | 789 | |
790 | data->buf = usbd_get_buffer(data->xfer); | | 790 | data->buf = usbd_get_buffer(data->xfer); |
791 | TAILQ_INSERT_TAIL(&sc->rx_free_list[j], data, next); | | 791 | TAILQ_INSERT_TAIL(&sc->rx_free_list[j], data, next); |
792 | } | | 792 | } |
793 | } | | 793 | } |
794 | if (error != 0) | | 794 | if (error != 0) |
795 | urtwn_free_rx_list(sc); | | 795 | urtwn_free_rx_list(sc); |
796 | return error; | | 796 | return error; |
797 | } | | 797 | } |
798 | | | 798 | |
799 | static void | | 799 | static void |
800 | urtwn_free_rx_list(struct urtwn_softc *sc) | | 800 | urtwn_free_rx_list(struct urtwn_softc *sc) |
801 | { | | 801 | { |
802 | struct usbd_xfer *xfer; | | 802 | struct usbd_xfer *xfer; |
803 | size_t i; | | 803 | size_t i; |
804 | | | 804 | |
805 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 805 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
806 | | | 806 | |
807 | /* NB: Caller must abort pipe first. */ | | 807 | /* NB: Caller must abort pipe first. */ |
808 | for (size_t j = 0; j < sc->rx_npipe; j++) { | | 808 | for (size_t j = 0; j < sc->rx_npipe; j++) { |
809 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { | | 809 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { |
810 | CTASSERT(sizeof(xfer) == sizeof(void *)); | | 810 | CTASSERT(sizeof(xfer) == sizeof(void *)); |
811 | xfer = atomic_swap_ptr(&sc->rx_data[j][i].xfer, NULL); | | 811 | xfer = atomic_swap_ptr(&sc->rx_data[j][i].xfer, NULL); |
812 | if (xfer != NULL) | | 812 | if (xfer != NULL) |
813 | usbd_destroy_xfer(xfer); | | 813 | usbd_destroy_xfer(xfer); |
814 | } | | 814 | } |
815 | } | | 815 | } |
816 | } | | 816 | } |
817 | | | 817 | |
818 | static int | | 818 | static int |
819 | urtwn_alloc_tx_list(struct urtwn_softc *sc) | | 819 | urtwn_alloc_tx_list(struct urtwn_softc *sc) |
820 | { | | 820 | { |
821 | struct urtwn_tx_data *data; | | 821 | struct urtwn_tx_data *data; |
822 | size_t i; | | 822 | size_t i; |
823 | int error = 0; | | 823 | int error = 0; |
824 | | | 824 | |
825 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 825 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
826 | | | 826 | |
827 | mutex_enter(&sc->sc_tx_mtx); | | 827 | mutex_enter(&sc->sc_tx_mtx); |
828 | for (size_t j = 0; j < sc->tx_npipe; j++) { | | 828 | for (size_t j = 0; j < sc->tx_npipe; j++) { |
829 | TAILQ_INIT(&sc->tx_free_list[j]); | | 829 | TAILQ_INIT(&sc->tx_free_list[j]); |
830 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { | | 830 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { |
831 | data = &sc->tx_data[j][i]; | | 831 | data = &sc->tx_data[j][i]; |
832 | | | 832 | |
833 | data->sc = sc; /* Backpointer for callbacks. */ | | 833 | data->sc = sc; /* Backpointer for callbacks. */ |
834 | data->pidx = j; | | 834 | data->pidx = j; |
835 | | | 835 | |
836 | error = usbd_create_xfer(sc->tx_pipe[j], | | 836 | error = usbd_create_xfer(sc->tx_pipe[j], |
837 | URTWN_TXBUFSZ, USBD_FORCE_SHORT_XFER, 0, | | 837 | URTWN_TXBUFSZ, USBD_FORCE_SHORT_XFER, 0, |
838 | &data->xfer); | | 838 | &data->xfer); |
839 | if (error) { | | 839 | if (error) { |
840 | aprint_error_dev(sc->sc_dev, | | 840 | aprint_error_dev(sc->sc_dev, |
841 | "could not allocate xfer\n"); | | 841 | "could not allocate xfer\n"); |
842 | goto fail; | | 842 | goto fail; |
843 | } | | 843 | } |
844 | | | 844 | |
845 | data->buf = usbd_get_buffer(data->xfer); | | 845 | data->buf = usbd_get_buffer(data->xfer); |
846 | | | 846 | |
847 | /* Append this Tx buffer to our free list. */ | | 847 | /* Append this Tx buffer to our free list. */ |
848 | TAILQ_INSERT_TAIL(&sc->tx_free_list[j], data, next); | | 848 | TAILQ_INSERT_TAIL(&sc->tx_free_list[j], data, next); |
849 | } | | 849 | } |
850 | } | | 850 | } |
851 | mutex_exit(&sc->sc_tx_mtx); | | 851 | mutex_exit(&sc->sc_tx_mtx); |
852 | return 0; | | 852 | return 0; |
853 | | | 853 | |
854 | fail: | | 854 | fail: |
855 | urtwn_free_tx_list(sc); | | 855 | urtwn_free_tx_list(sc); |
856 | mutex_exit(&sc->sc_tx_mtx); | | 856 | mutex_exit(&sc->sc_tx_mtx); |
857 | return error; | | 857 | return error; |
858 | } | | 858 | } |
859 | | | 859 | |
860 | static void | | 860 | static void |
861 | urtwn_free_tx_list(struct urtwn_softc *sc) | | 861 | urtwn_free_tx_list(struct urtwn_softc *sc) |
862 | { | | 862 | { |
863 | struct usbd_xfer *xfer; | | 863 | struct usbd_xfer *xfer; |
864 | size_t i; | | 864 | size_t i; |
865 | | | 865 | |
866 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 866 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
867 | | | 867 | |
868 | /* NB: Caller must abort pipe first. */ | | 868 | /* NB: Caller must abort pipe first. */ |
869 | for (size_t j = 0; j < sc->tx_npipe; j++) { | | 869 | for (size_t j = 0; j < sc->tx_npipe; j++) { |
870 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { | | 870 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { |
871 | CTASSERT(sizeof(xfer) == sizeof(void *)); | | 871 | CTASSERT(sizeof(xfer) == sizeof(void *)); |
872 | xfer = atomic_swap_ptr(&sc->tx_data[j][i].xfer, NULL); | | 872 | xfer = atomic_swap_ptr(&sc->tx_data[j][i].xfer, NULL); |
873 | if (xfer != NULL) | | 873 | if (xfer != NULL) |
874 | usbd_destroy_xfer(xfer); | | 874 | usbd_destroy_xfer(xfer); |
875 | } | | 875 | } |
876 | } | | 876 | } |
877 | } | | 877 | } |
878 | | | 878 | |
879 | static int | | 879 | static int |
880 | urtwn_tx_beacon(struct urtwn_softc *sc, struct mbuf *m, | | 880 | urtwn_tx_beacon(struct urtwn_softc *sc, struct mbuf *m, |
881 | struct ieee80211_node *ni) | | 881 | struct ieee80211_node *ni) |
882 | { | | 882 | { |
883 | struct urtwn_tx_data *data = | | 883 | struct urtwn_tx_data *data = |
884 | urtwn_get_tx_data(sc, sc->ac2idx[WME_AC_VO]); | | 884 | urtwn_get_tx_data(sc, sc->ac2idx[WME_AC_VO]); |
885 | return urtwn_tx(sc, m, ni, data); | | 885 | return urtwn_tx(sc, m, ni, data); |
886 | } | | 886 | } |
887 | | | 887 | |
888 | static void | | 888 | static void |
889 | urtwn_task(void *arg) | | 889 | urtwn_task(void *arg) |
890 | { | | 890 | { |
891 | struct urtwn_softc *sc = arg; | | 891 | struct urtwn_softc *sc = arg; |
892 | struct ieee80211com *ic = &sc->sc_ic; | | 892 | struct ieee80211com *ic = &sc->sc_ic; |
893 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | | 893 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); |
894 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; | | 894 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; |
895 | struct urtwn_host_cmd *cmd; | | 895 | struct urtwn_host_cmd *cmd; |
896 | int s; | | 896 | int s; |
897 | | | 897 | |
898 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 898 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
899 | if (vap->iv_state == IEEE80211_S_RUN && | | 899 | if (vap->iv_state == IEEE80211_S_RUN && |
900 | (ic->ic_opmode == IEEE80211_M_HOSTAP || | | 900 | (ic->ic_opmode == IEEE80211_M_HOSTAP || |
901 | ic->ic_opmode == IEEE80211_M_IBSS)) { | | 901 | ic->ic_opmode == IEEE80211_M_IBSS)) { |
902 | struct mbuf *m = ieee80211_beacon_alloc(vap->iv_bss); | | 902 | struct mbuf *m = ieee80211_beacon_alloc(vap->iv_bss); |
903 | if (m == NULL) { | | 903 | if (m == NULL) { |
904 | aprint_error_dev(sc->sc_dev, | | 904 | aprint_error_dev(sc->sc_dev, |
905 | "could not allocate beacon"); | | 905 | "could not allocate beacon"); |
906 | } | | 906 | } |
907 | | | 907 | |
908 | if (urtwn_tx_beacon(sc, m, vap->iv_bss) != 0) { | | 908 | if (urtwn_tx_beacon(sc, m, vap->iv_bss) != 0) { |
909 | m_freem(m); | | 909 | m_freem(m); |
910 | aprint_error_dev(sc->sc_dev, "could not send beacon"); | | 910 | aprint_error_dev(sc->sc_dev, "could not send beacon"); |
911 | } | | 911 | } |
912 | | | 912 | |
913 | /* beacon is no longer needed */ | | 913 | /* beacon is no longer needed */ |
914 | m_freem(m); | | 914 | m_freem(m); |
915 | } | | 915 | } |
916 | | | 916 | |
917 | /* Process host commands. */ | | 917 | /* Process host commands. */ |
918 | s = splusb(); | | 918 | s = splusb(); |
919 | mutex_spin_enter(&sc->sc_task_mtx); | | 919 | mutex_spin_enter(&sc->sc_task_mtx); |
920 | while (ring->next != ring->cur) { | | 920 | while (ring->next != ring->cur) { |
921 | cmd = &ring->cmd[ring->next]; | | 921 | cmd = &ring->cmd[ring->next]; |
922 | mutex_spin_exit(&sc->sc_task_mtx); | | 922 | mutex_spin_exit(&sc->sc_task_mtx); |
923 | splx(s); | | 923 | splx(s); |
924 | /* Invoke callback with kernel lock held. */ | | 924 | /* Invoke callback with kernel lock held. */ |
925 | cmd->cb(sc, cmd->data); | | 925 | cmd->cb(sc, cmd->data); |
926 | s = splusb(); | | 926 | s = splusb(); |
927 | mutex_spin_enter(&sc->sc_task_mtx); | | 927 | mutex_spin_enter(&sc->sc_task_mtx); |
928 | ring->queued--; | | 928 | ring->queued--; |
929 | ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT; | | 929 | ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT; |
930 | } | | 930 | } |
931 | mutex_spin_exit(&sc->sc_task_mtx); | | 931 | mutex_spin_exit(&sc->sc_task_mtx); |
932 | wakeup(&sc->cmdq); | | 932 | wakeup(&sc->cmdq); |
933 | splx(s); | | 933 | splx(s); |
934 | } | | 934 | } |
935 | | | 935 | |
936 | static void | | 936 | static void |
937 | urtwn_do_async(struct urtwn_softc *sc, void (*cb)(struct urtwn_softc*, void *), | | 937 | urtwn_do_async(struct urtwn_softc *sc, void (*cb)(struct urtwn_softc*, void *), |
938 | void *arg, int len) | | 938 | void *arg, int len) |
939 | { | | 939 | { |
940 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; | | 940 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; |
941 | struct urtwn_host_cmd *cmd; | | 941 | struct urtwn_host_cmd *cmd; |
942 | int s; | | 942 | int s; |
943 | | | 943 | |
944 | DPRINTFN(DBG_FN, ("%s: %s: cb=%p, arg=%p, len=%d\n", | | 944 | DPRINTFN(DBG_FN, ("%s: %s: cb=%p, arg=%p, len=%d\n", |
945 | device_xname(sc->sc_dev), __func__, cb, arg, len)); | | 945 | device_xname(sc->sc_dev), __func__, cb, arg, len)); |
946 | | | 946 | |
947 | s = splusb(); | | 947 | s = splusb(); |
948 | mutex_spin_enter(&sc->sc_task_mtx); | | 948 | mutex_spin_enter(&sc->sc_task_mtx); |
949 | cmd = &ring->cmd[ring->cur]; | | 949 | cmd = &ring->cmd[ring->cur]; |
950 | cmd->cb = cb; | | 950 | cmd->cb = cb; |
951 | KASSERT(len <= sizeof(cmd->data)); | | 951 | KASSERT(len <= sizeof(cmd->data)); |
952 | memcpy(cmd->data, arg, len); | | 952 | memcpy(cmd->data, arg, len); |
953 | ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT; | | 953 | ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT; |
954 | | | 954 | |
955 | /* If there is no pending command already, schedule a task. */ | | 955 | /* If there is no pending command already, schedule a task. */ |
956 | if (!sc->sc_dying && ++ring->queued == 1) { | | 956 | if (!sc->sc_dying && ++ring->queued == 1) { |
957 | mutex_spin_exit(&sc->sc_task_mtx); | | 957 | mutex_spin_exit(&sc->sc_task_mtx); |
958 | usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER); | | 958 | usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER); |
959 | } else | | 959 | } else |
960 | mutex_spin_exit(&sc->sc_task_mtx); | | 960 | mutex_spin_exit(&sc->sc_task_mtx); |
961 | splx(s); | | 961 | splx(s); |
962 | } | | 962 | } |
963 | | | 963 | |
964 | static void | | 964 | static void |
965 | urtwn_wait_async(struct urtwn_softc *sc) | | 965 | urtwn_wait_async(struct urtwn_softc *sc) |
966 | { | | 966 | { |
967 | | | 967 | |
968 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 968 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
969 | | | 969 | |
970 | /* Wait for all queued asynchronous commands to complete. */ | | 970 | /* Wait for all queued asynchronous commands to complete. */ |
971 | while (sc->cmdq.queued > 0) | | 971 | while (sc->cmdq.queued > 0) |
972 | tsleep(&sc->cmdq, 0, "endtask", 0); | | 972 | tsleep(&sc->cmdq, 0, "endtask", 0); |
973 | } | | 973 | } |
974 | | | 974 | |
975 | static int | | 975 | static int |
976 | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | | 976 | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, |
977 | int len) | | 977 | int len) |
978 | { | | 978 | { |
979 | usb_device_request_t req; | | 979 | usb_device_request_t req; |
980 | usbd_status error; | | 980 | usbd_status error; |
981 | | | 981 | |
982 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 982 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
983 | | | 983 | |
984 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | | 984 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
985 | req.bRequest = R92C_REQ_REGS; | | 985 | req.bRequest = R92C_REQ_REGS; |
986 | USETW(req.wValue, addr); | | 986 | USETW(req.wValue, addr); |
987 | USETW(req.wIndex, 0); | | 987 | USETW(req.wIndex, 0); |
988 | USETW(req.wLength, len); | | 988 | USETW(req.wLength, len); |
989 | error = usbd_do_request(sc->sc_udev, &req, buf); | | 989 | error = usbd_do_request(sc->sc_udev, &req, buf); |
990 | if (error != USBD_NORMAL_COMPLETION) { | | 990 | if (error != USBD_NORMAL_COMPLETION) { |
991 | DPRINTFN(DBG_REG, ("%s: %s: error=%d: addr=%#x, len=%d\n", | | 991 | DPRINTFN(DBG_REG, ("%s: %s: error=%d: addr=%#x, len=%d\n", |
992 | device_xname(sc->sc_dev), __func__, error, addr, len)); | | 992 | device_xname(sc->sc_dev), __func__, error, addr, len)); |
993 | } | | 993 | } |
994 | return error; | | 994 | return error; |
995 | } | | 995 | } |
996 | | | 996 | |
997 | static void | | 997 | static void |
998 | urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) | | 998 | urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) |
999 | { | | 999 | { |
1000 | | | 1000 | |
1001 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, val=%#x\n", | | 1001 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, val=%#x\n", |
1002 | device_xname(sc->sc_dev), __func__, addr, val)); | | 1002 | device_xname(sc->sc_dev), __func__, addr, val)); |
1003 | | | 1003 | |
1004 | urtwn_write_region_1(sc, addr, &val, 1); | | 1004 | urtwn_write_region_1(sc, addr, &val, 1); |
1005 | } | | 1005 | } |
1006 | | | 1006 | |
1007 | static void | | 1007 | static void |
1008 | urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) | | 1008 | urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) |
1009 | { | | 1009 | { |
1010 | uint8_t buf[2]; | | 1010 | uint8_t buf[2]; |
1011 | | | 1011 | |
1012 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, val=%#x\n", | | 1012 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, val=%#x\n", |
1013 | device_xname(sc->sc_dev), __func__, addr, val)); | | 1013 | device_xname(sc->sc_dev), __func__, addr, val)); |
1014 | | | 1014 | |
1015 | buf[0] = (uint8_t)val; | | 1015 | buf[0] = (uint8_t)val; |
1016 | buf[1] = (uint8_t)(val >> 8); | | 1016 | buf[1] = (uint8_t)(val >> 8); |
1017 | urtwn_write_region_1(sc, addr, buf, 2); | | 1017 | urtwn_write_region_1(sc, addr, buf, 2); |
1018 | } | | 1018 | } |
1019 | | | 1019 | |
1020 | static void | | 1020 | static void |
1021 | urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) | | 1021 | urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) |
1022 | { | | 1022 | { |
1023 | uint8_t buf[4]; | | 1023 | uint8_t buf[4]; |
1024 | | | 1024 | |
1025 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, val=%#x\n", | | 1025 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, val=%#x\n", |
1026 | device_xname(sc->sc_dev), __func__, addr, val)); | | 1026 | device_xname(sc->sc_dev), __func__, addr, val)); |
1027 | | | 1027 | |
1028 | buf[0] = (uint8_t)val; | | 1028 | buf[0] = (uint8_t)val; |
1029 | buf[1] = (uint8_t)(val >> 8); | | 1029 | buf[1] = (uint8_t)(val >> 8); |
1030 | buf[2] = (uint8_t)(val >> 16); | | 1030 | buf[2] = (uint8_t)(val >> 16); |
1031 | buf[3] = (uint8_t)(val >> 24); | | 1031 | buf[3] = (uint8_t)(val >> 24); |
1032 | urtwn_write_region_1(sc, addr, buf, 4); | | 1032 | urtwn_write_region_1(sc, addr, buf, 4); |
1033 | } | | 1033 | } |
1034 | | | 1034 | |
1035 | static int | | 1035 | static int |
1036 | urtwn_write_region(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, int len) | | 1036 | urtwn_write_region(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, int len) |
1037 | { | | 1037 | { |
1038 | | | 1038 | |
1039 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, len=%#x\n", | | 1039 | DPRINTFN(DBG_REG, ("%s: %s: addr=%#x, len=%#x\n", |
1040 | device_xname(sc->sc_dev), __func__, addr, len)); | | 1040 | device_xname(sc->sc_dev), __func__, addr, len)); |
1041 | | | 1041 | |
1042 | return urtwn_write_region_1(sc, addr, buf, len); | | 1042 | return urtwn_write_region_1(sc, addr, buf, len); |
1043 | } | | 1043 | } |
1044 | | | 1044 | |
| @@ -2456,2062 +2456,2066 @@ urtwn_newstate(struct ieee80211vap *vap, | | | @@ -2456,2062 +2456,2066 @@ urtwn_newstate(struct ieee80211vap *vap, |
2456 | } | | 2456 | } |
2457 | | | 2457 | |
2458 | /* Set media status to 'Associated'. */ | | 2458 | /* Set media status to 'Associated'. */ |
2459 | urtwn_set_nettype0_msr(sc, urtwn_get_nettype(sc)); | | 2459 | urtwn_set_nettype0_msr(sc, urtwn_get_nettype(sc)); |
2460 | | | 2460 | |
2461 | /* Set BSSID. */ | | 2461 | /* Set BSSID. */ |
2462 | urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0])); | | 2462 | urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0])); |
2463 | urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4])); | | 2463 | urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4])); |
2464 | | | 2464 | |
2465 | if (ic->ic_curmode == IEEE80211_MODE_11B) { | | 2465 | if (ic->ic_curmode == IEEE80211_MODE_11B) { |
2466 | urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); | | 2466 | urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); |
2467 | } else { | | 2467 | } else { |
2468 | /* 802.11b/g */ | | 2468 | /* 802.11b/g */ |
2469 | urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); | | 2469 | urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); |
2470 | } | | 2470 | } |
2471 | | | 2471 | |
2472 | /* Enable Rx of data frames. */ | | 2472 | /* Enable Rx of data frames. */ |
2473 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); | | 2473 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); |
2474 | | | 2474 | |
2475 | /* Set beacon interval. */ | | 2475 | /* Set beacon interval. */ |
2476 | urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); | | 2476 | urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); |
2477 | | | 2477 | |
2478 | msr = urtwn_read_1(sc, R92C_MSR); | | 2478 | msr = urtwn_read_1(sc, R92C_MSR); |
2479 | msr &= R92C_MSR_MASK; | | 2479 | msr &= R92C_MSR_MASK; |
2480 | switch (ic->ic_opmode) { | | 2480 | switch (ic->ic_opmode) { |
2481 | case IEEE80211_M_STA: | | 2481 | case IEEE80211_M_STA: |
2482 | /* Allow Rx from our BSSID only. */ | | 2482 | /* Allow Rx from our BSSID only. */ |
2483 | urtwn_write_4(sc, R92C_RCR, | | 2483 | urtwn_write_4(sc, R92C_RCR, |
2484 | urtwn_read_4(sc, R92C_RCR) | | | 2484 | urtwn_read_4(sc, R92C_RCR) | |
2485 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); | | 2485 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); |
2486 | | | 2486 | |
2487 | /* Enable TSF synchronization. */ | | 2487 | /* Enable TSF synchronization. */ |
2488 | urtwn_tsf_sync_enable(sc); | | 2488 | urtwn_tsf_sync_enable(sc); |
2489 | | | 2489 | |
2490 | msr |= R92C_MSR_INFRA; | | 2490 | msr |= R92C_MSR_INFRA; |
2491 | break; | | 2491 | break; |
2492 | case IEEE80211_M_HOSTAP: | | 2492 | case IEEE80211_M_HOSTAP: |
2493 | urtwn_write_2(sc, R92C_BCNTCFG, 0x000f); | | 2493 | urtwn_write_2(sc, R92C_BCNTCFG, 0x000f); |
2494 | | | 2494 | |
2495 | /* Allow Rx from any BSSID. */ | | 2495 | /* Allow Rx from any BSSID. */ |
2496 | urtwn_write_4(sc, R92C_RCR, | | 2496 | urtwn_write_4(sc, R92C_RCR, |
2497 | urtwn_read_4(sc, R92C_RCR) & | | 2497 | urtwn_read_4(sc, R92C_RCR) & |
2498 | ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN)); | | 2498 | ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN)); |
2499 | | | 2499 | |
2500 | /* Reset TSF timer to zero. */ | | 2500 | /* Reset TSF timer to zero. */ |
2501 | reg = urtwn_read_4(sc, R92C_TCR); | | 2501 | reg = urtwn_read_4(sc, R92C_TCR); |
2502 | reg &= ~0x01; | | 2502 | reg &= ~0x01; |
2503 | urtwn_write_4(sc, R92C_TCR, reg); | | 2503 | urtwn_write_4(sc, R92C_TCR, reg); |
2504 | reg |= 0x01; | | 2504 | reg |= 0x01; |
2505 | urtwn_write_4(sc, R92C_TCR, reg); | | 2505 | urtwn_write_4(sc, R92C_TCR, reg); |
2506 | | | 2506 | |
2507 | msr |= R92C_MSR_AP; | | 2507 | msr |= R92C_MSR_AP; |
2508 | break; | | 2508 | break; |
2509 | default: | | 2509 | default: |
2510 | msr |= R92C_MSR_ADHOC; | | 2510 | msr |= R92C_MSR_ADHOC; |
2511 | break; | | 2511 | break; |
2512 | } | | 2512 | } |
2513 | urtwn_write_1(sc, R92C_MSR, msr); | | 2513 | urtwn_write_1(sc, R92C_MSR, msr); |
2514 | | | 2514 | |
2515 | sifs_time = 10; | | 2515 | sifs_time = 10; |
2516 | urtwn_write_1(sc, R92C_SIFS_CCK + 1, sifs_time); | | 2516 | urtwn_write_1(sc, R92C_SIFS_CCK + 1, sifs_time); |
2517 | urtwn_write_1(sc, R92C_SIFS_OFDM + 1, sifs_time); | | 2517 | urtwn_write_1(sc, R92C_SIFS_OFDM + 1, sifs_time); |
2518 | urtwn_write_1(sc, R92C_SPEC_SIFS + 1, sifs_time); | | 2518 | urtwn_write_1(sc, R92C_SPEC_SIFS + 1, sifs_time); |
2519 | urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, sifs_time); | | 2519 | urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, sifs_time); |
2520 | urtwn_write_1(sc, R92C_R2T_SIFS + 1, sifs_time); | | 2520 | urtwn_write_1(sc, R92C_R2T_SIFS + 1, sifs_time); |
2521 | urtwn_write_1(sc, R92C_T2T_SIFS + 1, sifs_time); | | 2521 | urtwn_write_1(sc, R92C_T2T_SIFS + 1, sifs_time); |
2522 | | | 2522 | |
2523 | /* Initialize rate adaptation. */ | | 2523 | /* Initialize rate adaptation. */ |
2524 | if (ISSET(sc->chip, URTWN_CHIP_88E) || | | 2524 | if (ISSET(sc->chip, URTWN_CHIP_88E) || |
2525 | ISSET(sc->chip, URTWN_CHIP_92EU)) | | 2525 | ISSET(sc->chip, URTWN_CHIP_92EU)) |
2526 | ni->ni_txrate = ni->ni_rates.rs_nrates - 1; | | 2526 | ni->ni_txrate = ni->ni_rates.rs_nrates - 1; |
2527 | else | | 2527 | else |
2528 | urtwn_ra_init(vap); | | 2528 | urtwn_ra_init(vap); |
2529 | | | 2529 | |
2530 | /* Turn link LED on. */ | | 2530 | /* Turn link LED on. */ |
2531 | urtwn_set_led(sc, URTWN_LED_LINK, 1); | | 2531 | urtwn_set_led(sc, URTWN_LED_LINK, 1); |
2532 | | | 2532 | |
2533 | /* Reset average RSSI. */ | | 2533 | /* Reset average RSSI. */ |
2534 | sc->avg_pwdb = -1; | | 2534 | sc->avg_pwdb = -1; |
2535 | | | 2535 | |
2536 | /* Reset temperature calibration state machine. */ | | 2536 | /* Reset temperature calibration state machine. */ |
2537 | sc->thcal_state = 0; | | 2537 | sc->thcal_state = 0; |
2538 | sc->thcal_lctemp = 0; | | 2538 | sc->thcal_lctemp = 0; |
2539 | | | 2539 | |
2540 | /* Start periodic calibration. */ | | 2540 | /* Start periodic calibration. */ |
2541 | if (!sc->sc_dying) | | 2541 | if (!sc->sc_dying) |
2542 | callout_schedule(&sc->sc_calib_to, hz); | | 2542 | callout_schedule(&sc->sc_calib_to, hz); |
2543 | break; | | 2543 | break; |
2544 | case IEEE80211_S_CAC: | | 2544 | case IEEE80211_S_CAC: |
2545 | case IEEE80211_S_CSA: | | 2545 | case IEEE80211_S_CSA: |
2546 | case IEEE80211_S_SLEEP: | | 2546 | case IEEE80211_S_SLEEP: |
2547 | /* NNN what do we do in these states? XXX */ | | 2547 | /* NNN what do we do in these states? XXX */ |
2548 | printf ("URTWN UNKNOWN nSTATE: %d\n", nstate); | | 2548 | printf ("URTWN UNKNOWN nSTATE: %d\n", nstate); |
2549 | break; | | 2549 | break; |
2550 | } | | 2550 | } |
2551 | mutex_exit(&sc->sc_write_mtx); | | 2551 | mutex_exit(&sc->sc_write_mtx); |
2552 | | | 2552 | |
2553 | /* newstate functions expect the ic to be locked. */ | | 2553 | /* newstate functions expect the ic to be locked. */ |
2554 | error = (*sc->sc_newstate)(vap, nstate, arg); | | 2554 | error = (*sc->sc_newstate)(vap, nstate, arg); |
2555 | | | 2555 | |
2556 | splx(s); | | 2556 | splx(s); |
2557 | return error; | | 2557 | return error; |
2558 | } | | 2558 | } |
2559 | | | 2559 | |
2560 | static int | | 2560 | static int |
2561 | urtwn_wme_update(struct ieee80211com *ic) | | 2561 | urtwn_wme_update(struct ieee80211com *ic) |
2562 | { | | 2562 | { |
2563 | struct urtwn_softc *sc = ic->ic_softc; | | 2563 | struct urtwn_softc *sc = ic->ic_softc; |
2564 | | | 2564 | |
2565 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 2565 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
2566 | | | 2566 | |
2567 | /* don't override default WME values if WME is not actually enabled */ | | 2567 | /* don't override default WME values if WME is not actually enabled */ |
2568 | if (!(ic->ic_flags & IEEE80211_F_WME)) | | 2568 | if (!(ic->ic_flags & IEEE80211_F_WME)) |
2569 | return 0; | | 2569 | return 0; |
2570 | | | 2570 | |
2571 | /* Do it in a process context. */ | | 2571 | /* Do it in a process context. */ |
2572 | urtwn_do_async(sc, urtwn_wme_update_cb, NULL, 0); | | 2572 | urtwn_do_async(sc, urtwn_wme_update_cb, NULL, 0); |
2573 | return 0; | | 2573 | return 0; |
2574 | } | | 2574 | } |
2575 | | | 2575 | |
2576 | static void | | 2576 | static void |
2577 | urtwn_wme_update_cb(struct urtwn_softc *sc, void *arg) | | 2577 | urtwn_wme_update_cb(struct urtwn_softc *sc, void *arg) |
2578 | { | | 2578 | { |
2579 | static const uint16_t ac2reg[WME_NUM_AC] = { | | 2579 | static const uint16_t ac2reg[WME_NUM_AC] = { |
2580 | R92C_EDCA_BE_PARAM, | | 2580 | R92C_EDCA_BE_PARAM, |
2581 | R92C_EDCA_BK_PARAM, | | 2581 | R92C_EDCA_BK_PARAM, |
2582 | R92C_EDCA_VI_PARAM, | | 2582 | R92C_EDCA_VI_PARAM, |
2583 | R92C_EDCA_VO_PARAM | | 2583 | R92C_EDCA_VO_PARAM |
2584 | }; | | 2584 | }; |
2585 | struct ieee80211com *ic = &sc->sc_ic; | | 2585 | struct ieee80211com *ic = &sc->sc_ic; |
2586 | const struct wmeParams *wmep; | | 2586 | const struct wmeParams *wmep; |
2587 | int ac, aifs, slottime; | | 2587 | int ac, aifs, slottime; |
2588 | int s; | | 2588 | int s; |
2589 | | | 2589 | |
2590 | DPRINTFN(DBG_FN|DBG_STM, ("%s: %s\n", device_xname(sc->sc_dev), | | 2590 | DPRINTFN(DBG_FN|DBG_STM, ("%s: %s\n", device_xname(sc->sc_dev), |
2591 | __func__)); | | 2591 | __func__)); |
2592 | | | 2592 | |
2593 | s = splnet(); | | 2593 | s = splnet(); |
2594 | mutex_enter(&sc->sc_write_mtx); | | 2594 | mutex_enter(&sc->sc_write_mtx); |
2595 | slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; | | 2595 | slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; |
2596 | for (ac = 0; ac < WME_NUM_AC; ac++) { | | 2596 | for (ac = 0; ac < WME_NUM_AC; ac++) { |
2597 | wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; | | 2597 | wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; |
2598 | /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ | | 2598 | /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ |
2599 | aifs = wmep->wmep_aifsn * slottime + 10; | | 2599 | aifs = wmep->wmep_aifsn * slottime + 10; |
2600 | urtwn_write_4(sc, ac2reg[ac], | | 2600 | urtwn_write_4(sc, ac2reg[ac], |
2601 | SM(R92C_EDCA_PARAM_TXOP, wmep->wmep_txopLimit) | | | 2601 | SM(R92C_EDCA_PARAM_TXOP, wmep->wmep_txopLimit) | |
2602 | SM(R92C_EDCA_PARAM_ECWMIN, wmep->wmep_logcwmin) | | | 2602 | SM(R92C_EDCA_PARAM_ECWMIN, wmep->wmep_logcwmin) | |
2603 | SM(R92C_EDCA_PARAM_ECWMAX, wmep->wmep_logcwmax) | | | 2603 | SM(R92C_EDCA_PARAM_ECWMAX, wmep->wmep_logcwmax) | |
2604 | SM(R92C_EDCA_PARAM_AIFS, aifs)); | | 2604 | SM(R92C_EDCA_PARAM_AIFS, aifs)); |
2605 | } | | 2605 | } |
2606 | mutex_exit(&sc->sc_write_mtx); | | 2606 | mutex_exit(&sc->sc_write_mtx); |
2607 | splx(s); | | 2607 | splx(s); |
2608 | } | | 2608 | } |
2609 | | | 2609 | |
2610 | static void | | 2610 | static void |
2611 | urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) | | 2611 | urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) |
2612 | { | | 2612 | { |
2613 | int pwdb; | | 2613 | int pwdb; |
2614 | | | 2614 | |
2615 | DPRINTFN(DBG_FN, ("%s: %s: rate=%d, rsst=%d\n", | | 2615 | DPRINTFN(DBG_FN, ("%s: %s: rate=%d, rsst=%d\n", |
2616 | device_xname(sc->sc_dev), __func__, rate, rssi)); | | 2616 | device_xname(sc->sc_dev), __func__, rate, rssi)); |
2617 | | | 2617 | |
2618 | /* Convert antenna signal to percentage. */ | | 2618 | /* Convert antenna signal to percentage. */ |
2619 | if (rssi <= -100 || rssi >= 20) | | 2619 | if (rssi <= -100 || rssi >= 20) |
2620 | pwdb = 0; | | 2620 | pwdb = 0; |
2621 | else if (rssi >= 0) | | 2621 | else if (rssi >= 0) |
2622 | pwdb = 100; | | 2622 | pwdb = 100; |
2623 | else | | 2623 | else |
2624 | pwdb = 100 + rssi; | | 2624 | pwdb = 100 + rssi; |
2625 | if (!ISSET(sc->chip, URTWN_CHIP_88E)) { | | 2625 | if (!ISSET(sc->chip, URTWN_CHIP_88E)) { |
2626 | if (rate <= 3) { | | 2626 | if (rate <= 3) { |
2627 | /* CCK gain is smaller than OFDM/MCS gain. */ | | 2627 | /* CCK gain is smaller than OFDM/MCS gain. */ |
2628 | pwdb += 6; | | 2628 | pwdb += 6; |
2629 | if (pwdb > 100) | | 2629 | if (pwdb > 100) |
2630 | pwdb = 100; | | 2630 | pwdb = 100; |
2631 | if (pwdb <= 14) | | 2631 | if (pwdb <= 14) |
2632 | pwdb -= 4; | | 2632 | pwdb -= 4; |
2633 | else if (pwdb <= 26) | | 2633 | else if (pwdb <= 26) |
2634 | pwdb -= 8; | | 2634 | pwdb -= 8; |
2635 | else if (pwdb <= 34) | | 2635 | else if (pwdb <= 34) |
2636 | pwdb -= 6; | | 2636 | pwdb -= 6; |
2637 | else if (pwdb <= 42) | | 2637 | else if (pwdb <= 42) |
2638 | pwdb -= 2; | | 2638 | pwdb -= 2; |
2639 | } | | 2639 | } |
2640 | } | | 2640 | } |
2641 | if (sc->avg_pwdb == -1) /* Init. */ | | 2641 | if (sc->avg_pwdb == -1) /* Init. */ |
2642 | sc->avg_pwdb = pwdb; | | 2642 | sc->avg_pwdb = pwdb; |
2643 | else if (sc->avg_pwdb < pwdb) | | 2643 | else if (sc->avg_pwdb < pwdb) |
2644 | sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; | | 2644 | sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; |
2645 | else | | 2645 | else |
2646 | sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); | | 2646 | sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); |
2647 | | | 2647 | |
2648 | DPRINTFN(DBG_RF, ("%s: %s: rate=%d rssi=%d PWDB=%d EMA=%d\n", | | 2648 | DPRINTFN(DBG_RF, ("%s: %s: rate=%d rssi=%d PWDB=%d EMA=%d\n", |
2649 | device_xname(sc->sc_dev), __func__, | | 2649 | device_xname(sc->sc_dev), __func__, |
2650 | rate, rssi, pwdb, sc->avg_pwdb)); | | 2650 | rate, rssi, pwdb, sc->avg_pwdb)); |
2651 | } | | 2651 | } |
2652 | | | 2652 | |
2653 | static int8_t | | 2653 | static int8_t |
2654 | urtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt) | | 2654 | urtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt) |
2655 | { | | 2655 | { |
2656 | static const int8_t cckoff[] = { 16, -12, -26, -46 }; | | 2656 | static const int8_t cckoff[] = { 16, -12, -26, -46 }; |
2657 | struct r92c_rx_phystat *phy; | | 2657 | struct r92c_rx_phystat *phy; |
2658 | struct r92c_rx_cck *cck; | | 2658 | struct r92c_rx_cck *cck; |
2659 | uint8_t rpt; | | 2659 | uint8_t rpt; |
2660 | int8_t rssi; | | 2660 | int8_t rssi; |
2661 | | | 2661 | |
2662 | DPRINTFN(DBG_FN, ("%s: %s: rate=%d\n", device_xname(sc->sc_dev), | | 2662 | DPRINTFN(DBG_FN, ("%s: %s: rate=%d\n", device_xname(sc->sc_dev), |
2663 | __func__, rate)); | | 2663 | __func__, rate)); |
2664 | | | 2664 | |
2665 | if (rate <= 3) { | | 2665 | if (rate <= 3) { |
2666 | cck = (struct r92c_rx_cck *)physt; | | 2666 | cck = (struct r92c_rx_cck *)physt; |
2667 | if (ISSET(sc->sc_flags, URTWN_FLAG_CCK_HIPWR)) { | | 2667 | if (ISSET(sc->sc_flags, URTWN_FLAG_CCK_HIPWR)) { |
2668 | rpt = (cck->agc_rpt >> 5) & 0x3; | | 2668 | rpt = (cck->agc_rpt >> 5) & 0x3; |
2669 | rssi = (cck->agc_rpt & 0x1f) << 1; | | 2669 | rssi = (cck->agc_rpt & 0x1f) << 1; |
2670 | } else { | | 2670 | } else { |
2671 | rpt = (cck->agc_rpt >> 6) & 0x3; | | 2671 | rpt = (cck->agc_rpt >> 6) & 0x3; |
2672 | rssi = cck->agc_rpt & 0x3e; | | 2672 | rssi = cck->agc_rpt & 0x3e; |
2673 | } | | 2673 | } |
2674 | rssi = cckoff[rpt] - rssi; | | 2674 | rssi = cckoff[rpt] - rssi; |
2675 | } else { /* OFDM/HT. */ | | 2675 | } else { /* OFDM/HT. */ |
2676 | phy = (struct r92c_rx_phystat *)physt; | | 2676 | phy = (struct r92c_rx_phystat *)physt; |
2677 | rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; | | 2677 | rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; |
2678 | } | | 2678 | } |
2679 | return rssi; | | 2679 | return rssi; |
2680 | } | | 2680 | } |
2681 | | | 2681 | |
2682 | static int8_t | | 2682 | static int8_t |
2683 | urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt) | | 2683 | urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt) |
2684 | { | | 2684 | { |
2685 | struct r92c_rx_phystat *phy; | | 2685 | struct r92c_rx_phystat *phy; |
2686 | struct r88e_rx_cck *cck; | | 2686 | struct r88e_rx_cck *cck; |
2687 | uint8_t cck_agc_rpt, lna_idx, vga_idx; | | 2687 | uint8_t cck_agc_rpt, lna_idx, vga_idx; |
2688 | int8_t rssi; | | 2688 | int8_t rssi; |
2689 | | | 2689 | |
2690 | DPRINTFN(DBG_FN, ("%s: %s: rate=%d\n", device_xname(sc->sc_dev), | | 2690 | DPRINTFN(DBG_FN, ("%s: %s: rate=%d\n", device_xname(sc->sc_dev), |
2691 | __func__, rate)); | | 2691 | __func__, rate)); |
2692 | | | 2692 | |
2693 | rssi = 0; | | 2693 | rssi = 0; |
2694 | if (rate <= 3) { | | 2694 | if (rate <= 3) { |
2695 | cck = (struct r88e_rx_cck *)physt; | | 2695 | cck = (struct r88e_rx_cck *)physt; |
2696 | cck_agc_rpt = cck->agc_rpt; | | 2696 | cck_agc_rpt = cck->agc_rpt; |
2697 | lna_idx = (cck_agc_rpt & 0xe0) >> 5; | | 2697 | lna_idx = (cck_agc_rpt & 0xe0) >> 5; |
2698 | vga_idx = cck_agc_rpt & 0x1f; | | 2698 | vga_idx = cck_agc_rpt & 0x1f; |
2699 | switch (lna_idx) { | | 2699 | switch (lna_idx) { |
2700 | case 7: | | 2700 | case 7: |
2701 | if (vga_idx <= 27) | | 2701 | if (vga_idx <= 27) |
2702 | rssi = -100 + 2* (27 - vga_idx); | | 2702 | rssi = -100 + 2* (27 - vga_idx); |
2703 | else | | 2703 | else |
2704 | rssi = -100; | | 2704 | rssi = -100; |
2705 | break; | | 2705 | break; |
2706 | case 6: | | 2706 | case 6: |
2707 | rssi = -48 + 2 * (2 - vga_idx); | | 2707 | rssi = -48 + 2 * (2 - vga_idx); |
2708 | break; | | 2708 | break; |
2709 | case 5: | | 2709 | case 5: |
2710 | rssi = -42 + 2 * (7 - vga_idx); | | 2710 | rssi = -42 + 2 * (7 - vga_idx); |
2711 | break; | | 2711 | break; |
2712 | case 4: | | 2712 | case 4: |
2713 | rssi = -36 + 2 * (7 - vga_idx); | | 2713 | rssi = -36 + 2 * (7 - vga_idx); |
2714 | break; | | 2714 | break; |
2715 | case 3: | | 2715 | case 3: |
2716 | rssi = -24 + 2 * (7 - vga_idx); | | 2716 | rssi = -24 + 2 * (7 - vga_idx); |
2717 | break; | | 2717 | break; |
2718 | case 2: | | 2718 | case 2: |
2719 | rssi = -12 + 2 * (5 - vga_idx); | | 2719 | rssi = -12 + 2 * (5 - vga_idx); |
2720 | break; | | 2720 | break; |
2721 | case 1: | | 2721 | case 1: |
2722 | rssi = 8 - (2 * vga_idx); | | 2722 | rssi = 8 - (2 * vga_idx); |
2723 | break; | | 2723 | break; |
2724 | case 0: | | 2724 | case 0: |
2725 | rssi = 14 - (2 * vga_idx); | | 2725 | rssi = 14 - (2 * vga_idx); |
2726 | break; | | 2726 | break; |
2727 | } | | 2727 | } |
2728 | rssi += 6; | | 2728 | rssi += 6; |
2729 | } else { /* OFDM/HT. */ | | 2729 | } else { /* OFDM/HT. */ |
2730 | phy = (struct r92c_rx_phystat *)physt; | | 2730 | phy = (struct r92c_rx_phystat *)physt; |
2731 | rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; | | 2731 | rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; |
2732 | } | | 2732 | } |
2733 | return rssi; | | 2733 | return rssi; |
2734 | } | | 2734 | } |
2735 | | | 2735 | |
2736 | static void | | 2736 | static void |
2737 | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen) | | 2737 | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen) |
2738 | { | | 2738 | { |
2739 | struct ieee80211com *ic = &sc->sc_ic; | | 2739 | struct ieee80211com *ic = &sc->sc_ic; |
2740 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | | 2740 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); |
2741 | struct ifnet *ifp = vap->iv_ifp; | | 2741 | struct ifnet *ifp = vap->iv_ifp; |
2742 | struct ieee80211_frame *wh; | | 2742 | struct ieee80211_frame *wh; |
2743 | struct ieee80211_node *ni; | | 2743 | struct ieee80211_node *ni; |
2744 | struct r92c_rx_desc_usb *stat; | | 2744 | struct r92c_rx_desc_usb *stat; |
2745 | uint32_t rxdw0, rxdw3; | | 2745 | uint32_t rxdw0, rxdw3; |
2746 | struct mbuf *m; | | 2746 | struct mbuf *m; |
2747 | uint8_t rate; | | 2747 | uint8_t rate; |
2748 | int8_t rssi = 0; | | 2748 | int8_t rssi = 0; |
2749 | int s, infosz; | | 2749 | int s, infosz; |
2750 | | | 2750 | |
2751 | DPRINTFN(DBG_FN, ("%s: %s: buf=%p, pktlen=%d\n", | | 2751 | DPRINTFN(DBG_FN, ("%s: %s: buf=%p, pktlen=%d\n", |
2752 | device_xname(sc->sc_dev), __func__, buf, pktlen)); | | 2752 | device_xname(sc->sc_dev), __func__, buf, pktlen)); |
2753 | | | 2753 | |
2754 | stat = (struct r92c_rx_desc_usb *)buf; | | 2754 | stat = (struct r92c_rx_desc_usb *)buf; |
2755 | rxdw0 = le32toh(stat->rxdw0); | | 2755 | rxdw0 = le32toh(stat->rxdw0); |
2756 | rxdw3 = le32toh(stat->rxdw3); | | 2756 | rxdw3 = le32toh(stat->rxdw3); |
2757 | | | 2757 | |
2758 | if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { | | 2758 | if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { |
2759 | /* | | 2759 | /* |
2760 | * This should not happen since we setup our Rx filter | | 2760 | * This should not happen since we setup our Rx filter |
2761 | * to not receive these frames. | | 2761 | * to not receive these frames. |
2762 | */ | | 2762 | */ |
2763 | DPRINTFN(DBG_RX, ("%s: %s: CRC error\n", | | 2763 | DPRINTFN(DBG_RX, ("%s: %s: CRC error\n", |
2764 | device_xname(sc->sc_dev), __func__)); | | 2764 | device_xname(sc->sc_dev), __func__)); |
2765 | if_statinc(ifp, if_ierrors); | | 2765 | if_statinc(ifp, if_ierrors); |
2766 | return; | | 2766 | return; |
2767 | } | | 2767 | } |
2768 | | | 2768 | |
2769 | /* | | 2769 | /* |
2770 | * XXX: This will drop most control packets. Do we really | | 2770 | * XXX: This will drop most control packets. Do we really |
2771 | * want this in IEEE80211_M_MONITOR mode? | | 2771 | * want this in IEEE80211_M_MONITOR mode? |
2772 | */ | | 2772 | */ |
2773 | // if (__predict_false(pktlen < (int)sizeof(*wh))) { | | 2773 | // if (__predict_false(pktlen < (int)sizeof(*wh))) { |
2774 | if (__predict_false(pktlen < (int)sizeof(struct ieee80211_frame_ack))) { | | 2774 | if (__predict_false(pktlen < (int)sizeof(struct ieee80211_frame_ack))) { |
2775 | DPRINTFN(DBG_RX, ("%s: %s: packet too short %d\n", | | 2775 | DPRINTFN(DBG_RX, ("%s: %s: packet too short %d\n", |
2776 | device_xname(sc->sc_dev), __func__, pktlen)); | | 2776 | device_xname(sc->sc_dev), __func__, pktlen)); |
2777 | vap->iv_stats.is_rx_tooshort++; | | 2777 | vap->iv_stats.is_rx_tooshort++; |
2778 | if_statinc(ifp,if_ierrors); | | 2778 | if_statinc(ifp,if_ierrors); |
2779 | return; | | 2779 | return; |
2780 | } | | 2780 | } |
2781 | if (__predict_false(pktlen > MCLBYTES)) { | | 2781 | if (__predict_false(pktlen > MCLBYTES)) { |
2782 | DPRINTFN(DBG_RX, ("%s: %s: packet too big %d\n", | | 2782 | DPRINTFN(DBG_RX, ("%s: %s: packet too big %d\n", |
2783 | device_xname(sc->sc_dev), __func__, pktlen)); | | 2783 | device_xname(sc->sc_dev), __func__, pktlen)); |
2784 | if_statinc(ifp, if_ierrors); | | 2784 | if_statinc(ifp, if_ierrors); |
2785 | return; | | 2785 | return; |
2786 | } | | 2786 | } |
2787 | | | 2787 | |
2788 | rate = MS(rxdw3, R92C_RXDW3_RATE); | | 2788 | rate = MS(rxdw3, R92C_RXDW3_RATE); |
2789 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; | | 2789 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; |
2790 | | | 2790 | |
2791 | /* Get RSSI from PHY status descriptor if present. */ | | 2791 | /* Get RSSI from PHY status descriptor if present. */ |
2792 | if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { | | 2792 | if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { |
2793 | if (!ISSET(sc->chip, URTWN_CHIP_92C)) | | 2793 | if (!ISSET(sc->chip, URTWN_CHIP_92C)) |
2794 | rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]); | | 2794 | rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]); |
2795 | else | | 2795 | else |
2796 | rssi = urtwn_get_rssi(sc, rate, &stat[1]); | | 2796 | rssi = urtwn_get_rssi(sc, rate, &stat[1]); |
2797 | /* Update our average RSSI. */ | | 2797 | /* Update our average RSSI. */ |
2798 | urtwn_update_avgrssi(sc, rate, rssi); | | 2798 | urtwn_update_avgrssi(sc, rate, rssi); |
2799 | } | | 2799 | } |
2800 | | | 2800 | |
2801 | DPRINTFN(DBG_RX, ("%s: %s: Rx frame len=%d rate=%d infosz=%d rssi=%d\n", | | 2801 | DPRINTFN(DBG_RX, ("%s: %s: Rx frame len=%d rate=%d infosz=%d rssi=%d\n", |
2802 | device_xname(sc->sc_dev), __func__, pktlen, rate, infosz, rssi)); | | 2802 | device_xname(sc->sc_dev), __func__, pktlen, rate, infosz, rssi)); |
2803 | | | 2803 | |
2804 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 2804 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
2805 | if (__predict_false(m == NULL)) { | | 2805 | if (__predict_false(m == NULL)) { |
2806 | aprint_error_dev(sc->sc_dev, "couldn't allocate rx mbuf\n"); | | 2806 | aprint_error_dev(sc->sc_dev, "couldn't allocate rx mbuf\n"); |
2807 | vap->iv_stats.is_rx_nobuf++; | | 2807 | vap->iv_stats.is_rx_nobuf++; |
2808 | if_statinc(ifp, if_ierrors); | | 2808 | if_statinc(ifp, if_ierrors); |
2809 | return; | | 2809 | return; |
2810 | } | | 2810 | } |
2811 | if (pktlen > (int)MHLEN) { | | 2811 | if (pktlen > (int)MHLEN) { |
2812 | MCLGET(m, M_DONTWAIT); | | 2812 | MCLGET(m, M_DONTWAIT); |
2813 | if (__predict_false(!(m->m_flags & M_EXT))) { | | 2813 | if (__predict_false(!(m->m_flags & M_EXT))) { |
2814 | aprint_error_dev(sc->sc_dev, | | 2814 | aprint_error_dev(sc->sc_dev, |
2815 | "couldn't allocate rx mbuf cluster\n"); | | 2815 | "couldn't allocate rx mbuf cluster\n"); |
2816 | m_freem(m); | | 2816 | m_freem(m); |
2817 | vap->iv_stats.is_rx_nobuf++; | | 2817 | vap->iv_stats.is_rx_nobuf++; |
2818 | if_statinc(ifp, if_ierrors); | | 2818 | if_statinc(ifp, if_ierrors); |
2819 | return; | | 2819 | return; |
2820 | } | | 2820 | } |
2821 | } | | 2821 | } |
2822 | | | 2822 | |
2823 | /* Finalize mbuf. */ | | 2823 | /* Finalize mbuf. */ |
2824 | m_set_rcvif(m, ifp); | | 2824 | m_set_rcvif(m, ifp); |
2825 | wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); | | 2825 | wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); |
2826 | | | 2826 | |
2827 | memcpy(mtod(m, uint8_t *), wh, pktlen); | | 2827 | memcpy(mtod(m, uint8_t *), wh, pktlen); |
2828 | m->m_pkthdr.len = m->m_len = pktlen; | | 2828 | m->m_pkthdr.len = m->m_len = pktlen; |
2829 | | | 2829 | |
2830 | s = splnet(); | | 2830 | s = splnet(); |
2831 | if (__predict_false(sc->sc_drvbpf != NULL)) { | | 2831 | if (__predict_false(sc->sc_drvbpf != NULL)) { |
2832 | struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; | | 2832 | struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; |
2833 | | | 2833 | |
2834 | tap->wr_flags = 0; | | 2834 | tap->wr_flags = 0; |
2835 | if (!(rxdw3 & R92C_RXDW3_HT)) { | | 2835 | if (!(rxdw3 & R92C_RXDW3_HT)) { |
2836 | switch (rate) { | | 2836 | switch (rate) { |
2837 | /* CCK. */ | | 2837 | /* CCK. */ |
2838 | case 0: tap->wr_rate = 2; break; | | 2838 | case 0: tap->wr_rate = 2; break; |
2839 | case 1: tap->wr_rate = 4; break; | | 2839 | case 1: tap->wr_rate = 4; break; |
2840 | case 2: tap->wr_rate = 11; break; | | 2840 | case 2: tap->wr_rate = 11; break; |
2841 | case 3: tap->wr_rate = 22; break; | | 2841 | case 3: tap->wr_rate = 22; break; |
2842 | /* OFDM. */ | | 2842 | /* OFDM. */ |
2843 | case 4: tap->wr_rate = 12; break; | | 2843 | case 4: tap->wr_rate = 12; break; |
2844 | case 5: tap->wr_rate = 18; break; | | 2844 | case 5: tap->wr_rate = 18; break; |
2845 | case 6: tap->wr_rate = 24; break; | | 2845 | case 6: tap->wr_rate = 24; break; |
2846 | case 7: tap->wr_rate = 36; break; | | 2846 | case 7: tap->wr_rate = 36; break; |
2847 | case 8: tap->wr_rate = 48; break; | | 2847 | case 8: tap->wr_rate = 48; break; |
2848 | case 9: tap->wr_rate = 72; break; | | 2848 | case 9: tap->wr_rate = 72; break; |
2849 | case 10: tap->wr_rate = 96; break; | | 2849 | case 10: tap->wr_rate = 96; break; |
2850 | case 11: tap->wr_rate = 108; break; | | 2850 | case 11: tap->wr_rate = 108; break; |
2851 | } | | 2851 | } |
2852 | } else if (rate >= 12) { /* MCS0~15. */ | | 2852 | } else if (rate >= 12) { /* MCS0~15. */ |
2853 | /* Bit 7 set means HT MCS instead of rate. */ | | 2853 | /* Bit 7 set means HT MCS instead of rate. */ |
2854 | tap->wr_rate = 0x80 | (rate - 12); | | 2854 | tap->wr_rate = 0x80 | (rate - 12); |
2855 | } | | 2855 | } |
2856 | tap->wr_dbm_antsignal = rssi; | | 2856 | tap->wr_dbm_antsignal = rssi; |
2857 | tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); | | 2857 | tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); |
2858 | tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); | | 2858 | tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); |
2859 | | | 2859 | |
2860 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_D_IN); | | 2860 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_D_IN); |
2861 | } | | 2861 | } |
2862 | | | 2862 | |
2863 | ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); | | 2863 | ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); |
2864 | | | 2864 | |
2865 | if (ni != NULL) { | | 2865 | if (ni != NULL) { |
2866 | if (ni->ni_vap != NULL) { | | 2866 | if (ni->ni_vap != NULL) { |
2867 | | | 2867 | |
2868 | } else { | | 2868 | } else { |
2869 | splx(s); | | 2869 | splx(s); |
2870 | return; | | 2870 | return; |
2871 | } | | 2871 | } |
2872 | /* push the frame up to the 802.11 stack */ | | 2872 | /* push the frame up to the 802.11 stack */ |
2873 | /* NNN Convert rssi to -10 to 110 ? for 802.11 layer */ | | 2873 | /* NNN Convert rssi to -10 to 110 ? for 802.11 layer */ |
2874 | ieee80211_input(ni, m, rssi+90, 0); | | 2874 | ieee80211_input(ni, m, rssi+90, 0); |
2875 | | | 2875 | |
2876 | /* Node is no longer needed. */ | | 2876 | /* Node is no longer needed. */ |
2877 | ieee80211_free_node(ni); | | 2877 | ieee80211_free_node(ni); |
2878 | | | 2878 | |
2879 | } else { | | 2879 | } else { |
2880 | | | 2880 | |
2881 | /* No node found ... process differently. */ | | 2881 | /* No node found ... process differently. */ |
2882 | (void) ieee80211_input_all(ic, m, rssi+90, 0); | | 2882 | (void) ieee80211_input_all(ic, m, rssi+90, 0); |
2883 | } | | 2883 | } |
2884 | | | 2884 | |
2885 | splx(s); | | 2885 | splx(s); |
2886 | } | | 2886 | } |
2887 | | | 2887 | |
2888 | static void | | 2888 | static void |
2889 | urtwn_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 2889 | urtwn_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
2890 | { | | 2890 | { |
2891 | struct urtwn_rx_data *data = priv; | | 2891 | struct urtwn_rx_data *data = priv; |
2892 | struct urtwn_softc *sc = data->sc; | | 2892 | struct urtwn_softc *sc = data->sc; |
2893 | struct r92c_rx_desc_usb *stat; | | 2893 | struct r92c_rx_desc_usb *stat; |
2894 | size_t pidx = data->pidx; | | 2894 | size_t pidx = data->pidx; |
2895 | uint32_t rxdw0; | | 2895 | uint32_t rxdw0; |
2896 | uint8_t *buf; | | 2896 | uint8_t *buf; |
2897 | int len, totlen, pktlen, infosz, npkts; | | 2897 | int len, totlen, pktlen, infosz, npkts; |
2898 | | | 2898 | |
2899 | DPRINTFN(DBG_FN|DBG_RX, ("%s: %s: status=%d\n", | | 2899 | DPRINTFN(DBG_FN|DBG_RX, ("%s: %s: status=%d\n", |
2900 | device_xname(sc->sc_dev), __func__, status)); | | 2900 | device_xname(sc->sc_dev), __func__, status)); |
2901 | | | 2901 | |
2902 | mutex_enter(&sc->sc_rx_mtx); | | 2902 | mutex_enter(&sc->sc_rx_mtx); |
2903 | TAILQ_REMOVE(&sc->rx_free_list[pidx], data, next); | | 2903 | TAILQ_REMOVE(&sc->rx_free_list[pidx], data, next); |
2904 | TAILQ_INSERT_TAIL(&sc->rx_free_list[pidx], data, next); | | 2904 | TAILQ_INSERT_TAIL(&sc->rx_free_list[pidx], data, next); |
2905 | /* Put this Rx buffer back to our free list. */ | | 2905 | /* Put this Rx buffer back to our free list. */ |
2906 | mutex_exit(&sc->sc_rx_mtx); | | 2906 | mutex_exit(&sc->sc_rx_mtx); |
2907 | | | 2907 | |
2908 | if (__predict_false(status != USBD_NORMAL_COMPLETION)) { | | 2908 | if (__predict_false(status != USBD_NORMAL_COMPLETION)) { |
2909 | if (status == USBD_STALLED) | | 2909 | if (status == USBD_STALLED) |
2910 | usbd_clear_endpoint_stall_async(sc->rx_pipe[pidx]); | | 2910 | usbd_clear_endpoint_stall_async(sc->rx_pipe[pidx]); |
2911 | else if (status != USBD_CANCELLED) | | 2911 | else if (status != USBD_CANCELLED) |
2912 | goto resubmit; | | 2912 | goto resubmit; |
2913 | return; | | 2913 | return; |
2914 | } | | 2914 | } |
2915 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); | | 2915 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); |
2916 | | | 2916 | |
2917 | if (__predict_false(len < (int)sizeof(*stat))) { | | 2917 | if (__predict_false(len < (int)sizeof(*stat))) { |
2918 | DPRINTFN(DBG_RX, ("%s: %s: xfer too short %d\n", | | 2918 | DPRINTFN(DBG_RX, ("%s: %s: xfer too short %d\n", |
2919 | device_xname(sc->sc_dev), __func__, len)); | | 2919 | device_xname(sc->sc_dev), __func__, len)); |
2920 | goto resubmit; | | 2920 | goto resubmit; |
2921 | } | | 2921 | } |
2922 | buf = data->buf; | | 2922 | buf = data->buf; |
2923 | | | 2923 | |
2924 | /* Get the number of encapsulated frames. */ | | 2924 | /* Get the number of encapsulated frames. */ |
2925 | stat = (struct r92c_rx_desc_usb *)buf; | | 2925 | stat = (struct r92c_rx_desc_usb *)buf; |
2926 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) | | 2926 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) |
2927 | npkts = MS(le32toh(stat->rxdw2), R92E_RXDW2_PKTCNT); | | 2927 | npkts = MS(le32toh(stat->rxdw2), R92E_RXDW2_PKTCNT); |
2928 | else | | 2928 | else |
2929 | npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); | | 2929 | npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); |
2930 | DPRINTFN(DBG_RX, ("%s: %s: Rx %d frames in one chunk\n", | | 2930 | DPRINTFN(DBG_RX, ("%s: %s: Rx %d frames in one chunk\n", |
2931 | device_xname(sc->sc_dev), __func__, npkts)); | | 2931 | device_xname(sc->sc_dev), __func__, npkts)); |
2932 | | | 2932 | |
2933 | /* Process all of them. */ | | 2933 | /* Process all of them. */ |
2934 | while (npkts-- > 0) { | | 2934 | while (npkts-- > 0) { |
2935 | if (__predict_false(len < (int)sizeof(*stat))) { | | 2935 | if (__predict_false(len < (int)sizeof(*stat))) { |
2936 | DPRINTFN(DBG_RX, | | 2936 | DPRINTFN(DBG_RX, |
2937 | ("%s: %s: len(%d) is short than header\n", | | 2937 | ("%s: %s: len(%d) is short than header\n", |
2938 | device_xname(sc->sc_dev), __func__, len)); | | 2938 | device_xname(sc->sc_dev), __func__, len)); |
2939 | break; | | 2939 | break; |
2940 | } | | 2940 | } |
2941 | stat = (struct r92c_rx_desc_usb *)buf; | | 2941 | stat = (struct r92c_rx_desc_usb *)buf; |
2942 | rxdw0 = le32toh(stat->rxdw0); | | 2942 | rxdw0 = le32toh(stat->rxdw0); |
2943 | | | 2943 | |
2944 | pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); | | 2944 | pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); |
2945 | if (__predict_false(pktlen == 0)) { | | 2945 | if (__predict_false(pktlen == 0)) { |
2946 | DPRINTFN(DBG_RX, ("%s: %s: pktlen is 0 byte\n", | | 2946 | DPRINTFN(DBG_RX, ("%s: %s: pktlen is 0 byte\n", |
2947 | device_xname(sc->sc_dev), __func__)); | | 2947 | device_xname(sc->sc_dev), __func__)); |
2948 | break; | | 2948 | break; |
2949 | } | | 2949 | } |
2950 | | | 2950 | |
2951 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; | | 2951 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; |
2952 | | | 2952 | |
2953 | /* Make sure everything fits in xfer. */ | | 2953 | /* Make sure everything fits in xfer. */ |
2954 | totlen = sizeof(*stat) + infosz + pktlen; | | 2954 | totlen = sizeof(*stat) + infosz + pktlen; |
2955 | if (__predict_false(totlen > len)) { | | 2955 | if (__predict_false(totlen > len)) { |
2956 | DPRINTFN(DBG_RX, ("%s: %s: pktlen %d(%d+%d+%d) > %d\n", | | 2956 | DPRINTFN(DBG_RX, ("%s: %s: pktlen %d(%d+%d+%d) > %d\n", |
2957 | device_xname(sc->sc_dev), __func__, totlen, | | 2957 | device_xname(sc->sc_dev), __func__, totlen, |
2958 | (int)sizeof(*stat), infosz, pktlen, len)); | | 2958 | (int)sizeof(*stat), infosz, pktlen, len)); |
2959 | break; | | 2959 | break; |
2960 | } | | 2960 | } |
2961 | | | 2961 | |
2962 | /* Process 802.11 frame. */ | | 2962 | /* Process 802.11 frame. */ |
2963 | urtwn_rx_frame(sc, buf, pktlen); | | 2963 | urtwn_rx_frame(sc, buf, pktlen); |
2964 | | | 2964 | |
2965 | /* Next chunk is 128-byte aligned. */ | | 2965 | /* Next chunk is 128-byte aligned. */ |
2966 | totlen = roundup2(totlen, 128); | | 2966 | totlen = roundup2(totlen, 128); |
2967 | buf += totlen; | | 2967 | buf += totlen; |
2968 | len -= totlen; | | 2968 | len -= totlen; |
2969 | } | | 2969 | } |
2970 | | | 2970 | |
2971 | resubmit: | | 2971 | resubmit: |
2972 | /* Setup a new transfer. */ | | 2972 | /* Setup a new transfer. */ |
2973 | usbd_setup_xfer(xfer, data, data->buf, URTWN_RXBUFSZ, | | 2973 | usbd_setup_xfer(xfer, data, data->buf, URTWN_RXBUFSZ, |
2974 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, urtwn_rxeof); | | 2974 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, urtwn_rxeof); |
2975 | (void)usbd_transfer(xfer); | | 2975 | (void)usbd_transfer(xfer); |
2976 | } | | 2976 | } |
2977 | | | 2977 | |
2978 | static void | | 2978 | static void |
2979 | urtwn_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 2979 | urtwn_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
2980 | { | | 2980 | { |
2981 | struct urtwn_tx_data *data = priv; | | 2981 | struct urtwn_tx_data *data = priv; |
2982 | struct urtwn_softc *sc = data->sc; | | 2982 | struct urtwn_softc *sc = data->sc; |
2983 | struct ifnet *ifp = TAILQ_FIRST(&sc->sc_ic.ic_vaps)->iv_ifp; | | 2983 | struct ifnet *ifp = TAILQ_FIRST(&sc->sc_ic.ic_vaps)->iv_ifp; |
2984 | size_t pidx = data->pidx; | | 2984 | size_t pidx = data->pidx; |
2985 | int s; | | 2985 | int s; |
2986 | | | 2986 | |
2987 | DPRINTFN(DBG_FN|DBG_TX, ("%s: %s: status=%d\n", | | 2987 | DPRINTFN(DBG_FN|DBG_TX, ("%s: %s: status=%d\n", |
2988 | device_xname(sc->sc_dev), __func__, status)); | | 2988 | device_xname(sc->sc_dev), __func__, status)); |
2989 | | | 2989 | |
2990 | mutex_enter(&sc->sc_tx_mtx); | | 2990 | mutex_enter(&sc->sc_tx_mtx); |
2991 | /* Put this Tx buffer back to our free list. */ | | 2991 | /* Put this Tx buffer back to our free list. */ |
2992 | TAILQ_INSERT_TAIL(&sc->tx_free_list[pidx], data, next); | | 2992 | TAILQ_INSERT_TAIL(&sc->tx_free_list[pidx], data, next); |
2993 | mutex_exit(&sc->sc_tx_mtx); | | 2993 | mutex_exit(&sc->sc_tx_mtx); |
2994 | | | 2994 | |
2995 | s = splnet(); | | 2995 | s = splnet(); |
2996 | sc->tx_timer = 0; | | 2996 | sc->tx_timer = 0; |
2997 | ifp->if_flags &= ~IFF_OACTIVE; | | 2997 | ifp->if_flags &= ~IFF_OACTIVE; |
2998 | | | 2998 | |
2999 | if (__predict_false(status != USBD_NORMAL_COMPLETION)) { | | 2999 | if (__predict_false(status != USBD_NORMAL_COMPLETION)) { |
3000 | if (status != USBD_NOT_STARTED && status != USBD_CANCELLED) { | | 3000 | if (status != USBD_NOT_STARTED && status != USBD_CANCELLED) { |
3001 | if (status == USBD_STALLED) { | | 3001 | if (status == USBD_STALLED) { |
3002 | struct usbd_pipe *pipe = sc->tx_pipe[pidx]; | | 3002 | struct usbd_pipe *pipe = sc->tx_pipe[pidx]; |
3003 | usbd_clear_endpoint_stall_async(pipe); | | 3003 | usbd_clear_endpoint_stall_async(pipe); |
3004 | } | | 3004 | } |
3005 | printf("ERROR1\n"); | | 3005 | printf("ERROR1\n"); |
3006 | if_statinc(ifp, if_oerrors); | | 3006 | if_statinc(ifp, if_oerrors); |
3007 | } | | 3007 | } |
3008 | splx(s); | | 3008 | splx(s); |
3009 | return; | | 3009 | return; |
3010 | } | | 3010 | } |
3011 | | | 3011 | |
3012 | if_statinc(ifp, if_opackets); | | 3012 | if_statinc(ifp, if_opackets); |
3013 | urtwn_start(ifp); | | 3013 | urtwn_start(ifp); |
3014 | splx(s); | | 3014 | splx(s); |
3015 | | | 3015 | |
3016 | } | | 3016 | } |
3017 | | | 3017 | |
3018 | static int | | 3018 | static int |
3019 | urtwn_tx(struct urtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, | | 3019 | urtwn_tx(struct urtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, |
3020 | struct urtwn_tx_data *data) | | 3020 | struct urtwn_tx_data *data) |
3021 | { | | 3021 | { |
3022 | struct ieee80211com *ic = &sc->sc_ic; | | 3022 | struct ieee80211com *ic = &sc->sc_ic; |
3023 | struct ieee80211_frame *wh; | | 3023 | struct ieee80211_frame *wh; |
3024 | struct ieee80211_key *k = NULL; | | 3024 | struct ieee80211_key *k = NULL; |
3025 | struct r92c_tx_desc_usb *txd; | | 3025 | struct r92c_tx_desc_usb *txd; |
3026 | size_t i, padsize, xferlen, txd_len; | | 3026 | size_t i, padsize, xferlen, txd_len; |
3027 | uint16_t seq, sum; | | 3027 | uint16_t seq, sum; |
3028 | uint8_t raid, type, tid; | | 3028 | uint8_t raid, type, tid; |
3029 | int s, hasqos, error; | | 3029 | int s, hasqos, error; |
3030 | | | 3030 | |
3031 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3031 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3032 | | | 3032 | |
3033 | wh = mtod(m, struct ieee80211_frame *); | | 3033 | wh = mtod(m, struct ieee80211_frame *); |
3034 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | | 3034 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
3035 | txd_len = sizeof(*txd); | | 3035 | txd_len = sizeof(*txd); |
3036 | | | 3036 | |
3037 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) | | 3037 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) |
3038 | txd_len = 32; | | 3038 | txd_len = 32; |
3039 | | | 3039 | |
3040 | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | | 3040 | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { |
3041 | k = ieee80211_crypto_encap(ni, m); | | 3041 | k = ieee80211_crypto_encap(ni, m); |
3042 | if (k == NULL) | | 3042 | if (k == NULL) |
3043 | return ENOBUFS; | | 3043 | return ENOBUFS; |
3044 | | | 3044 | |
3045 | /* packet header may have moved, reset our local pointer */ | | 3045 | /* packet header may have moved, reset our local pointer */ |
3046 | wh = mtod(m, struct ieee80211_frame *); | | 3046 | wh = mtod(m, struct ieee80211_frame *); |
3047 | } | | 3047 | } |
3048 | | | 3048 | |
3049 | if (__predict_false(sc->sc_drvbpf != NULL)) { | | 3049 | if (__predict_false(sc->sc_drvbpf != NULL)) { |
3050 | struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap; | | 3050 | struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap; |
3051 | | | 3051 | |
3052 | tap->wt_flags = 0; | | 3052 | tap->wt_flags = 0; |
3053 | tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); | | 3053 | tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); |
3054 | tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); | | 3054 | tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); |
3055 | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) | | 3055 | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) |
3056 | tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; | | 3056 | tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; |
3057 | | | 3057 | |
3058 | /* XXX: set tap->wt_rate? */ | | 3058 | /* XXX: set tap->wt_rate? */ |
3059 | | | 3059 | |
3060 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m, BPF_D_OUT); | | 3060 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m, BPF_D_OUT); |
3061 | } | | 3061 | } |
3062 | | | 3062 | |
3063 | /* non-qos data frames */ | | 3063 | /* non-qos data frames */ |
3064 | tid = R92C_TXDW1_QSEL_BE; | | 3064 | tid = R92C_TXDW1_QSEL_BE; |
3065 | if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { | | 3065 | if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { |
3066 | /* data frames in 11n mode */ | | 3066 | /* data frames in 11n mode */ |
3067 | struct ieee80211_qosframe *qwh = (void *)wh; | | 3067 | struct ieee80211_qosframe *qwh = (void *)wh; |
3068 | tid = qwh->i_qos[0] & IEEE80211_QOS_TID; | | 3068 | tid = qwh->i_qos[0] & IEEE80211_QOS_TID; |
3069 | } else if (type != IEEE80211_FC0_TYPE_DATA) { | | 3069 | } else if (type != IEEE80211_FC0_TYPE_DATA) { |
3070 | tid = R92C_TXDW1_QSEL_MGNT; | | 3070 | tid = R92C_TXDW1_QSEL_MGNT; |
3071 | } | | 3071 | } |
3072 | | | 3072 | |
3073 | if (((txd_len + m->m_pkthdr.len) % 64) == 0) /* XXX: 64 */ | | 3073 | if (((txd_len + m->m_pkthdr.len) % 64) == 0) /* XXX: 64 */ |
3074 | padsize = 8; | | 3074 | padsize = 8; |
3075 | else | | 3075 | else |
3076 | padsize = 0; | | 3076 | padsize = 0; |
3077 | | | 3077 | |
3078 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) | | 3078 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) |
3079 | padsize = 0; | | 3079 | padsize = 0; |
3080 | | | 3080 | |
3081 | /* Fill Tx descriptor. */ | | 3081 | /* Fill Tx descriptor. */ |
3082 | txd = (struct r92c_tx_desc_usb *)data->buf; | | 3082 | txd = (struct r92c_tx_desc_usb *)data->buf; |
3083 | memset(txd, 0, txd_len + padsize); | | 3083 | memset(txd, 0, txd_len + padsize); |
3084 | | | 3084 | |
3085 | txd->txdw0 |= htole32( | | 3085 | txd->txdw0 |= htole32( |
3086 | SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | | | 3086 | SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | |
3087 | SM(R92C_TXDW0_OFFSET, txd_len)); | | 3087 | SM(R92C_TXDW0_OFFSET, txd_len)); |
3088 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 3088 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { |
3089 | txd->txdw0 |= htole32( | | 3089 | txd->txdw0 |= htole32( |
3090 | R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); | | 3090 | R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); |
3091 | } | | 3091 | } |
3092 | | | 3092 | |
3093 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)) | | 3093 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)) |
3094 | txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); | | 3094 | txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); |
3095 | | | 3095 | |
3096 | /* fix pad field */ | | 3096 | /* fix pad field */ |
3097 | if (padsize > 0) { | | 3097 | if (padsize > 0) { |
3098 | DPRINTFN(DBG_TX, ("%s: %s: padding: size=%zd\n", | | 3098 | DPRINTFN(DBG_TX, ("%s: %s: padding: size=%zd\n", |
3099 | device_xname(sc->sc_dev), __func__, padsize)); | | 3099 | device_xname(sc->sc_dev), __func__, padsize)); |
3100 | txd->txdw1 |= htole32(SM(R92C_TXDW1_PKTOFF, (padsize / 8))); | | 3100 | txd->txdw1 |= htole32(SM(R92C_TXDW1_PKTOFF, (padsize / 8))); |
3101 | } | | 3101 | } |
3102 | | | 3102 | |
3103 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && | | 3103 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && |
3104 | type == IEEE80211_FC0_TYPE_DATA) { | | 3104 | type == IEEE80211_FC0_TYPE_DATA) { |
3105 | if (ic->ic_curmode == IEEE80211_MODE_11B) | | 3105 | if (ic->ic_curmode == IEEE80211_MODE_11B) |
3106 | raid = R92C_RAID_11B; | | 3106 | raid = R92C_RAID_11B; |
3107 | else | | 3107 | else |
3108 | raid = R92C_RAID_11BG; | | 3108 | raid = R92C_RAID_11BG; |
3109 | DPRINTFN(DBG_TX, | | 3109 | DPRINTFN(DBG_TX, |
3110 | ("%s: %s: data packet: tid=%d, raid=%d\n", | | 3110 | ("%s: %s: data packet: tid=%d, raid=%d\n", |
3111 | device_xname(sc->sc_dev), __func__, tid, raid)); | | 3111 | device_xname(sc->sc_dev), __func__, tid, raid)); |
3112 | | | 3112 | |
3113 | if (!ISSET(sc->chip, URTWN_CHIP_92C)) { | | 3113 | if (!ISSET(sc->chip, URTWN_CHIP_92C)) { |
3114 | txd->txdw1 |= htole32( | | 3114 | txd->txdw1 |= htole32( |
3115 | SM(R88E_TXDW1_MACID, RTWN_MACID_BSS) | | | 3115 | SM(R88E_TXDW1_MACID, RTWN_MACID_BSS) | |
3116 | SM(R92C_TXDW1_QSEL, tid) | | | 3116 | SM(R92C_TXDW1_QSEL, tid) | |
3117 | SM(R92C_TXDW1_RAID, raid) | | | 3117 | SM(R92C_TXDW1_RAID, raid) | |
3118 | R92C_TXDW1_AGGBK); | | 3118 | R92C_TXDW1_AGGBK); |
3119 | } else | | 3119 | } else |
3120 | txd->txdw1 |= htole32( | | 3120 | txd->txdw1 |= htole32( |
3121 | SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) | | | 3121 | SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) | |
3122 | SM(R92C_TXDW1_QSEL, tid) | | | 3122 | SM(R92C_TXDW1_QSEL, tid) | |
3123 | SM(R92C_TXDW1_RAID, raid) | | | 3123 | SM(R92C_TXDW1_RAID, raid) | |
3124 | R92C_TXDW1_AGGBK); | | 3124 | R92C_TXDW1_AGGBK); |
3125 | | | 3125 | |
3126 | if (ISSET(sc->chip, URTWN_CHIP_88E)) | | 3126 | if (ISSET(sc->chip, URTWN_CHIP_88E)) |
3127 | txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); | | 3127 | txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); |
3128 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) | | 3128 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) |
3129 | txd->txdw3 |= htole32(R92E_TXDW3_AGGBK); | | 3129 | txd->txdw3 |= htole32(R92E_TXDW3_AGGBK); |
3130 | | | 3130 | |
3131 | if (hasqos) { | | 3131 | if (hasqos) { |
3132 | txd->txdw4 |= htole32(R92C_TXDW4_QOS); | | 3132 | txd->txdw4 |= htole32(R92C_TXDW4_QOS); |
3133 | } | | 3133 | } |
3134 | | | 3134 | |
3135 | if (ic->ic_flags & IEEE80211_F_USEPROT) { | | 3135 | if (ic->ic_flags & IEEE80211_F_USEPROT) { |
3136 | /* for 11g */ | | 3136 | /* for 11g */ |
3137 | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { | | 3137 | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { |
3138 | txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF | | | 3138 | txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF | |
3139 | R92C_TXDW4_HWRTSEN); | | 3139 | R92C_TXDW4_HWRTSEN); |
3140 | } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { | | 3140 | } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { |
3141 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | | | 3141 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | |
3142 | R92C_TXDW4_HWRTSEN); | | 3142 | R92C_TXDW4_HWRTSEN); |
3143 | } | | 3143 | } |
3144 | } | | 3144 | } |
3145 | /* Send RTS at OFDM24. */ | | 3145 | /* Send RTS at OFDM24. */ |
3146 | txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 8)); | | 3146 | txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 8)); |
3147 | txd->txdw5 |= htole32(0x0001ff00); | | 3147 | txd->txdw5 |= htole32(0x0001ff00); |
3148 | /* Send data at OFDM54. */ | | 3148 | /* Send data at OFDM54. */ |
3149 | if (ISSET(sc->chip, URTWN_CHIP_88E)) | | 3149 | if (ISSET(sc->chip, URTWN_CHIP_88E)) |
3150 | txd->txdw5 |= htole32(0x13 & 0x3f); | | 3150 | txd->txdw5 |= htole32(0x13 & 0x3f); |
3151 | else | | 3151 | else |
3152 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11)); | | 3152 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11)); |
3153 | } else if (type == IEEE80211_FC0_TYPE_MGT) { | | 3153 | } else if (type == IEEE80211_FC0_TYPE_MGT) { |
3154 | DPRINTFN(DBG_TX, ("%s: %s: mgmt packet\n", | | 3154 | DPRINTFN(DBG_TX, ("%s: %s: mgmt packet\n", |
3155 | device_xname(sc->sc_dev), __func__)); | | 3155 | device_xname(sc->sc_dev), __func__)); |
3156 | txd->txdw1 |= htole32( | | 3156 | txd->txdw1 |= htole32( |
3157 | SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) | | | 3157 | SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) | |
3158 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) | | | 3158 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) | |
3159 | SM(R92C_TXDW1_RAID, R92C_RAID_11B)); | | 3159 | SM(R92C_TXDW1_RAID, R92C_RAID_11B)); |
3160 | | | 3160 | |
3161 | /* Force CCK1. */ | | 3161 | /* Force CCK1. */ |
3162 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); | | 3162 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); |
3163 | /* Use 1Mbps */ | | 3163 | /* Use 1Mbps */ |
3164 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); | | 3164 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); |
3165 | } else { | | 3165 | } else { |
3166 | /* broadcast or multicast packets */ | | 3166 | /* broadcast or multicast packets */ |
3167 | DPRINTFN(DBG_TX, ("%s: %s: bc or mc packet\n", | | 3167 | DPRINTFN(DBG_TX, ("%s: %s: bc or mc packet\n", |
3168 | device_xname(sc->sc_dev), __func__)); | | 3168 | device_xname(sc->sc_dev), __func__)); |
3169 | txd->txdw1 |= htole32( | | 3169 | txd->txdw1 |= htole32( |
3170 | SM(R92C_TXDW1_MACID, RTWN_MACID_BC) | | | 3170 | SM(R92C_TXDW1_MACID, RTWN_MACID_BC) | |
3171 | SM(R92C_TXDW1_RAID, R92C_RAID_11B)); | | 3171 | SM(R92C_TXDW1_RAID, R92C_RAID_11B)); |
3172 | | | 3172 | |
3173 | /* Force CCK1. */ | | 3173 | /* Force CCK1. */ |
3174 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); | | 3174 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); |
3175 | /* Use 1Mbps */ | | 3175 | /* Use 1Mbps */ |
3176 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); | | 3176 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); |
3177 | } | | 3177 | } |
3178 | /* Set sequence number */ | | 3178 | /* Set sequence number */ |
3179 | seq = LE_READ_2(&wh->i_seq[0]) >> IEEE80211_SEQ_SEQ_SHIFT; | | 3179 | seq = LE_READ_2(&wh->i_seq[0]) >> IEEE80211_SEQ_SEQ_SHIFT; |
3180 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 3180 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { |
3181 | txd->txdseq |= htole16(seq); | | 3181 | txd->txdseq |= htole16(seq); |
3182 | | | 3182 | |
3183 | if (!hasqos) { | | 3183 | if (!hasqos) { |
3184 | /* Use HW sequence numbering for non-QoS frames. */ | | 3184 | /* Use HW sequence numbering for non-QoS frames. */ |
3185 | txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); | | 3185 | txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); |
3186 | txd->txdseq |= htole16(R92C_HWSEQ_EN); | | 3186 | txd->txdseq |= htole16(R92C_HWSEQ_EN); |
3187 | } | | 3187 | } |
3188 | } else { | | 3188 | } else { |
3189 | txd->txdseq2 |= htole16((seq & R92E_HWSEQ_MASK) << | | 3189 | txd->txdseq2 |= htole16((seq & R92E_HWSEQ_MASK) << |
3190 | R92E_HWSEQ_SHIFT); | | 3190 | R92E_HWSEQ_SHIFT); |
3191 | if (!hasqos) { | | 3191 | if (!hasqos) { |
3192 | /* Use HW sequence numbering for non-QoS frames. */ | | 3192 | /* Use HW sequence numbering for non-QoS frames. */ |
3193 | txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); | | 3193 | txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); |
3194 | txd->txdw7 |= htole16(R92C_HWSEQ_EN); | | 3194 | txd->txdw7 |= htole16(R92C_HWSEQ_EN); |
3195 | } | | 3195 | } |
3196 | } | | 3196 | } |
3197 | | | 3197 | |
3198 | /* Compute Tx descriptor checksum. */ | | 3198 | /* Compute Tx descriptor checksum. */ |
3199 | sum = 0; | | 3199 | sum = 0; |
3200 | for (i = 0; i < R92C_TXDESC_SUMSIZE / 2; i++) | | 3200 | for (i = 0; i < R92C_TXDESC_SUMSIZE / 2; i++) |
3201 | sum ^= ((uint16_t *)txd)[i]; | | 3201 | sum ^= ((uint16_t *)txd)[i]; |
3202 | txd->txdsum = sum; /* NB: already little endian. */ | | 3202 | txd->txdsum = sum; /* NB: already little endian. */ |
3203 | | | 3203 | |
3204 | xferlen = txd_len + m->m_pkthdr.len + padsize; | | 3204 | xferlen = txd_len + m->m_pkthdr.len + padsize; |
3205 | m_copydata(m, 0, m->m_pkthdr.len, (char *)&txd[0] + txd_len + padsize); | | 3205 | m_copydata(m, 0, m->m_pkthdr.len, (char *)&txd[0] + txd_len + padsize); |
3206 | | | 3206 | |
3207 | if (data->xfer == NULL) { | | 3207 | if (data->xfer == NULL) { |
3208 | /* NNN Don't crash ... but what is going on! */ | | 3208 | /* NNN Don't crash ... but what is going on! */ |
3209 | printf ("urtwn_tx: data->xfer is NULL\n"); | | 3209 | printf ("urtwn_tx: data->xfer is NULL\n"); |
3210 | m_print(m,"", printf); | | 3210 | m_print(m,"", printf); |
3211 | return -1; | | 3211 | return -1; |
3212 | } | | 3212 | } |
3213 | | | 3213 | |
3214 | s = splnet(); | | 3214 | s = splnet(); |
3215 | usbd_setup_xfer(data->xfer, data, data->buf, xferlen, | | 3215 | usbd_setup_xfer(data->xfer, data, data->buf, xferlen, |
3216 | USBD_FORCE_SHORT_XFER, URTWN_TX_TIMEOUT, | | 3216 | USBD_FORCE_SHORT_XFER, URTWN_TX_TIMEOUT, |
3217 | urtwn_txeof); | | 3217 | urtwn_txeof); |
3218 | error = usbd_transfer(data->xfer); | | 3218 | error = usbd_transfer(data->xfer); |
3219 | if (__predict_false(error != USBD_NORMAL_COMPLETION && | | 3219 | if (__predict_false(error != USBD_NORMAL_COMPLETION && |
3220 | error != USBD_IN_PROGRESS)) { | | 3220 | error != USBD_IN_PROGRESS)) { |
3221 | splx(s); | | 3221 | splx(s); |
3222 | DPRINTFN(DBG_TX, ("%s: %s: transfer failed %d\n", | | 3222 | DPRINTFN(DBG_TX, ("%s: %s: transfer failed %d\n", |
3223 | device_xname(sc->sc_dev), __func__, error)); | | 3223 | device_xname(sc->sc_dev), __func__, error)); |
3224 | return error; | | 3224 | return error; |
3225 | } | | 3225 | } |
3226 | splx(s); | | 3226 | splx(s); |
3227 | return 0; | | 3227 | return 0; |
3228 | } | | 3228 | } |
3229 | | | 3229 | |
3230 | struct urtwn_tx_data * | | 3230 | struct urtwn_tx_data * |
3231 | urtwn_get_tx_data(struct urtwn_softc *sc, size_t pidx) | | 3231 | urtwn_get_tx_data(struct urtwn_softc *sc, size_t pidx) |
3232 | { | | 3232 | { |
3233 | struct urtwn_tx_data *data = NULL; | | 3233 | struct urtwn_tx_data *data = NULL; |
3234 | | | 3234 | |
3235 | mutex_enter(&sc->sc_tx_mtx); | | 3235 | mutex_enter(&sc->sc_tx_mtx); |
3236 | if (!TAILQ_EMPTY(&sc->tx_free_list[pidx])) { | | 3236 | if (!TAILQ_EMPTY(&sc->tx_free_list[pidx])) { |
3237 | data = TAILQ_FIRST(&sc->tx_free_list[pidx]); | | 3237 | data = TAILQ_FIRST(&sc->tx_free_list[pidx]); |
3238 | TAILQ_REMOVE(&sc->tx_free_list[pidx], data, next); | | 3238 | TAILQ_REMOVE(&sc->tx_free_list[pidx], data, next); |
3239 | } | | 3239 | } |
3240 | mutex_exit(&sc->sc_tx_mtx); | | 3240 | mutex_exit(&sc->sc_tx_mtx); |
3241 | | | 3241 | |
3242 | return data; | | 3242 | return data; |
3243 | } | | 3243 | } |
3244 | | | 3244 | |
3245 | static void | | 3245 | static void |
3246 | urtwn_start(struct ifnet *ifp) | | 3246 | urtwn_start(struct ifnet *ifp) |
3247 | { | | 3247 | { |
3248 | struct ieee80211vap *vap = ifp->if_softc; | | 3248 | struct ieee80211vap *vap = ifp->if_softc; |
3249 | struct ieee80211com *ic = vap->iv_ic; | | 3249 | struct ieee80211com *ic = vap->iv_ic; |
3250 | struct urtwn_softc *sc = ic->ic_softc; | | 3250 | struct urtwn_softc *sc = ic->ic_softc; |
3251 | struct urtwn_tx_data *data; | | 3251 | struct urtwn_tx_data *data; |
3252 | struct ether_header *eh; | | 3252 | struct ether_header *eh; |
3253 | struct ieee80211_node *ni; | | 3253 | struct ieee80211_node *ni; |
3254 | struct mbuf *m; | | 3254 | struct mbuf *m; |
3255 | | | 3255 | |
3256 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3256 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3257 | | | 3257 | |
3258 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | | 3258 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) |
3259 | return; | | 3259 | return; |
3260 | | | 3260 | |
3261 | data = NULL; | | 3261 | data = NULL; |
3262 | for (;;) { | | 3262 | for (;;) { |
3263 | /* Send pending management frames first. */ | | 3263 | /* Send pending management frames first. */ |
3264 | IF_POLL(&ic->ic_mgtq, m); | | 3264 | IF_POLL(&ic->ic_mgtq, m); |
3265 | if (m != NULL) { | | 3265 | if (m != NULL) { |
3266 | /* Use AC_VO for management frames. */ | | 3266 | /* Use AC_VO for management frames. */ |
3267 | | | 3267 | |
3268 | data = urtwn_get_tx_data(sc, sc->ac2idx[WME_AC_VO]); | | 3268 | data = urtwn_get_tx_data(sc, sc->ac2idx[WME_AC_VO]); |
3269 | | | 3269 | |
3270 | if (data == NULL) { | | 3270 | if (data == NULL) { |
3271 | ifp->if_flags |= IFF_OACTIVE; | | 3271 | ifp->if_flags |= IFF_OACTIVE; |
3272 | DPRINTFN(DBG_TX, ("%s: empty tx_free_list\n", | | 3272 | DPRINTFN(DBG_TX, ("%s: empty tx_free_list\n", |
3273 | device_xname(sc->sc_dev))); | | 3273 | device_xname(sc->sc_dev))); |
3274 | return; | | 3274 | return; |
3275 | } | | 3275 | } |
3276 | IF_DEQUEUE(&ic->ic_mgtq, m); | | 3276 | IF_DEQUEUE(&ic->ic_mgtq, m); |
3277 | ni = M_GETCTX(m, struct ieee80211_node *); | | 3277 | ni = M_GETCTX(m, struct ieee80211_node *); |
3278 | M_CLEARCTX(m); | | 3278 | M_CLEARCTX(m); |
3279 | goto sendit; | | 3279 | goto sendit; |
3280 | } | | 3280 | } |
3281 | | | 3281 | |
3282 | if (vap->iv_state != IEEE80211_S_RUN) | | 3282 | if (vap->iv_state != IEEE80211_S_RUN) |
3283 | break; | | 3283 | break; |
3284 | | | 3284 | |
3285 | /* Encapsulate and send data frames. */ | | 3285 | /* Encapsulate and send data frames. */ |
3286 | IFQ_POLL(&sc->sc_sendq, m); | | 3286 | IFQ_POLL(&sc->sc_sendq, m); |
3287 | if (m == NULL) | | 3287 | if (m == NULL) |
3288 | break; | | 3288 | break; |
3289 | | | 3289 | |
3290 | struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); | | 3290 | struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); |
3291 | uint8_t type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | | 3291 | uint8_t type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
3292 | uint8_t qid = WME_AC_BE; | | 3292 | uint8_t qid = WME_AC_BE; |
3293 | if (IEEE80211_QOS_HAS_SEQ(wh)) { | | 3293 | if (IEEE80211_QOS_HAS_SEQ(wh)) { |
3294 | /* data frames in 11n mode */ | | 3294 | /* data frames in 11n mode */ |
3295 | struct ieee80211_qosframe *qwh = (void *)wh; | | 3295 | struct ieee80211_qosframe *qwh = (void *)wh; |
3296 | uint8_t tid = qwh->i_qos[0] & IEEE80211_QOS_TID; | | 3296 | uint8_t tid = qwh->i_qos[0] & IEEE80211_QOS_TID; |
3297 | qid = TID_TO_WME_AC(tid); | | 3297 | qid = TID_TO_WME_AC(tid); |
3298 | } else if (type != IEEE80211_FC0_TYPE_DATA) { | | 3298 | } else if (type != IEEE80211_FC0_TYPE_DATA) { |
3299 | qid = WME_AC_VO; | | 3299 | qid = WME_AC_VO; |
3300 | } | | 3300 | } |
3301 | data = urtwn_get_tx_data(sc, sc->ac2idx[qid]); | | 3301 | data = urtwn_get_tx_data(sc, sc->ac2idx[qid]); |
3302 | | | 3302 | |
3303 | if (data == NULL) { | | 3303 | if (data == NULL) { |
3304 | ifp->if_flags |= IFF_OACTIVE; | | 3304 | ifp->if_flags |= IFF_OACTIVE; |
3305 | DPRINTFN(DBG_TX, ("%s: empty tx_free_list\n", | | 3305 | DPRINTFN(DBG_TX, ("%s: empty tx_free_list\n", |
3306 | device_xname(sc->sc_dev))); | | 3306 | device_xname(sc->sc_dev))); |
3307 | return; | | 3307 | return; |
3308 | } | | 3308 | } |
3309 | IFQ_DEQUEUE(&sc->sc_sendq, m); | | 3309 | IFQ_DEQUEUE(&sc->sc_sendq, m); |
3310 | | | 3310 | |
3311 | if (m->m_len < (int)sizeof(*eh) && | | 3311 | if (m->m_len < (int)sizeof(*eh) && |
3312 | (m = m_pullup(m, sizeof(*eh))) == NULL) { | | 3312 | (m = m_pullup(m, sizeof(*eh))) == NULL) { |
3313 | printf("ERROR6\n"); | | 3313 | printf("ERROR6\n"); |
3314 | if_statinc(ifp, if_oerrors); | | 3314 | if_statinc(ifp, if_oerrors); |
3315 | continue; | | 3315 | continue; |
3316 | } | | 3316 | } |
3317 | eh = mtod(m, struct ether_header *); | | 3317 | eh = mtod(m, struct ether_header *); |
3318 | ni = ieee80211_find_txnode(vap, eh->ether_dhost); | | 3318 | ni = ieee80211_find_txnode(vap, eh->ether_dhost); |
3319 | if (ni == NULL) { | | 3319 | if (ni == NULL) { |
3320 | m_freem(m); | | 3320 | m_freem(m); |
3321 | printf("ERROR5\n"); | | 3321 | printf("ERROR5\n"); |
3322 | if_statinc(ifp, if_oerrors); | | 3322 | if_statinc(ifp, if_oerrors); |
3323 | continue; | | 3323 | continue; |
3324 | } | | 3324 | } |
3325 | | | 3325 | |
3326 | //bpf_mtap(ifp, m, BPF_D_OUT); | | 3326 | //bpf_mtap(ifp, m, BPF_D_OUT); |
3327 | | | 3327 | |
3328 | sendit: | | 3328 | sendit: |
3329 | if (urtwn_tx(sc, m, ni, data) != 0) { | | 3329 | if (urtwn_tx(sc, m, ni, data) != 0) { |
3330 | m_freem(m); | | 3330 | m_freem(m); |
3331 | ieee80211_free_node(ni); | | 3331 | ieee80211_free_node(ni); |
3332 | printf("ERROR3\n"); | | 3332 | printf("ERROR3\n"); |
3333 | if_statinc(ifp, if_oerrors); | | 3333 | if_statinc(ifp, if_oerrors); |
3334 | continue; | | 3334 | continue; |
3335 | } | | 3335 | } |
3336 | m_freem(m); | | 3336 | m_freem(m); |
3337 | ieee80211_free_node(ni); | | 3337 | ieee80211_free_node(ni); |
3338 | sc->tx_timer = 5; | | 3338 | sc->tx_timer = 5; |
3339 | ifp->if_timer = 1; | | 3339 | ifp->if_timer = 1; |
3340 | } | | 3340 | } |
3341 | } | | 3341 | } |
3342 | | | 3342 | |
3343 | static __unused void | | 3343 | static __unused void |
3344 | urtwn_watchdog(struct ifnet *ifp) | | 3344 | urtwn_watchdog(struct ifnet *ifp) |
3345 | { | | 3345 | { |
3346 | struct ieee80211vap *vap = ifp->if_softc; | | 3346 | struct ieee80211vap *vap = ifp->if_softc; |
3347 | struct urtwn_softc *sc = vap->iv_ic->ic_softc; | | 3347 | struct urtwn_softc *sc = vap->iv_ic->ic_softc; |
3348 | | | 3348 | |
3349 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3349 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3350 | | | 3350 | |
3351 | ifp->if_timer = 0; | | 3351 | ifp->if_timer = 0; |
3352 | | | 3352 | |
3353 | if (sc->tx_timer > 0) { | | 3353 | if (sc->tx_timer > 0) { |
3354 | if (--sc->tx_timer == 0) { | | 3354 | if (--sc->tx_timer == 0) { |
3355 | aprint_error_dev(sc->sc_dev, "device timeout\n"); | | 3355 | aprint_error_dev(sc->sc_dev, "device timeout\n"); |
3356 | /* urtwn_init(ifp); XXX needs a process context! */ | | 3356 | /* urtwn_init(ifp); XXX needs a process context! */ |
3357 | printf("ERROR2\n"); | | 3357 | printf("ERROR2\n"); |
3358 | if_statinc(ifp, if_oerrors); | | 3358 | if_statinc(ifp, if_oerrors); |
3359 | return; | | 3359 | return; |
3360 | } | | 3360 | } |
3361 | ifp->if_timer = 1; | | 3361 | ifp->if_timer = 1; |
3362 | } | | 3362 | } |
3363 | // ieee80211_watchdog(&sc->sc_ic); | | 3363 | // ieee80211_watchdog(&sc->sc_ic); |
3364 | } | | 3364 | } |
3365 | | | 3365 | |
3366 | /* | | 3366 | /* |
3367 | * Create a VAP node for use with the urtwn driver. | | 3367 | * Create a VAP node for use with the urtwn driver. |
3368 | */ | | 3368 | */ |
3369 | | | 3369 | |
3370 | static struct ieee80211vap * | | 3370 | static struct ieee80211vap * |
3371 | urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], | | 3371 | urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], |
3372 | int unit, enum ieee80211_opmode opmode, int flags, | | 3372 | int unit, enum ieee80211_opmode opmode, int flags, |
3373 | const uint8_t bssid[IEEE80211_ADDR_LEN], | | 3373 | const uint8_t bssid[IEEE80211_ADDR_LEN], |
3374 | const uint8_t macaddr[IEEE80211_ADDR_LEN]) | | 3374 | const uint8_t macaddr[IEEE80211_ADDR_LEN]) |
3375 | { | | 3375 | { |
3376 | struct urtwn_softc *sc = ic->ic_softc; | | 3376 | struct urtwn_softc *sc = ic->ic_softc; |
3377 | struct ifnet *ifp; | | 3377 | struct ifnet *ifp; |
3378 | struct ieee80211vap *vap; | | 3378 | struct ieee80211vap *vap; |
3379 | | | 3379 | |
3380 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3380 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3381 | | | 3381 | |
3382 | /* Allow only one VAP for the urtwn driver. */ | | 3382 | /* Allow only one VAP for the urtwn driver. */ |
3383 | if (!TAILQ_EMPTY(&ic->ic_vaps)) | | 3383 | if (!TAILQ_EMPTY(&ic->ic_vaps)) |
3384 | return NULL; | | 3384 | return NULL; |
3385 | | | 3385 | |
3386 | /* Allocate the vap and setup. */ | | 3386 | /* Allocate the vap and setup. */ |
3387 | vap = kmem_zalloc(sizeof(struct ieee80211vap), KM_SLEEP); | | 3387 | vap = kmem_zalloc(sizeof(struct ieee80211vap), KM_SLEEP); |
3388 | if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | | 3388 | if (ieee80211_vap_setup(ic, vap, name, unit, opmode, |
3389 | flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { | | 3389 | flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { |
3390 | kmem_free(vap, sizeof(struct ieee80211vap)); | | 3390 | kmem_free(vap, sizeof(struct ieee80211vap)); |
3391 | return NULL; | | 3391 | return NULL; |
3392 | } | | 3392 | } |
3393 | | | 3393 | |
3394 | /* Local setup */ | | 3394 | /* Local setup */ |
3395 | vap->iv_reset = urtwn_reset; | | 3395 | vap->iv_reset = urtwn_reset; |
3396 | | | 3396 | |
3397 | ifp = vap->iv_ifp; | | 3397 | ifp = vap->iv_ifp; |
3398 | if_initialize(ifp); | | 3398 | if_initialize(ifp); |
3399 | ifp->if_init = urtwn_init; | | 3399 | ifp->if_init = urtwn_init; |
3400 | ifp->if_ioctl = urtwn_ioctl; | | 3400 | ifp->if_ioctl = urtwn_ioctl; |
3401 | ifp->if_start = urtwn_start; | | 3401 | ifp->if_start = urtwn_start; |
3402 | // ifp->if_watchdog = urtwn_watchdog; NNN | | 3402 | // ifp->if_watchdog = urtwn_watchdog; NNN |
3403 | ifp->if_extflags |= IFEF_MPSAFE; | | 3403 | ifp->if_extflags |= IFEF_MPSAFE; |
3404 | // IFQ_SET_READY(&ifp->if_snd); | | 3404 | // IFQ_SET_READY(&ifp->if_snd); |
3405 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | | 3405 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); |
3406 | | | 3406 | |
3407 | ifp->if_percpuq = if_percpuq_create(ifp); | | 3407 | ifp->if_percpuq = if_percpuq_create(ifp); |
3408 | | | 3408 | |
3409 | /* Override state transition machine. */ | | 3409 | /* Override state transition machine. */ |
3410 | /* NNN --- many possible newstate machines ... issue! */ | | 3410 | /* NNN --- many possible newstate machines ... issue! */ |
3411 | sc->sc_newstate = vap->iv_newstate; | | 3411 | sc->sc_newstate = vap->iv_newstate; |
3412 | vap->iv_newstate = urtwn_newstate; | | 3412 | vap->iv_newstate = urtwn_newstate; |
3413 | | | 3413 | |
3414 | /* Finish setup */ | | 3414 | /* Finish setup */ |
3415 | ieee80211_vap_attach(vap, urtwn_media_change, | | 3415 | ieee80211_vap_attach(vap, urtwn_media_change, |
3416 | ieee80211_media_status, macaddr); | | 3416 | ieee80211_media_status, macaddr); |
3417 | ic->ic_opmode = opmode; | | 3417 | ic->ic_opmode = opmode; |
3418 | | | 3418 | |
3419 | /* Attach the packet filter */ | | 3419 | /* Attach the packet filter */ |
3420 | bpf_attach2(vap->iv_ifp, DLT_IEEE802_11_RADIO, | | 3420 | bpf_attach2(vap->iv_ifp, DLT_IEEE802_11_RADIO, |
3421 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, | | 3421 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, |
3422 | &sc->sc_drvbpf); | | 3422 | &sc->sc_drvbpf); |
3423 | | | 3423 | |
3424 | return vap; | | 3424 | return vap; |
3425 | } | | 3425 | } |
3426 | | | 3426 | |
3427 | static void | | 3427 | static void |
3428 | urtwn_vap_delete(struct ieee80211vap *vap) | | 3428 | urtwn_vap_delete(struct ieee80211vap *vap) |
3429 | { | | 3429 | { |
3430 | struct ifnet *ifp = vap->iv_ifp; | | 3430 | struct ifnet *ifp = vap->iv_ifp; |
3431 | struct urtwn_softc *sc __unused =vap->iv_ic->ic_softc; | | 3431 | struct urtwn_softc *sc __unused =vap->iv_ic->ic_softc; |
3432 | | | 3432 | |
3433 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3433 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3434 | | | 3434 | |
3435 | urtwn_stop(ifp, 0); | | 3435 | urtwn_stop(ifp, 0); |
3436 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | | 3436 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
3437 | bpf_detach(ifp); | | 3437 | bpf_detach(ifp); |
3438 | if_detach(ifp); | | 3438 | if_detach(ifp); |
3439 | kmem_free(vap, sizeof(struct ieee80211vap)); | | 3439 | kmem_free(vap, sizeof(struct ieee80211vap)); |
3440 | } | | 3440 | } |
3441 | | | 3441 | |
3442 | static void | | 3442 | static void |
3443 | urtwn_parent(struct ieee80211com *ic) | | 3443 | urtwn_parent(struct ieee80211com *ic) |
3444 | { | | 3444 | { |
3445 | struct urtwn_softc *sc __unused = ic->ic_softc; | | 3445 | struct urtwn_softc *sc __unused = ic->ic_softc; |
3446 | | | 3446 | |
3447 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3447 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3448 | | | 3448 | |
3449 | /* Not sure what to do here yet. */ | | 3449 | /* Not sure what to do here yet. */ |
3450 | } | | 3450 | } |
3451 | | | 3451 | |
3452 | static void | | 3452 | static void |
3453 | urtwn_scan_start(struct ieee80211com *ic) | | 3453 | urtwn_scan_start(struct ieee80211com *ic) |
3454 | { | | 3454 | { |
3455 | //struct urtwn_softc *sc = ic->ic_softc; | | 3455 | #ifdef URTWN_DEBUG |
| | | 3456 | struct urtwn_softc *sc = ic->ic_softc; |
| | | 3457 | #endif |
3456 | //uint32_t reg; | | 3458 | //uint32_t reg; |
3457 | //int s; | | 3459 | //int s; |
3458 | | | 3460 | |
3459 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3461 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3460 | | | 3462 | |
3461 | /* | | 3463 | /* |
3462 | * Not sure what to do here yet. Try #1: do what was in the | | 3464 | * Not sure what to do here yet. Try #1: do what was in the |
3463 | * state machine. NNN | | 3465 | * state machine. NNN |
3464 | */ | | 3466 | */ |
3465 | #if NOTWITHSTATEMACHINEOVERRIDE | | 3467 | #if NOTWITHSTATEMACHINEOVERRIDE |
3466 | /* | | 3468 | /* |
3467 | * Begin of scanning | | 3469 | * Begin of scanning |
3468 | */ | | 3470 | */ |
3469 | | | 3471 | |
3470 | s = splnet(); | | 3472 | s = splnet(); |
3471 | mutex_enter(&sc->sc_write_mtx); | | 3473 | mutex_enter(&sc->sc_write_mtx); |
3472 | | | 3474 | |
3473 | /* Set gain for scanning. */ | | 3475 | /* Set gain for scanning. */ |
3474 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); | | 3476 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); |
3475 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20); | | 3477 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20); |
3476 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); | | 3478 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); |
3477 | | | 3479 | |
3478 | if (!ISSET(sc->chip, URTWN_CHIP_88E)) { | | 3480 | if (!ISSET(sc->chip, URTWN_CHIP_88E)) { |
3479 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); | | 3481 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); |
3480 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20); | | 3482 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20); |
3481 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); | | 3483 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); |
3482 | } | | 3484 | } |
3483 | | | 3485 | |
3484 | /* Set media status to 'No Link'. */ | | 3486 | /* Set media status to 'No Link'. */ |
3485 | urtwn_set_nettype0_msr(sc, R92C_CR_NETTYPE_NOLINK); | | 3487 | urtwn_set_nettype0_msr(sc, R92C_CR_NETTYPE_NOLINK); |
3486 | | | 3488 | |
3487 | /* Allow Rx from any BSSID. */ | | 3489 | /* Allow Rx from any BSSID. */ |
3488 | urtwn_write_4(sc, R92C_RCR, | | 3490 | urtwn_write_4(sc, R92C_RCR, |
3489 | urtwn_read_4(sc, R92C_RCR) & | | 3491 | urtwn_read_4(sc, R92C_RCR) & |
3490 | ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN)); | | 3492 | ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN)); |
3491 | | | 3493 | |
3492 | /* Stop Rx of data frames. */ | | 3494 | /* Stop Rx of data frames. */ |
3493 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0); | | 3495 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0); |
3494 | | | 3496 | |
3495 | /* Disable update TSF */ | | 3497 | /* Disable update TSF */ |
3496 | urtwn_write_1(sc, R92C_BCN_CTRL, | | 3498 | urtwn_write_1(sc, R92C_BCN_CTRL, |
3497 | urtwn_read_1(sc, R92C_BCN_CTRL) | | | 3499 | urtwn_read_1(sc, R92C_BCN_CTRL) | |
3498 | R92C_BCN_CTRL_DIS_TSF_UDT0); | | 3500 | R92C_BCN_CTRL_DIS_TSF_UDT0); |
3499 | | | 3501 | |
3500 | /* Make link LED blink during scan. */ | | 3502 | /* Make link LED blink during scan. */ |
3501 | urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); | | 3503 | urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); |
3502 | | | 3504 | |
3503 | /* Pause AC Tx queues. */ | | 3505 | /* Pause AC Tx queues. */ |
3504 | urtwn_write_1(sc, R92C_TXPAUSE, | | 3506 | urtwn_write_1(sc, R92C_TXPAUSE, |
3505 | urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); | | 3507 | urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); |
3506 | | | 3508 | |
3507 | urtwn_set_chan(sc, ic->ic_curchan, | | 3509 | urtwn_set_chan(sc, ic->ic_curchan, |
3508 | IEEE80211_HTINFO_2NDCHAN_NONE); | | 3510 | IEEE80211_HTINFO_2NDCHAN_NONE); |
3509 | | | 3511 | |
3510 | mutex_exit(&sc->sc_write_mtx); | | 3512 | mutex_exit(&sc->sc_write_mtx); |
3511 | splx(s); | | 3513 | splx(s); |
3512 | #endif | | 3514 | #endif |
3513 | } | | 3515 | } |
3514 | | | 3516 | |
3515 | static void | | 3517 | static void |
3516 | urtwn_scan_end(struct ieee80211com *ic) | | 3518 | urtwn_scan_end(struct ieee80211com *ic) |
3517 | { | | 3519 | { |
3518 | //struct urtwn_softc *sc = ic->ic_softc; | | 3520 | #ifdef URTWN_DEBUG |
| | | 3521 | struct urtwn_softc *sc = ic->ic_softc; |
| | | 3522 | #endif |
3519 | | | 3523 | |
3520 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3524 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3521 | | | 3525 | |
3522 | #ifdef NOTWITHSTATEMACHINEOVERRIDE | | 3526 | #ifdef NOTWITHSTATEMACHINEOVERRIDE |
3523 | /* | | 3527 | /* |
3524 | * End of scanning | | 3528 | * End of scanning |
3525 | */ | | 3529 | */ |
3526 | | | 3530 | |
3527 | mutex_enter(&sc->sc_write_mtx); | | 3531 | mutex_enter(&sc->sc_write_mtx); |
3528 | | | 3532 | |
3529 | /* flush 4-AC Queue after site_survey */ | | 3533 | /* flush 4-AC Queue after site_survey */ |
3530 | urtwn_write_1(sc, R92C_TXPAUSE, 0x0); | | 3534 | urtwn_write_1(sc, R92C_TXPAUSE, 0x0); |
3531 | | | 3535 | |
3532 | /* Allow Rx from our BSSID only. */ | | 3536 | /* Allow Rx from our BSSID only. */ |
3533 | urtwn_write_4(sc, R92C_RCR, | | 3537 | urtwn_write_4(sc, R92C_RCR, |
3534 | urtwn_read_4(sc, R92C_RCR) | | | 3538 | urtwn_read_4(sc, R92C_RCR) | |
3535 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); | | 3539 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); |
3536 | | | 3540 | |
3537 | /* Turn link LED off. */ | | 3541 | /* Turn link LED off. */ |
3538 | urtwn_set_led(sc, URTWN_LED_LINK, 0); | | 3542 | urtwn_set_led(sc, URTWN_LED_LINK, 0); |
3539 | | | 3543 | |
3540 | mutex_exit(&sc->sc_write_mtx); | | 3544 | mutex_exit(&sc->sc_write_mtx); |
3541 | #endif | | 3545 | #endif |
3542 | } | | 3546 | } |
3543 | | | 3547 | |
3544 | static void | | 3548 | static void |
3545 | urtwn_set_channel(struct ieee80211com *ic) | | 3549 | urtwn_set_channel(struct ieee80211com *ic) |
3546 | { | | 3550 | { |
3547 | struct urtwn_softc *sc = ic->ic_softc; | | 3551 | struct urtwn_softc *sc = ic->ic_softc; |
3548 | | | 3552 | |
3549 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3553 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3550 | | | 3554 | |
3551 | mutex_enter(&sc->sc_write_mtx); | | 3555 | mutex_enter(&sc->sc_write_mtx); |
3552 | urtwn_set_chan(sc, ic->ic_curchan, IEEE80211_HTINFO_2NDCHAN_NONE); | | 3556 | urtwn_set_chan(sc, ic->ic_curchan, IEEE80211_HTINFO_2NDCHAN_NONE); |
3553 | mutex_exit(&sc->sc_write_mtx); | | 3557 | mutex_exit(&sc->sc_write_mtx); |
3554 | } | | 3558 | } |
3555 | | | 3559 | |
3556 | static int | | 3560 | static int |
3557 | urtwn_transmit(struct ieee80211com *ic, struct mbuf *m) | | 3561 | urtwn_transmit(struct ieee80211com *ic, struct mbuf *m) |
3558 | { | | 3562 | { |
3559 | struct urtwn_softc *sc = ic->ic_softc; | | 3563 | struct urtwn_softc *sc = ic->ic_softc; |
3560 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | | 3564 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); |
3561 | int s; | | 3565 | int s; |
3562 | size_t pktlen = m->m_pkthdr.len; | | 3566 | size_t pktlen = m->m_pkthdr.len; |
3563 | bool mcast = (m->m_flags & M_MCAST) != 0; | | 3567 | bool mcast = (m->m_flags & M_MCAST) != 0; |
3564 | | | 3568 | |
3565 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3569 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3566 | | | 3570 | |
3567 | s = splnet(); | | 3571 | s = splnet(); |
3568 | | | 3572 | |
3569 | IF_ENQUEUE(&sc->sc_sendq, m); | | 3573 | IF_ENQUEUE(&sc->sc_sendq, m); |
3570 | | | 3574 | |
3571 | if_statadd(vap->iv_ifp, if_obytes, pktlen); | | 3575 | if_statadd(vap->iv_ifp, if_obytes, pktlen); |
3572 | if (mcast) | | 3576 | if (mcast) |
3573 | if_statinc(vap->iv_ifp, if_omcasts); | | 3577 | if_statinc(vap->iv_ifp, if_omcasts); |
3574 | | | 3578 | |
3575 | if ((vap->iv_ifp->if_flags & IFF_OACTIVE) == 0) | | 3579 | if ((vap->iv_ifp->if_flags & IFF_OACTIVE) == 0) |
3576 | if_start_lock(vap->iv_ifp); | | 3580 | if_start_lock(vap->iv_ifp); |
3577 | splx(s); | | 3581 | splx(s); |
3578 | | | 3582 | |
3579 | urtwn_start(vap->iv_ifp); | | 3583 | urtwn_start(vap->iv_ifp); |
3580 | | | 3584 | |
3581 | return 0; | | 3585 | return 0; |
3582 | } | | 3586 | } |
3583 | | | 3587 | |
3584 | #if 0 | | 3588 | #if 0 |
3585 | static int | | 3589 | static int |
3586 | urtwn_send_mgmt(struct ieee80211_node *ni, int arg1, int arg2) { | | 3590 | urtwn_send_mgmt(struct ieee80211_node *ni, int arg1, int arg2) { |
3587 | #ifdef URTWN_DEBUG | | 3591 | #ifdef URTWN_DEBUG |
3588 | // struct ieee80211vap *vap = ni->ni_vap; | | 3592 | // struct ieee80211vap *vap = ni->ni_vap; |
3589 | struct ieee80211com *ic = ni->ni_ic; | | 3593 | struct ieee80211com *ic = ni->ni_ic; |
3590 | struct urtwn_softc *sc = ic->ic_softc; | | 3594 | struct urtwn_softc *sc = ic->ic_softc; |
3591 | #endif | | 3595 | #endif |
3592 | | | 3596 | |
3593 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3597 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3594 | | | 3598 | |
3595 | /* Don't know what to do right now. */ | | 3599 | /* Don't know what to do right now. */ |
3596 | return ENOTTY; | | 3600 | return ENOTTY; |
3597 | } | | 3601 | } |
3598 | #endif | | 3602 | #endif |
3599 | | | 3603 | |
3600 | | | 3604 | |
3601 | static int | | 3605 | static int |
3602 | urtwn_raw_xmit(struct ieee80211_node *ni , struct mbuf *m, | | 3606 | urtwn_raw_xmit(struct ieee80211_node *ni , struct mbuf *m, |
3603 | const struct ieee80211_bpf_params *bpfp) | | 3607 | const struct ieee80211_bpf_params *bpfp) |
3604 | { | | 3608 | { |
3605 | struct ieee80211vap *vap = ni->ni_vap; | | 3609 | struct ieee80211vap *vap = ni->ni_vap; |
3606 | struct ieee80211com *ic = ni->ni_ic; | | 3610 | struct ieee80211com *ic = ni->ni_ic; |
3607 | struct urtwn_softc *sc = ic->ic_softc; | | 3611 | struct urtwn_softc *sc = ic->ic_softc; |
3608 | struct urtwn_tx_data *data; | | 3612 | struct urtwn_tx_data *data; |
3609 | int error; | | 3613 | int error; |
3610 | | | 3614 | |
3611 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); | | 3615 | DPRINTFN(DBG_FN, ("%s: %s\n",device_xname(sc->sc_dev), __func__)); |
3612 | | | 3616 | |
3613 | KASSERT(vap != NULL); /* NNN need these? */ | | 3617 | KASSERT(vap != NULL); /* NNN need these? */ |
3614 | KASSERT(ic != NULL); | | 3618 | KASSERT(ic != NULL); |
3615 | KASSERT(sc != NULL); | | 3619 | KASSERT(sc != NULL); |
3616 | KASSERT(m != NULL); | | 3620 | KASSERT(m != NULL); |
3617 | | | 3621 | |
3618 | data = urtwn_get_tx_data(sc, sc->ac2idx[WME_AC_VO]); | | 3622 | data = urtwn_get_tx_data(sc, sc->ac2idx[WME_AC_VO]); |
3619 | | | 3623 | |
3620 | if (data == NULL) { | | 3624 | if (data == NULL) { |
3621 | vap->iv_ifp->if_flags |= IFF_OACTIVE; | | 3625 | vap->iv_ifp->if_flags |= IFF_OACTIVE; |
3622 | DPRINTFN(DBG_TX, ("%s: empty tx_free_list\n", | | 3626 | DPRINTFN(DBG_TX, ("%s: empty tx_free_list\n", |
3623 | device_xname(sc->sc_dev))); | | 3627 | device_xname(sc->sc_dev))); |
3624 | return ENOBUFS; | | 3628 | return ENOBUFS; |
3625 | } | | 3629 | } |
3626 | | | 3630 | |
3627 | bpf_mtap3(vap->iv_rawbpf, m, BPF_D_OUT); | | 3631 | bpf_mtap3(vap->iv_rawbpf, m, BPF_D_OUT); |
3628 | | | 3632 | |
3629 | error = urtwn_tx(sc, m, ni, data); | | 3633 | error = urtwn_tx(sc, m, ni, data); |
3630 | if (error != 0) { | | 3634 | if (error != 0) { |
3631 | printf("ERROR3\n"); | | 3635 | printf("ERROR3\n"); |
3632 | if_statinc(vap->iv_ifp, if_oerrors); | | 3636 | if_statinc(vap->iv_ifp, if_oerrors); |
3633 | } else { | | 3637 | } else { |
3634 | sc->tx_timer = 5; | | 3638 | sc->tx_timer = 5; |
3635 | vap->iv_ifp->if_timer = 1; | | 3639 | vap->iv_ifp->if_timer = 1; |
3636 | } | | 3640 | } |
3637 | m_freem(m); | | 3641 | m_freem(m); |
3638 | ieee80211_free_node(ni); | | 3642 | ieee80211_free_node(ni); |
3639 | return error; | | 3643 | return error; |
3640 | } | | 3644 | } |
3641 | | | 3645 | |
3642 | static void | | 3646 | static void |
3643 | urtwn_getradiocaps(struct ieee80211com *ic, | | 3647 | urtwn_getradiocaps(struct ieee80211com *ic, |
3644 | int maxchans, int *nchans, struct ieee80211_channel chans[]) | | 3648 | int maxchans, int *nchans, struct ieee80211_channel chans[]) |
3645 | { | | 3649 | { |
3646 | uint8_t bands[IEEE80211_MODE_BYTES]; | | 3650 | uint8_t bands[IEEE80211_MODE_BYTES]; |
3647 | | | 3651 | |
3648 | /* | | 3652 | /* |
3649 | * NNN Should be able to do something based on chip if | | 3653 | * NNN Should be able to do something based on chip if |
3650 | * a chip has more bands .... eg. N ... but for the future. | | 3654 | * a chip has more bands .... eg. N ... but for the future. |
3651 | */ | | 3655 | */ |
3652 | | | 3656 | |
3653 | memset(bands, 0, sizeof(bands)); | | 3657 | memset(bands, 0, sizeof(bands)); |
3654 | setbit(bands, IEEE80211_MODE_11B); | | 3658 | setbit(bands, IEEE80211_MODE_11B); |
3655 | setbit(bands, IEEE80211_MODE_11G); | | 3659 | setbit(bands, IEEE80211_MODE_11G); |
3656 | ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, | | 3660 | ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, |
3657 | urtwn_chan_2ghz, nitems(urtwn_chan_2ghz), bands, 0); | | 3661 | urtwn_chan_2ghz, nitems(urtwn_chan_2ghz), bands, 0); |
3658 | } | | 3662 | } |
3659 | | | 3663 | |
3660 | | | 3664 | |
3661 | static int | | 3665 | static int |
3662 | urtwn_ioctl(struct ifnet *ifp, u_long cmd, void *data) | | 3666 | urtwn_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
3663 | { | | 3667 | { |
3664 | | | 3668 | |
3665 | struct ieee80211vap *vap = ifp->if_softc; | | 3669 | struct ieee80211vap *vap = ifp->if_softc; |
3666 | struct ieee80211com *ic = vap->iv_ic; | | 3670 | struct ieee80211com *ic = vap->iv_ic; |
3667 | struct urtwn_softc *sc __unused = vap->iv_ic->ic_softc; | | 3671 | struct urtwn_softc *sc __unused = vap->iv_ic->ic_softc; |
3668 | int s, error = 0; | | 3672 | int s, error = 0; |
3669 | | | 3673 | |
3670 | DPRINTFN(DBG_FN, ("%s: %s: cmd=0x%08lx, data=%p\n", | | 3674 | DPRINTFN(DBG_FN, ("%s: %s: cmd=0x%08lx, data=%p\n", |
3671 | device_xname(sc->sc_dev), __func__, cmd, data)); | | 3675 | device_xname(sc->sc_dev), __func__, cmd, data)); |
3672 | | | 3676 | |
3673 | s = splnet(); | | 3677 | s = splnet(); |
3674 | | | 3678 | |
3675 | switch (cmd) { | | 3679 | switch (cmd) { |
3676 | case SIOCSIFFLAGS: | | 3680 | case SIOCSIFFLAGS: |
3677 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | | 3681 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
3678 | break; | | 3682 | break; |
3679 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { | | 3683 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { |
3680 | case IFF_UP | IFF_RUNNING: | | 3684 | case IFF_UP | IFF_RUNNING: |
3681 | break; | | 3685 | break; |
3682 | case IFF_UP: | | 3686 | case IFF_UP: |
3683 | urtwn_init(ifp); | | 3687 | urtwn_init(ifp); |
3684 | break; | | 3688 | break; |
3685 | case IFF_RUNNING: | | 3689 | case IFF_RUNNING: |
3686 | urtwn_stop(ifp, 1); | | 3690 | urtwn_stop(ifp, 1); |
3687 | break; | | 3691 | break; |
3688 | case 0: | | 3692 | case 0: |
3689 | break; | | 3693 | break; |
3690 | } | | 3694 | } |
3691 | break; | | 3695 | break; |
3692 | | | 3696 | |
3693 | case SIOCADDMULTI: | | 3697 | case SIOCADDMULTI: |
3694 | case SIOCDELMULTI: | | 3698 | case SIOCDELMULTI: |
3695 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | | 3699 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { |
3696 | /* setup multicast filter, etc */ | | 3700 | /* setup multicast filter, etc */ |
3697 | error = 0; | | 3701 | error = 0; |
3698 | } | | 3702 | } |
3699 | break; | | 3703 | break; |
3700 | | | 3704 | |
3701 | case SIOCS80211CHANNEL: | | 3705 | case SIOCS80211CHANNEL: |
3702 | /* | | 3706 | /* |
3703 | * This allows for fast channel switching in monitor mode | | 3707 | * This allows for fast channel switching in monitor mode |
3704 | * (used by kismet). In IBSS mode, we must explicitly reset | | 3708 | * (used by kismet). In IBSS mode, we must explicitly reset |
3705 | * the interface to generate a new beacon frame. | | 3709 | * the interface to generate a new beacon frame. |
3706 | */ | | 3710 | */ |
3707 | error = ieee80211_ioctl(ifp, cmd, data); | | 3711 | error = ieee80211_ioctl(ifp, cmd, data); |
3708 | if (error == ENETRESET && | | 3712 | if (error == ENETRESET && |
3709 | ic->ic_opmode == IEEE80211_M_MONITOR) { | | 3713 | ic->ic_opmode == IEEE80211_M_MONITOR) { |
3710 | urtwn_set_chan(sc, ic->ic_curchan, | | 3714 | urtwn_set_chan(sc, ic->ic_curchan, |
3711 | IEEE80211_HTINFO_2NDCHAN_NONE); | | 3715 | IEEE80211_HTINFO_2NDCHAN_NONE); |
3712 | error = 0; | | 3716 | error = 0; |
3713 | } | | 3717 | } |
3714 | break; | | 3718 | break; |
3715 | | | 3719 | |
3716 | default: | | 3720 | default: |
3717 | error = ieee80211_ioctl(ifp, cmd, data); | | 3721 | error = ieee80211_ioctl(ifp, cmd, data); |
3718 | break; | | 3722 | break; |
3719 | } | | 3723 | } |
3720 | if (error == ENETRESET) { | | 3724 | if (error == ENETRESET) { |
3721 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | | 3725 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == |
3722 | (IFF_UP | IFF_RUNNING) /* && NNN need a vap for next line | | 3726 | (IFF_UP | IFF_RUNNING) /* && NNN need a vap for next line |
3723 | ic->ic_roaming != IEEE80211_ROAMING_MANUAL*/) { | | 3727 | ic->ic_roaming != IEEE80211_ROAMING_MANUAL*/) { |
3724 | urtwn_init(ifp); | | 3728 | urtwn_init(ifp); |
3725 | } | | 3729 | } |
3726 | error = 0; | | 3730 | error = 0; |
3727 | } | | 3731 | } |
3728 | | | 3732 | |
3729 | splx(s); | | 3733 | splx(s); |
3730 | | | 3734 | |
3731 | return error; | | 3735 | return error; |
3732 | } | | 3736 | } |
3733 | | | 3737 | |
3734 | static __inline int | | 3738 | static __inline int |
3735 | urtwn_power_on(struct urtwn_softc *sc) | | 3739 | urtwn_power_on(struct urtwn_softc *sc) |
3736 | { | | 3740 | { |
3737 | | | 3741 | |
3738 | return sc->sc_power_on(sc); | | 3742 | return sc->sc_power_on(sc); |
3739 | } | | 3743 | } |
3740 | | | 3744 | |
3741 | static int | | 3745 | static int |
3742 | urtwn_r92c_power_on(struct urtwn_softc *sc) | | 3746 | urtwn_r92c_power_on(struct urtwn_softc *sc) |
3743 | { | | 3747 | { |
3744 | uint32_t reg; | | 3748 | uint32_t reg; |
3745 | int ntries; | | 3749 | int ntries; |
3746 | | | 3750 | |
3747 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3751 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3748 | | | 3752 | |
3749 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 3753 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
3750 | | | 3754 | |
3751 | /* Wait for autoload done bit. */ | | 3755 | /* Wait for autoload done bit. */ |
3752 | for (ntries = 0; ntries < 1000; ntries++) { | | 3756 | for (ntries = 0; ntries < 1000; ntries++) { |
3753 | if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) | | 3757 | if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) |
3754 | break; | | 3758 | break; |
3755 | DELAY(5); | | 3759 | DELAY(5); |
3756 | } | | 3760 | } |
3757 | if (ntries == 1000) { | | 3761 | if (ntries == 1000) { |
3758 | aprint_error_dev(sc->sc_dev, | | 3762 | aprint_error_dev(sc->sc_dev, |
3759 | "timeout waiting for chip autoload\n"); | | 3763 | "timeout waiting for chip autoload\n"); |
3760 | return ETIMEDOUT; | | 3764 | return ETIMEDOUT; |
3761 | } | | 3765 | } |
3762 | | | 3766 | |
3763 | /* Unlock ISO/CLK/Power control register. */ | | 3767 | /* Unlock ISO/CLK/Power control register. */ |
3764 | urtwn_write_1(sc, R92C_RSV_CTRL, 0); | | 3768 | urtwn_write_1(sc, R92C_RSV_CTRL, 0); |
3765 | /* Move SPS into PWM mode. */ | | 3769 | /* Move SPS into PWM mode. */ |
3766 | urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); | | 3770 | urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); |
3767 | DELAY(5); | | 3771 | DELAY(5); |
3768 | | | 3772 | |
3769 | reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL); | | 3773 | reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL); |
3770 | if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { | | 3774 | if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { |
3771 | urtwn_write_1(sc, R92C_LDOV12D_CTRL, | | 3775 | urtwn_write_1(sc, R92C_LDOV12D_CTRL, |
3772 | reg | R92C_LDOV12D_CTRL_LDV12_EN); | | 3776 | reg | R92C_LDOV12D_CTRL_LDV12_EN); |
3773 | DELAY(100); | | 3777 | DELAY(100); |
3774 | urtwn_write_1(sc, R92C_SYS_ISO_CTRL, | | 3778 | urtwn_write_1(sc, R92C_SYS_ISO_CTRL, |
3775 | urtwn_read_1(sc, R92C_SYS_ISO_CTRL) & | | 3779 | urtwn_read_1(sc, R92C_SYS_ISO_CTRL) & |
3776 | ~R92C_SYS_ISO_CTRL_MD2PP); | | 3780 | ~R92C_SYS_ISO_CTRL_MD2PP); |
3777 | } | | 3781 | } |
3778 | | | 3782 | |
3779 | /* Auto enable WLAN. */ | | 3783 | /* Auto enable WLAN. */ |
3780 | urtwn_write_2(sc, R92C_APS_FSMCO, | | 3784 | urtwn_write_2(sc, R92C_APS_FSMCO, |
3781 | urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); | | 3785 | urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); |
3782 | for (ntries = 0; ntries < 1000; ntries++) { | | 3786 | for (ntries = 0; ntries < 1000; ntries++) { |
3783 | if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & | | 3787 | if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & |
3784 | R92C_APS_FSMCO_APFM_ONMAC)) | | 3788 | R92C_APS_FSMCO_APFM_ONMAC)) |
3785 | break; | | 3789 | break; |
3786 | DELAY(100); | | 3790 | DELAY(100); |
3787 | } | | 3791 | } |
3788 | if (ntries == 1000) { | | 3792 | if (ntries == 1000) { |
3789 | aprint_error_dev(sc->sc_dev, | | 3793 | aprint_error_dev(sc->sc_dev, |
3790 | "timeout waiting for MAC auto ON\n"); | | 3794 | "timeout waiting for MAC auto ON\n"); |
3791 | return ETIMEDOUT; | | 3795 | return ETIMEDOUT; |
3792 | } | | 3796 | } |
3793 | | | 3797 | |
3794 | /* Enable radio, GPIO and LED functions. */ | | 3798 | /* Enable radio, GPIO and LED functions. */ |
3795 | KASSERT((R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_PDN_EN | | | 3799 | KASSERT((R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_PDN_EN | |
3796 | R92C_APS_FSMCO_PFM_ALDN) == 0x0812); | | 3800 | R92C_APS_FSMCO_PFM_ALDN) == 0x0812); |
3797 | urtwn_write_2(sc, R92C_APS_FSMCO, | | 3801 | urtwn_write_2(sc, R92C_APS_FSMCO, |
3798 | R92C_APS_FSMCO_AFSM_HSUS | | | 3802 | R92C_APS_FSMCO_AFSM_HSUS | |
3799 | R92C_APS_FSMCO_PDN_EN | | | 3803 | R92C_APS_FSMCO_PDN_EN | |
3800 | R92C_APS_FSMCO_PFM_ALDN); | | 3804 | R92C_APS_FSMCO_PFM_ALDN); |
3801 | | | 3805 | |
3802 | /* Release RF digital isolation. */ | | 3806 | /* Release RF digital isolation. */ |
3803 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL, | | 3807 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL, |
3804 | urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); | | 3808 | urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); |
3805 | | | 3809 | |
3806 | /* Initialize MAC. */ | | 3810 | /* Initialize MAC. */ |
3807 | urtwn_write_1(sc, R92C_APSD_CTRL, | | 3811 | urtwn_write_1(sc, R92C_APSD_CTRL, |
3808 | urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); | | 3812 | urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); |
3809 | for (ntries = 0; ntries < 200; ntries++) { | | 3813 | for (ntries = 0; ntries < 200; ntries++) { |
3810 | if (!(urtwn_read_1(sc, R92C_APSD_CTRL) & | | 3814 | if (!(urtwn_read_1(sc, R92C_APSD_CTRL) & |
3811 | R92C_APSD_CTRL_OFF_STATUS)) | | 3815 | R92C_APSD_CTRL_OFF_STATUS)) |
3812 | break; | | 3816 | break; |
3813 | DELAY(5); | | 3817 | DELAY(5); |
3814 | } | | 3818 | } |
3815 | if (ntries == 200) { | | 3819 | if (ntries == 200) { |
3816 | aprint_error_dev(sc->sc_dev, | | 3820 | aprint_error_dev(sc->sc_dev, |
3817 | "timeout waiting for MAC initialization\n"); | | 3821 | "timeout waiting for MAC initialization\n"); |
3818 | return ETIMEDOUT; | | 3822 | return ETIMEDOUT; |
3819 | } | | 3823 | } |
3820 | | | 3824 | |
3821 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ | | 3825 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ |
3822 | reg = urtwn_read_2(sc, R92C_CR); | | 3826 | reg = urtwn_read_2(sc, R92C_CR); |
3823 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | | | 3827 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | |
3824 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | | | 3828 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | |
3825 | R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | | | 3829 | R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | |
3826 | R92C_CR_ENSEC; | | 3830 | R92C_CR_ENSEC; |
3827 | urtwn_write_2(sc, R92C_CR, reg); | | 3831 | urtwn_write_2(sc, R92C_CR, reg); |
3828 | | | 3832 | |
3829 | urtwn_write_1(sc, 0xfe10, 0x19); | | 3833 | urtwn_write_1(sc, 0xfe10, 0x19); |
3830 | return 0; | | 3834 | return 0; |
3831 | } | | 3835 | } |
3832 | | | 3836 | |
3833 | static int | | 3837 | static int |
3834 | urtwn_r92e_power_on(struct urtwn_softc *sc) | | 3838 | urtwn_r92e_power_on(struct urtwn_softc *sc) |
3835 | { | | 3839 | { |
3836 | uint32_t reg; | | 3840 | uint32_t reg; |
3837 | uint32_t val; | | 3841 | uint32_t val; |
3838 | int ntries; | | 3842 | int ntries; |
3839 | | | 3843 | |
3840 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3844 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3841 | | | 3845 | |
3842 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 3846 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
3843 | | | 3847 | |
3844 | /* Enable radio, GPIO and LED functions. */ | | 3848 | /* Enable radio, GPIO and LED functions. */ |
3845 | KASSERT((R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_PDN_EN | | | 3849 | KASSERT((R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_PDN_EN | |
3846 | R92C_APS_FSMCO_PFM_ALDN) == 0x0812); | | 3850 | R92C_APS_FSMCO_PFM_ALDN) == 0x0812); |
3847 | urtwn_write_2(sc, R92C_APS_FSMCO, | | 3851 | urtwn_write_2(sc, R92C_APS_FSMCO, |
3848 | R92C_APS_FSMCO_AFSM_HSUS | | | 3852 | R92C_APS_FSMCO_AFSM_HSUS | |
3849 | R92C_APS_FSMCO_PDN_EN | | | 3853 | R92C_APS_FSMCO_PDN_EN | |
3850 | R92C_APS_FSMCO_PFM_ALDN); | | 3854 | R92C_APS_FSMCO_PFM_ALDN); |
3851 | | | 3855 | |
3852 | if (urtwn_read_4(sc, R92E_SYS_CFG1_8192E) & R92E_SPSLDO_SEL){ | | 3856 | if (urtwn_read_4(sc, R92E_SYS_CFG1_8192E) & R92E_SPSLDO_SEL){ |
3853 | /* LDO. */ | | 3857 | /* LDO. */ |
3854 | urtwn_write_1(sc, R92E_LDO_SWR_CTRL, 0xc3); | | 3858 | urtwn_write_1(sc, R92E_LDO_SWR_CTRL, 0xc3); |
3855 | } | | 3859 | } |
3856 | else { | | 3860 | else { |
3857 | urtwn_write_2(sc, R92C_SYS_SWR_CTRL2, urtwn_read_2(sc, | | 3861 | urtwn_write_2(sc, R92C_SYS_SWR_CTRL2, urtwn_read_2(sc, |
3858 | R92C_SYS_SWR_CTRL2) & 0xffff); | | 3862 | R92C_SYS_SWR_CTRL2) & 0xffff); |
3859 | urtwn_write_1(sc, R92E_LDO_SWR_CTRL, 0x83); | | 3863 | urtwn_write_1(sc, R92E_LDO_SWR_CTRL, 0x83); |
3860 | } | | 3864 | } |
3861 | | | 3865 | |
3862 | for (ntries = 0; ntries < 2; ntries++) { | | 3866 | for (ntries = 0; ntries < 2; ntries++) { |
3863 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL, | | 3867 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL, |
3864 | urtwn_read_1(sc, R92C_AFE_PLL_CTRL)); | | 3868 | urtwn_read_1(sc, R92C_AFE_PLL_CTRL)); |
3865 | urtwn_write_2(sc, R92C_AFE_CTRL4, urtwn_read_2(sc, | | 3869 | urtwn_write_2(sc, R92C_AFE_CTRL4, urtwn_read_2(sc, |
3866 | R92C_AFE_CTRL4)); | | 3870 | R92C_AFE_CTRL4)); |
3867 | } | | 3871 | } |
3868 | | | 3872 | |
3869 | /* Reset BB. */ | | 3873 | /* Reset BB. */ |
3870 | urtwn_write_1(sc, R92C_SYS_FUNC_EN, | | 3874 | urtwn_write_1(sc, R92C_SYS_FUNC_EN, |
3871 | urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | | | 3875 | urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | |
3872 | R92C_SYS_FUNC_EN_BB_GLB_RST)); | | 3876 | R92C_SYS_FUNC_EN_BB_GLB_RST)); |
3873 | | | 3877 | |
3874 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2, urtwn_read_1(sc, | | 3878 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2, urtwn_read_1(sc, |
3875 | R92C_AFE_XTAL_CTRL + 2) | 0x80); | | 3879 | R92C_AFE_XTAL_CTRL + 2) | 0x80); |
3876 | | | 3880 | |
3877 | /* Disable HWPDN. */ | | 3881 | /* Disable HWPDN. */ |
3878 | urtwn_write_2(sc, R92C_APS_FSMCO, urtwn_read_2(sc, | | 3882 | urtwn_write_2(sc, R92C_APS_FSMCO, urtwn_read_2(sc, |
3879 | R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); | | 3883 | R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); |
3880 | | | 3884 | |
3881 | /* Disable WL suspend. */ | | 3885 | /* Disable WL suspend. */ |
3882 | urtwn_write_2(sc, R92C_APS_FSMCO, urtwn_read_2(sc, | | 3886 | urtwn_write_2(sc, R92C_APS_FSMCO, urtwn_read_2(sc, |
3883 | R92C_APS_FSMCO) & ~(R92C_APS_FSMCO_AFSM_PCIE | | | 3887 | R92C_APS_FSMCO) & ~(R92C_APS_FSMCO_AFSM_PCIE | |
3884 | R92C_APS_FSMCO_AFSM_HSUS)); | | 3888 | R92C_APS_FSMCO_AFSM_HSUS)); |
3885 | | | 3889 | |
3886 | urtwn_write_4(sc, R92C_APS_FSMCO, urtwn_read_4(sc, | | 3890 | urtwn_write_4(sc, R92C_APS_FSMCO, urtwn_read_4(sc, |
3887 | R92C_APS_FSMCO) | R92C_APS_FSMCO_RDY_MACON); | | 3891 | R92C_APS_FSMCO) | R92C_APS_FSMCO_RDY_MACON); |
3888 | urtwn_write_2(sc, R92C_APS_FSMCO, urtwn_read_2(sc, | | 3892 | urtwn_write_2(sc, R92C_APS_FSMCO, urtwn_read_2(sc, |
3889 | R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); | | 3893 | R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); |
3890 | for (ntries = 0; ntries < 10000; ntries++) { | | 3894 | for (ntries = 0; ntries < 10000; ntries++) { |
3891 | val = urtwn_read_2(sc, R92C_APS_FSMCO) & | | 3895 | val = urtwn_read_2(sc, R92C_APS_FSMCO) & |
3892 | R92C_APS_FSMCO_APFM_ONMAC; | | 3896 | R92C_APS_FSMCO_APFM_ONMAC; |
3893 | if (val == 0x0) | | 3897 | if (val == 0x0) |
3894 | break; | | 3898 | break; |
3895 | DELAY(10); | | 3899 | DELAY(10); |
3896 | } | | 3900 | } |
3897 | if (ntries == 10000) { | | 3901 | if (ntries == 10000) { |
3898 | aprint_error_dev(sc->sc_dev, | | 3902 | aprint_error_dev(sc->sc_dev, |
3899 | "timeout waiting for chip power up\n"); | | 3903 | "timeout waiting for chip power up\n"); |
3900 | return ETIMEDOUT; | | 3904 | return ETIMEDOUT; |
3901 | } | | 3905 | } |
3902 | | | 3906 | |
3903 | urtwn_write_2(sc, R92C_CR, 0x00); | | 3907 | urtwn_write_2(sc, R92C_CR, 0x00); |
3904 | reg = urtwn_read_2(sc, R92C_CR); | | 3908 | reg = urtwn_read_2(sc, R92C_CR); |
3905 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | | | 3909 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | |
3906 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | | | 3910 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | |
3907 | R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC; | | 3911 | R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC; |
3908 | urtwn_write_2(sc, R92C_CR, reg); | | 3912 | urtwn_write_2(sc, R92C_CR, reg); |
3909 | | | 3913 | |
3910 | return 0; | | 3914 | return 0; |
3911 | } | | 3915 | } |
3912 | | | 3916 | |
3913 | static int | | 3917 | static int |
3914 | urtwn_r88e_power_on(struct urtwn_softc *sc) | | 3918 | urtwn_r88e_power_on(struct urtwn_softc *sc) |
3915 | { | | 3919 | { |
3916 | uint32_t reg; | | 3920 | uint32_t reg; |
3917 | uint8_t val; | | 3921 | uint8_t val; |
3918 | int ntries; | | 3922 | int ntries; |
3919 | | | 3923 | |
3920 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3924 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3921 | | | 3925 | |
3922 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 3926 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
3923 | | | 3927 | |
3924 | /* Wait for power ready bit. */ | | 3928 | /* Wait for power ready bit. */ |
3925 | for (ntries = 0; ntries < 5000; ntries++) { | | 3929 | for (ntries = 0; ntries < 5000; ntries++) { |
3926 | val = urtwn_read_1(sc, 0x6) & 0x2; | | 3930 | val = urtwn_read_1(sc, 0x6) & 0x2; |
3927 | if (val == 0x2) | | 3931 | if (val == 0x2) |
3928 | break; | | 3932 | break; |
3929 | DELAY(10); | | 3933 | DELAY(10); |
3930 | } | | 3934 | } |
3931 | if (ntries == 5000) { | | 3935 | if (ntries == 5000) { |
3932 | aprint_error_dev(sc->sc_dev, | | 3936 | aprint_error_dev(sc->sc_dev, |
3933 | "timeout waiting for chip power up\n"); | | 3937 | "timeout waiting for chip power up\n"); |
3934 | return ETIMEDOUT; | | 3938 | return ETIMEDOUT; |
3935 | } | | 3939 | } |
3936 | | | 3940 | |
3937 | /* Reset BB. */ | | 3941 | /* Reset BB. */ |
3938 | urtwn_write_1(sc, R92C_SYS_FUNC_EN, | | 3942 | urtwn_write_1(sc, R92C_SYS_FUNC_EN, |
3939 | urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | | | 3943 | urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | |
3940 | R92C_SYS_FUNC_EN_BB_GLB_RST)); | | 3944 | R92C_SYS_FUNC_EN_BB_GLB_RST)); |
3941 | | | 3945 | |
3942 | urtwn_write_1(sc, 0x26, urtwn_read_1(sc, 0x26) | 0x80); | | 3946 | urtwn_write_1(sc, 0x26, urtwn_read_1(sc, 0x26) | 0x80); |
3943 | | | 3947 | |
3944 | /* Disable HWPDN. */ | | 3948 | /* Disable HWPDN. */ |
3945 | urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) & ~0x80); | | 3949 | urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) & ~0x80); |
3946 | | | 3950 | |
3947 | /* Disable WL suspend. */ | | 3951 | /* Disable WL suspend. */ |
3948 | urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) & ~0x18); | | 3952 | urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) & ~0x18); |
3949 | | | 3953 | |
3950 | urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) | 0x1); | | 3954 | urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) | 0x1); |
3951 | for (ntries = 0; ntries < 5000; ntries++) { | | 3955 | for (ntries = 0; ntries < 5000; ntries++) { |
3952 | if (!(urtwn_read_1(sc, 0x5) & 0x1)) | | 3956 | if (!(urtwn_read_1(sc, 0x5) & 0x1)) |
3953 | break; | | 3957 | break; |
3954 | DELAY(10); | | 3958 | DELAY(10); |
3955 | } | | 3959 | } |
3956 | if (ntries == 5000) | | 3960 | if (ntries == 5000) |
3957 | return ETIMEDOUT; | | 3961 | return ETIMEDOUT; |
3958 | | | 3962 | |
3959 | /* Enable LDO normal mode. */ | | 3963 | /* Enable LDO normal mode. */ |
3960 | urtwn_write_1(sc, 0x23, urtwn_read_1(sc, 0x23) & ~0x10); | | 3964 | urtwn_write_1(sc, 0x23, urtwn_read_1(sc, 0x23) & ~0x10); |
3961 | | | 3965 | |
3962 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ | | 3966 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ |
3963 | urtwn_write_2(sc, R92C_CR, 0); | | 3967 | urtwn_write_2(sc, R92C_CR, 0); |
3964 | reg = urtwn_read_2(sc, R92C_CR); | | 3968 | reg = urtwn_read_2(sc, R92C_CR); |
3965 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | | | 3969 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | |
3966 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | | | 3970 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | |
3967 | R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN; | | 3971 | R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN; |
3968 | urtwn_write_2(sc, R92C_CR, reg); | | 3972 | urtwn_write_2(sc, R92C_CR, reg); |
3969 | | | 3973 | |
3970 | return 0; | | 3974 | return 0; |
3971 | } | | 3975 | } |
3972 | | | 3976 | |
3973 | static int | | 3977 | static int |
3974 | urtwn_llt_init(struct urtwn_softc *sc) | | 3978 | urtwn_llt_init(struct urtwn_softc *sc) |
3975 | { | | 3979 | { |
3976 | size_t i, page_count, pktbuf_count; | | 3980 | size_t i, page_count, pktbuf_count; |
3977 | uint32_t val; | | 3981 | uint32_t val; |
3978 | int error; | | 3982 | int error; |
3979 | | | 3983 | |
3980 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 3984 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
3981 | | | 3985 | |
3982 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 3986 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
3983 | | | 3987 | |
3984 | if (sc->chip & URTWN_CHIP_88E) | | 3988 | if (sc->chip & URTWN_CHIP_88E) |
3985 | page_count = R88E_TX_PAGE_COUNT; | | 3989 | page_count = R88E_TX_PAGE_COUNT; |
3986 | else if (sc->chip & URTWN_CHIP_92EU) | | 3990 | else if (sc->chip & URTWN_CHIP_92EU) |
3987 | page_count = R92E_TX_PAGE_COUNT; | | 3991 | page_count = R92E_TX_PAGE_COUNT; |
3988 | else | | 3992 | else |
3989 | page_count = R92C_TX_PAGE_COUNT; | | 3993 | page_count = R92C_TX_PAGE_COUNT; |
3990 | if (sc->chip & URTWN_CHIP_88E) | | 3994 | if (sc->chip & URTWN_CHIP_88E) |
3991 | pktbuf_count = R88E_TXPKTBUF_COUNT; | | 3995 | pktbuf_count = R88E_TXPKTBUF_COUNT; |
3992 | else if (sc->chip & URTWN_CHIP_92EU) | | 3996 | else if (sc->chip & URTWN_CHIP_92EU) |
3993 | pktbuf_count = R88E_TXPKTBUF_COUNT; | | 3997 | pktbuf_count = R88E_TXPKTBUF_COUNT; |
3994 | else | | 3998 | else |
3995 | pktbuf_count = R92C_TXPKTBUF_COUNT; | | 3999 | pktbuf_count = R92C_TXPKTBUF_COUNT; |
3996 | | | 4000 | |
3997 | if (sc->chip & URTWN_CHIP_92EU) { | | 4001 | if (sc->chip & URTWN_CHIP_92EU) { |
3998 | val = urtwn_read_4(sc, R92E_AUTO_LLT) | R92E_AUTO_LLT_EN; | | 4002 | val = urtwn_read_4(sc, R92E_AUTO_LLT) | R92E_AUTO_LLT_EN; |
3999 | urtwn_write_4(sc, R92E_AUTO_LLT, val); | | 4003 | urtwn_write_4(sc, R92E_AUTO_LLT, val); |
4000 | DELAY(100); | | 4004 | DELAY(100); |
4001 | val = urtwn_read_4(sc, R92E_AUTO_LLT); | | 4005 | val = urtwn_read_4(sc, R92E_AUTO_LLT); |
4002 | if (val & R92E_AUTO_LLT_EN) | | 4006 | if (val & R92E_AUTO_LLT_EN) |
4003 | return EIO; | | 4007 | return EIO; |
4004 | return 0; | | 4008 | return 0; |
4005 | } | | 4009 | } |
4006 | | | 4010 | |
4007 | /* Reserve pages [0; page_count]. */ | | 4011 | /* Reserve pages [0; page_count]. */ |
4008 | for (i = 0; i < page_count; i++) { | | 4012 | for (i = 0; i < page_count; i++) { |
4009 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) | | 4013 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) |
4010 | return error; | | 4014 | return error; |
4011 | } | | 4015 | } |
4012 | /* NB: 0xff indicates end-of-list. */ | | 4016 | /* NB: 0xff indicates end-of-list. */ |
4013 | if ((error = urtwn_llt_write(sc, i, 0xff)) != 0) | | 4017 | if ((error = urtwn_llt_write(sc, i, 0xff)) != 0) |
4014 | return error; | | 4018 | return error; |
4015 | /* | | 4019 | /* |
4016 | * Use pages [page_count + 1; pktbuf_count - 1] | | 4020 | * Use pages [page_count + 1; pktbuf_count - 1] |
4017 | * as ring buffer. | | 4021 | * as ring buffer. |
4018 | */ | | 4022 | */ |
4019 | for (++i; i < pktbuf_count - 1; i++) { | | 4023 | for (++i; i < pktbuf_count - 1; i++) { |
4020 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) | | 4024 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) |
4021 | return error; | | 4025 | return error; |
4022 | } | | 4026 | } |
4023 | /* Make the last page point to the beginning of the ring buffer. */ | | 4027 | /* Make the last page point to the beginning of the ring buffer. */ |
4024 | error = urtwn_llt_write(sc, i, pktbuf_count + 1); | | 4028 | error = urtwn_llt_write(sc, i, pktbuf_count + 1); |
4025 | return error; | | 4029 | return error; |
4026 | } | | 4030 | } |
4027 | | | 4031 | |
4028 | static __unused void | | 4032 | static __unused void |
4029 | urtwn_fw_reset(struct urtwn_softc *sc) | | 4033 | urtwn_fw_reset(struct urtwn_softc *sc) |
4030 | { | | 4034 | { |
4031 | uint16_t reg; | | 4035 | uint16_t reg; |
4032 | int ntries; | | 4036 | int ntries; |
4033 | | | 4037 | |
4034 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4038 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4035 | | | 4039 | |
4036 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4040 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4037 | | | 4041 | |
4038 | /* Tell 8051 to reset itself. */ | | 4042 | /* Tell 8051 to reset itself. */ |
4039 | urtwn_write_1(sc, R92C_HMETFR + 3, 0x20); | | 4043 | urtwn_write_1(sc, R92C_HMETFR + 3, 0x20); |
4040 | | | 4044 | |
4041 | /* Wait until 8051 resets by itself. */ | | 4045 | /* Wait until 8051 resets by itself. */ |
4042 | for (ntries = 0; ntries < 100; ntries++) { | | 4046 | for (ntries = 0; ntries < 100; ntries++) { |
4043 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); | | 4047 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); |
4044 | if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) | | 4048 | if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) |
4045 | return; | | 4049 | return; |
4046 | DELAY(50); | | 4050 | DELAY(50); |
4047 | } | | 4051 | } |
4048 | /* Force 8051 reset. */ | | 4052 | /* Force 8051 reset. */ |
4049 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, | | 4053 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, |
4050 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) & ~R92C_SYS_FUNC_EN_CPUEN); | | 4054 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) & ~R92C_SYS_FUNC_EN_CPUEN); |
4051 | } | | 4055 | } |
4052 | | | 4056 | |
4053 | static void | | 4057 | static void |
4054 | urtwn_r88e_fw_reset(struct urtwn_softc *sc) | | 4058 | urtwn_r88e_fw_reset(struct urtwn_softc *sc) |
4055 | { | | 4059 | { |
4056 | uint16_t reg; | | 4060 | uint16_t reg; |
4057 | | | 4061 | |
4058 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4062 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4059 | | | 4063 | |
4060 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4064 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4061 | | | 4065 | |
4062 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 4066 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { |
4063 | reg = urtwn_read_2(sc, R92C_RSV_CTRL) & ~R92E_RSV_MIO_EN; | | 4067 | reg = urtwn_read_2(sc, R92C_RSV_CTRL) & ~R92E_RSV_MIO_EN; |
4064 | urtwn_write_2(sc,R92C_RSV_CTRL, reg); | | 4068 | urtwn_write_2(sc,R92C_RSV_CTRL, reg); |
4065 | } | | 4069 | } |
4066 | DELAY(50); | | 4070 | DELAY(50); |
4067 | | | 4071 | |
4068 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); | | 4072 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); |
4069 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); | | 4073 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); |
4070 | DELAY(50); | | 4074 | DELAY(50); |
4071 | | | 4075 | |
4072 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN); | | 4076 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN); |
4073 | DELAY(50); | | 4077 | DELAY(50); |
4074 | | | 4078 | |
4075 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 4079 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { |
4076 | reg = urtwn_read_2(sc, R92C_RSV_CTRL) | R92E_RSV_MIO_EN; | | 4080 | reg = urtwn_read_2(sc, R92C_RSV_CTRL) | R92E_RSV_MIO_EN; |
4077 | urtwn_write_2(sc,R92C_RSV_CTRL, reg); | | 4081 | urtwn_write_2(sc,R92C_RSV_CTRL, reg); |
4078 | } | | 4082 | } |
4079 | DELAY(50); | | 4083 | DELAY(50); |
4080 | | | 4084 | |
4081 | } | | 4085 | } |
4082 | | | 4086 | |
4083 | static int | | 4087 | static int |
4084 | urtwn_fw_loadpage(struct urtwn_softc *sc, int page, uint8_t *buf, int len) | | 4088 | urtwn_fw_loadpage(struct urtwn_softc *sc, int page, uint8_t *buf, int len) |
4085 | { | | 4089 | { |
4086 | uint32_t reg; | | 4090 | uint32_t reg; |
4087 | int off, mlen, error = 0; | | 4091 | int off, mlen, error = 0; |
4088 | | | 4092 | |
4089 | DPRINTFN(DBG_FN, ("%s: %s: page=%d, buf=%p, len=%d\n", | | 4093 | DPRINTFN(DBG_FN, ("%s: %s: page=%d, buf=%p, len=%d\n", |
4090 | device_xname(sc->sc_dev), __func__, page, buf, len)); | | 4094 | device_xname(sc->sc_dev), __func__, page, buf, len)); |
4091 | | | 4095 | |
4092 | reg = urtwn_read_4(sc, R92C_MCUFWDL); | | 4096 | reg = urtwn_read_4(sc, R92C_MCUFWDL); |
4093 | reg = RW(reg, R92C_MCUFWDL_PAGE, page); | | 4097 | reg = RW(reg, R92C_MCUFWDL_PAGE, page); |
4094 | urtwn_write_4(sc, R92C_MCUFWDL, reg); | | 4098 | urtwn_write_4(sc, R92C_MCUFWDL, reg); |
4095 | | | 4099 | |
4096 | off = R92C_FW_START_ADDR; | | 4100 | off = R92C_FW_START_ADDR; |
4097 | while (len > 0) { | | 4101 | while (len > 0) { |
4098 | if (len > 196) | | 4102 | if (len > 196) |
4099 | mlen = 196; | | 4103 | mlen = 196; |
4100 | else if (len > 4) | | 4104 | else if (len > 4) |
4101 | mlen = 4; | | 4105 | mlen = 4; |
4102 | else | | 4106 | else |
4103 | mlen = 1; | | 4107 | mlen = 1; |
4104 | error = urtwn_write_region(sc, off, buf, mlen); | | 4108 | error = urtwn_write_region(sc, off, buf, mlen); |
4105 | if (error != 0) | | 4109 | if (error != 0) |
4106 | break; | | 4110 | break; |
4107 | off += mlen; | | 4111 | off += mlen; |
4108 | buf += mlen; | | 4112 | buf += mlen; |
4109 | len -= mlen; | | 4113 | len -= mlen; |
4110 | } | | 4114 | } |
4111 | return error; | | 4115 | return error; |
4112 | } | | 4116 | } |
4113 | | | 4117 | |
4114 | static int | | 4118 | static int |
4115 | urtwn_load_firmware(struct urtwn_softc *sc) | | 4119 | urtwn_load_firmware(struct urtwn_softc *sc) |
4116 | { | | 4120 | { |
4117 | firmware_handle_t fwh; | | 4121 | firmware_handle_t fwh; |
4118 | const struct r92c_fw_hdr *hdr; | | 4122 | const struct r92c_fw_hdr *hdr; |
4119 | const char *name; | | 4123 | const char *name; |
4120 | u_char *fw, *ptr; | | 4124 | u_char *fw, *ptr; |
4121 | size_t len; | | 4125 | size_t len; |
4122 | uint32_t reg; | | 4126 | uint32_t reg; |
4123 | int mlen, ntries, page, error; | | 4127 | int mlen, ntries, page, error; |
4124 | | | 4128 | |
4125 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4129 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4126 | | | 4130 | |
4127 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4131 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4128 | | | 4132 | |
4129 | /* Read firmware image from the filesystem. */ | | 4133 | /* Read firmware image from the filesystem. */ |
4130 | if (ISSET(sc->chip, URTWN_CHIP_88E)) | | 4134 | if (ISSET(sc->chip, URTWN_CHIP_88E)) |
4131 | name = "rtl8188eufw.bin"; | | 4135 | name = "rtl8188eufw.bin"; |
4132 | else if (ISSET(sc->chip, URTWN_CHIP_92EU)) | | 4136 | else if (ISSET(sc->chip, URTWN_CHIP_92EU)) |
4133 | name = "rtl8192eefw.bin"; | | 4137 | name = "rtl8192eefw.bin"; |
4134 | else if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == | | 4138 | else if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == |
4135 | URTWN_CHIP_UMC_A_CUT) | | 4139 | URTWN_CHIP_UMC_A_CUT) |
4136 | name = "rtl8192cfwU.bin"; | | 4140 | name = "rtl8192cfwU.bin"; |
4137 | else | | 4141 | else |
4138 | name = "rtl8192cfw.bin"; | | 4142 | name = "rtl8192cfw.bin"; |
4139 | if ((error = firmware_open("if_urtwn", name, &fwh)) != 0) { | | 4143 | if ((error = firmware_open("if_urtwn", name, &fwh)) != 0) { |
4140 | aprint_error_dev(sc->sc_dev, | | 4144 | aprint_error_dev(sc->sc_dev, |
4141 | "failed load firmware of file %s (error %d)\n", name, | | 4145 | "failed load firmware of file %s (error %d)\n", name, |
4142 | error); | | 4146 | error); |
4143 | return error; | | 4147 | return error; |
4144 | } | | 4148 | } |
4145 | const size_t fwlen = len = firmware_get_size(fwh); | | 4149 | const size_t fwlen = len = firmware_get_size(fwh); |
4146 | fw = firmware_malloc(len); | | 4150 | fw = firmware_malloc(len); |
4147 | if (fw == NULL) { | | 4151 | if (fw == NULL) { |
4148 | aprint_error_dev(sc->sc_dev, | | 4152 | aprint_error_dev(sc->sc_dev, |
4149 | "failed to allocate firmware memory\n"); | | 4153 | "failed to allocate firmware memory\n"); |
4150 | firmware_close(fwh); | | 4154 | firmware_close(fwh); |
4151 | return ENOMEM; | | 4155 | return ENOMEM; |
4152 | } | | 4156 | } |
4153 | error = firmware_read(fwh, 0, fw, len); | | 4157 | error = firmware_read(fwh, 0, fw, len); |
4154 | firmware_close(fwh); | | 4158 | firmware_close(fwh); |
4155 | if (error != 0) { | | 4159 | if (error != 0) { |
4156 | aprint_error_dev(sc->sc_dev, | | 4160 | aprint_error_dev(sc->sc_dev, |
4157 | "failed to read firmware (error %d)\n", error); | | 4161 | "failed to read firmware (error %d)\n", error); |
4158 | firmware_free(fw, fwlen); | | 4162 | firmware_free(fw, fwlen); |
4159 | return error; | | 4163 | return error; |
4160 | } | | 4164 | } |
4161 | | | 4165 | |
4162 | len = fwlen; | | 4166 | len = fwlen; |
4163 | ptr = fw; | | 4167 | ptr = fw; |
4164 | hdr = (const struct r92c_fw_hdr *)ptr; | | 4168 | hdr = (const struct r92c_fw_hdr *)ptr; |
4165 | /* Check if there is a valid FW header and skip it. */ | | 4169 | /* Check if there is a valid FW header and skip it. */ |
4166 | if ((le16toh(hdr->signature) >> 4) == 0x88c || | | 4170 | if ((le16toh(hdr->signature) >> 4) == 0x88c || |
4167 | (le16toh(hdr->signature) >> 4) == 0x88e || | | 4171 | (le16toh(hdr->signature) >> 4) == 0x88e || |
4168 | (le16toh(hdr->signature) >> 4) == 0x92e || | | 4172 | (le16toh(hdr->signature) >> 4) == 0x92e || |
4169 | (le16toh(hdr->signature) >> 4) == 0x92c) { | | 4173 | (le16toh(hdr->signature) >> 4) == 0x92c) { |
4170 | DPRINTFN(DBG_INIT, ("%s: %s: FW V%d.%d %02d-%02d %02d:%02d\n", | | 4174 | DPRINTFN(DBG_INIT, ("%s: %s: FW V%d.%d %02d-%02d %02d:%02d\n", |
4171 | device_xname(sc->sc_dev), __func__, | | 4175 | device_xname(sc->sc_dev), __func__, |
4172 | le16toh(hdr->version), le16toh(hdr->subversion), | | 4176 | le16toh(hdr->version), le16toh(hdr->subversion), |
4173 | hdr->month, hdr->date, hdr->hour, hdr->minute)); | | 4177 | hdr->month, hdr->date, hdr->hour, hdr->minute)); |
4174 | ptr += sizeof(*hdr); | | 4178 | ptr += sizeof(*hdr); |
4175 | len -= sizeof(*hdr); | | 4179 | len -= sizeof(*hdr); |
4176 | } | | 4180 | } |
4177 | | | 4181 | |
4178 | if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { | | 4182 | if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { |
4179 | if (ISSET(sc->chip, URTWN_CHIP_88E) || | | 4183 | if (ISSET(sc->chip, URTWN_CHIP_88E) || |
4180 | ISSET(sc->chip, URTWN_CHIP_92EU)) | | 4184 | ISSET(sc->chip, URTWN_CHIP_92EU)) |
4181 | urtwn_r88e_fw_reset(sc); | | 4185 | urtwn_r88e_fw_reset(sc); |
4182 | else | | 4186 | else |
4183 | urtwn_fw_reset(sc); | | 4187 | urtwn_fw_reset(sc); |
4184 | } | | 4188 | } |
4185 | if (!ISSET(sc->chip, URTWN_CHIP_88E) && | | 4189 | if (!ISSET(sc->chip, URTWN_CHIP_88E) && |
4186 | !ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 4190 | !ISSET(sc->chip, URTWN_CHIP_92EU)) { |
4187 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, | | 4191 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, |
4188 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) | | | 4192 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) | |
4189 | R92C_SYS_FUNC_EN_CPUEN); | | 4193 | R92C_SYS_FUNC_EN_CPUEN); |
4190 | } | | 4194 | } |
4191 | | | 4195 | |
4192 | /* download enabled */ | | 4196 | /* download enabled */ |
4193 | urtwn_write_1(sc, R92C_MCUFWDL, | | 4197 | urtwn_write_1(sc, R92C_MCUFWDL, |
4194 | urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); | | 4198 | urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); |
4195 | urtwn_write_1(sc, R92C_MCUFWDL + 2, | | 4199 | urtwn_write_1(sc, R92C_MCUFWDL + 2, |
4196 | urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); | | 4200 | urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); |
4197 | | | 4201 | |
4198 | /* Reset the FWDL checksum. */ | | 4202 | /* Reset the FWDL checksum. */ |
4199 | urtwn_write_1(sc, R92C_MCUFWDL, | | 4203 | urtwn_write_1(sc, R92C_MCUFWDL, |
4200 | urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); | | 4204 | urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); |
4201 | | | 4205 | |
4202 | DELAY(50); | | 4206 | DELAY(50); |
4203 | /* download firmware */ | | 4207 | /* download firmware */ |
4204 | for (page = 0; len > 0; page++) { | | 4208 | for (page = 0; len > 0; page++) { |
4205 | mlen = MIN(len, R92C_FW_PAGE_SIZE); | | 4209 | mlen = MIN(len, R92C_FW_PAGE_SIZE); |
4206 | error = urtwn_fw_loadpage(sc, page, ptr, mlen); | | 4210 | error = urtwn_fw_loadpage(sc, page, ptr, mlen); |
4207 | if (error != 0) { | | 4211 | if (error != 0) { |
4208 | aprint_error_dev(sc->sc_dev, | | 4212 | aprint_error_dev(sc->sc_dev, |
4209 | "could not load firmware page %d\n", page); | | 4213 | "could not load firmware page %d\n", page); |
4210 | goto fail; | | 4214 | goto fail; |
4211 | } | | 4215 | } |
4212 | ptr += mlen; | | 4216 | ptr += mlen; |
4213 | len -= mlen; | | 4217 | len -= mlen; |
4214 | } | | 4218 | } |
4215 | | | 4219 | |
4216 | /* download disable */ | | 4220 | /* download disable */ |
4217 | urtwn_write_1(sc, R92C_MCUFWDL, | | 4221 | urtwn_write_1(sc, R92C_MCUFWDL, |
4218 | urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); | | 4222 | urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); |
4219 | urtwn_write_1(sc, R92C_MCUFWDL + 1, 0); | | 4223 | urtwn_write_1(sc, R92C_MCUFWDL + 1, 0); |
4220 | | | 4224 | |
4221 | /* Wait for checksum report. */ | | 4225 | /* Wait for checksum report. */ |
4222 | for (ntries = 0; ntries < 1000; ntries++) { | | 4226 | for (ntries = 0; ntries < 1000; ntries++) { |
4223 | if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) | | 4227 | if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) |
4224 | break; | | 4228 | break; |
4225 | DELAY(5); | | 4229 | DELAY(5); |
4226 | } | | 4230 | } |
4227 | if (ntries == 1000) { | | 4231 | if (ntries == 1000) { |
4228 | aprint_error_dev(sc->sc_dev, | | 4232 | aprint_error_dev(sc->sc_dev, |
4229 | "timeout waiting for checksum report\n"); | | 4233 | "timeout waiting for checksum report\n"); |
4230 | error = ETIMEDOUT; | | 4234 | error = ETIMEDOUT; |
4231 | goto fail; | | 4235 | goto fail; |
4232 | } | | 4236 | } |
4233 | | | 4237 | |
4234 | /* Wait for firmware readiness. */ | | 4238 | /* Wait for firmware readiness. */ |
4235 | reg = urtwn_read_4(sc, R92C_MCUFWDL); | | 4239 | reg = urtwn_read_4(sc, R92C_MCUFWDL); |
4236 | reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; | | 4240 | reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; |
4237 | urtwn_write_4(sc, R92C_MCUFWDL, reg); | | 4241 | urtwn_write_4(sc, R92C_MCUFWDL, reg); |
4238 | if (ISSET(sc->chip, URTWN_CHIP_88E) || | | 4242 | if (ISSET(sc->chip, URTWN_CHIP_88E) || |
4239 | ISSET(sc->chip, URTWN_CHIP_92EU)) | | 4243 | ISSET(sc->chip, URTWN_CHIP_92EU)) |
4240 | urtwn_r88e_fw_reset(sc); | | 4244 | urtwn_r88e_fw_reset(sc); |
4241 | for (ntries = 0; ntries < 6000; ntries++) { | | 4245 | for (ntries = 0; ntries < 6000; ntries++) { |
4242 | if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) | | 4246 | if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) |
4243 | break; | | 4247 | break; |
4244 | DELAY(5); | | 4248 | DELAY(5); |
4245 | } | | 4249 | } |
4246 | if (ntries == 6000) { | | 4250 | if (ntries == 6000) { |
4247 | aprint_error_dev(sc->sc_dev, | | 4251 | aprint_error_dev(sc->sc_dev, |
4248 | "timeout waiting for firmware readiness\n"); | | 4252 | "timeout waiting for firmware readiness\n"); |
4249 | error = ETIMEDOUT; | | 4253 | error = ETIMEDOUT; |
4250 | goto fail; | | 4254 | goto fail; |
4251 | } | | 4255 | } |
4252 | fail: | | 4256 | fail: |
4253 | firmware_free(fw, fwlen); | | 4257 | firmware_free(fw, fwlen); |
4254 | return error; | | 4258 | return error; |
4255 | } | | 4259 | } |
4256 | | | 4260 | |
4257 | static __inline int | | 4261 | static __inline int |
4258 | urtwn_dma_init(struct urtwn_softc *sc) | | 4262 | urtwn_dma_init(struct urtwn_softc *sc) |
4259 | { | | 4263 | { |
4260 | | | 4264 | |
4261 | return sc->sc_dma_init(sc); | | 4265 | return sc->sc_dma_init(sc); |
4262 | } | | 4266 | } |
4263 | | | 4267 | |
4264 | static int | | 4268 | static int |
4265 | urtwn_r92c_dma_init(struct urtwn_softc *sc) | | 4269 | urtwn_r92c_dma_init(struct urtwn_softc *sc) |
4266 | { | | 4270 | { |
4267 | int hashq, hasnq, haslq, nqueues, nqpages, nrempages; | | 4271 | int hashq, hasnq, haslq, nqueues, nqpages, nrempages; |
4268 | uint32_t reg; | | 4272 | uint32_t reg; |
4269 | int error; | | 4273 | int error; |
4270 | | | 4274 | |
4271 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4275 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4272 | | | 4276 | |
4273 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4277 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4274 | | | 4278 | |
4275 | /* Initialize LLT table. */ | | 4279 | /* Initialize LLT table. */ |
4276 | error = urtwn_llt_init(sc); | | 4280 | error = urtwn_llt_init(sc); |
4277 | if (error != 0) | | 4281 | if (error != 0) |
4278 | return error; | | 4282 | return error; |
4279 | | | 4283 | |
4280 | /* Get Tx queues to USB endpoints mapping. */ | | 4284 | /* Get Tx queues to USB endpoints mapping. */ |
4281 | hashq = hasnq = haslq = 0; | | 4285 | hashq = hasnq = haslq = 0; |
4282 | reg = urtwn_read_2(sc, R92C_USB_EP + 1); | | 4286 | reg = urtwn_read_2(sc, R92C_USB_EP + 1); |
4283 | DPRINTFN(DBG_INIT, ("%s: %s: USB endpoints mapping %#x\n", | | 4287 | DPRINTFN(DBG_INIT, ("%s: %s: USB endpoints mapping %#x\n", |
4284 | device_xname(sc->sc_dev), __func__, reg)); | | 4288 | device_xname(sc->sc_dev), __func__, reg)); |
4285 | if (MS(reg, R92C_USB_EP_HQ) != 0) | | 4289 | if (MS(reg, R92C_USB_EP_HQ) != 0) |
4286 | hashq = 1; | | 4290 | hashq = 1; |
4287 | if (MS(reg, R92C_USB_EP_NQ) != 0) | | 4291 | if (MS(reg, R92C_USB_EP_NQ) != 0) |
4288 | hasnq = 1; | | 4292 | hasnq = 1; |
4289 | if (MS(reg, R92C_USB_EP_LQ) != 0) | | 4293 | if (MS(reg, R92C_USB_EP_LQ) != 0) |
4290 | haslq = 1; | | 4294 | haslq = 1; |
4291 | nqueues = hashq + hasnq + haslq; | | 4295 | nqueues = hashq + hasnq + haslq; |
4292 | if (nqueues == 0) | | 4296 | if (nqueues == 0) |
4293 | return EIO; | | 4297 | return EIO; |
4294 | /* Get the number of pages for each queue. */ | | 4298 | /* Get the number of pages for each queue. */ |
4295 | nqpages = (R92C_TX_PAGE_COUNT - R92C_PUBQ_NPAGES) / nqueues; | | 4299 | nqpages = (R92C_TX_PAGE_COUNT - R92C_PUBQ_NPAGES) / nqueues; |
4296 | /* The remaining pages are assigned to the high priority queue. */ | | 4300 | /* The remaining pages are assigned to the high priority queue. */ |
4297 | nrempages = (R92C_TX_PAGE_COUNT - R92C_PUBQ_NPAGES) % nqueues; | | 4301 | nrempages = (R92C_TX_PAGE_COUNT - R92C_PUBQ_NPAGES) % nqueues; |
4298 | | | 4302 | |
4299 | /* Set number of pages for normal priority queue. */ | | 4303 | /* Set number of pages for normal priority queue. */ |
4300 | urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0); | | 4304 | urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0); |
4301 | urtwn_write_4(sc, R92C_RQPN, | | 4305 | urtwn_write_4(sc, R92C_RQPN, |
4302 | /* Set number of pages for public queue. */ | | 4306 | /* Set number of pages for public queue. */ |
4303 | SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) | | | 4307 | SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) | |
4304 | /* Set number of pages for high priority queue. */ | | 4308 | /* Set number of pages for high priority queue. */ |
4305 | SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) | | | 4309 | SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) | |
4306 | /* Set number of pages for low priority queue. */ | | 4310 | /* Set number of pages for low priority queue. */ |
4307 | SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) | | | 4311 | SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) | |
4308 | /* Load values. */ | | 4312 | /* Load values. */ |
4309 | R92C_RQPN_LD); | | 4313 | R92C_RQPN_LD); |
4310 | | | 4314 | |
4311 | urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY); | | 4315 | urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY); |
4312 | urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY); | | 4316 | urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY); |
4313 | urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY); | | 4317 | urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY); |
4314 | urtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY); | | 4318 | urtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY); |
4315 | urtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY); | | 4319 | urtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY); |
4316 | | | 4320 | |
4317 | /* Set queue to USB pipe mapping. */ | | 4321 | /* Set queue to USB pipe mapping. */ |
4318 | reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); | | 4322 | reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); |
4319 | reg &= ~R92C_TRXDMA_CTRL_QMAP_M; | | 4323 | reg &= ~R92C_TRXDMA_CTRL_QMAP_M; |
4320 | if (nqueues == 1) { | | 4324 | if (nqueues == 1) { |
4321 | if (hashq) { | | 4325 | if (hashq) { |
4322 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ; | | 4326 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ; |
4323 | } else if (hasnq) { | | 4327 | } else if (hasnq) { |
4324 | reg |= R92C_TRXDMA_CTRL_QMAP_NQ; | | 4328 | reg |= R92C_TRXDMA_CTRL_QMAP_NQ; |
4325 | } else { | | 4329 | } else { |
4326 | reg |= R92C_TRXDMA_CTRL_QMAP_LQ; | | 4330 | reg |= R92C_TRXDMA_CTRL_QMAP_LQ; |
4327 | } | | 4331 | } |
4328 | } else if (nqueues == 2) { | | 4332 | } else if (nqueues == 2) { |
4329 | /* All 2-endpoints configs have a high priority queue. */ | | 4333 | /* All 2-endpoints configs have a high priority queue. */ |
4330 | if (!hashq) { | | 4334 | if (!hashq) { |
4331 | return EIO; | | 4335 | return EIO; |
4332 | } | | 4336 | } |
4333 | if (hasnq) { | | 4337 | if (hasnq) { |
4334 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; | | 4338 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; |
4335 | } else { | | 4339 | } else { |
4336 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_LQ; | | 4340 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_LQ; |
4337 | } | | 4341 | } |
4338 | } else { | | 4342 | } else { |
4339 | reg |= R92C_TRXDMA_CTRL_QMAP_3EP; | | 4343 | reg |= R92C_TRXDMA_CTRL_QMAP_3EP; |
4340 | } | | 4344 | } |
4341 | urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); | | 4345 | urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); |
4342 | | | 4346 | |
4343 | /* Set Tx/Rx transfer page boundary. */ | | 4347 | /* Set Tx/Rx transfer page boundary. */ |
4344 | urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff); | | 4348 | urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff); |
4345 | | | 4349 | |
4346 | /* Set Tx/Rx transfer page size. */ | | 4350 | /* Set Tx/Rx transfer page size. */ |
4347 | urtwn_write_1(sc, R92C_PBP, | | 4351 | urtwn_write_1(sc, R92C_PBP, |
4348 | SM(R92C_PBP_PSRX, R92C_PBP_128) | SM(R92C_PBP_PSTX, R92C_PBP_128)); | | 4352 | SM(R92C_PBP_PSRX, R92C_PBP_128) | SM(R92C_PBP_PSTX, R92C_PBP_128)); |
4349 | return 0; | | 4353 | return 0; |
4350 | } | | 4354 | } |
4351 | | | 4355 | |
4352 | static int | | 4356 | static int |
4353 | urtwn_r88e_dma_init(struct urtwn_softc *sc) | | 4357 | urtwn_r88e_dma_init(struct urtwn_softc *sc) |
4354 | { | | 4358 | { |
4355 | usb_interface_descriptor_t *id; | | 4359 | usb_interface_descriptor_t *id; |
4356 | uint32_t reg; | | 4360 | uint32_t reg; |
4357 | int nqueues; | | 4361 | int nqueues; |
4358 | int error; | | 4362 | int error; |
4359 | | | 4363 | |
4360 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4364 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4361 | | | 4365 | |
4362 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4366 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4363 | | | 4367 | |
4364 | /* Initialize LLT table. */ | | 4368 | /* Initialize LLT table. */ |
4365 | error = urtwn_llt_init(sc); | | 4369 | error = urtwn_llt_init(sc); |
4366 | if (error != 0) | | 4370 | if (error != 0) |
4367 | return error; | | 4371 | return error; |
4368 | | | 4372 | |
4369 | /* Get Tx queues to USB endpoints mapping. */ | | 4373 | /* Get Tx queues to USB endpoints mapping. */ |
4370 | id = usbd_get_interface_descriptor(sc->sc_iface); | | 4374 | id = usbd_get_interface_descriptor(sc->sc_iface); |
4371 | nqueues = id->bNumEndpoints - 1; | | 4375 | nqueues = id->bNumEndpoints - 1; |
4372 | if (nqueues == 0) | | 4376 | if (nqueues == 0) |
4373 | return EIO; | | 4377 | return EIO; |
4374 | | | 4378 | |
4375 | /* Set number of pages for normal priority queue. */ | | 4379 | /* Set number of pages for normal priority queue. */ |
4376 | urtwn_write_2(sc, R92C_RQPN_NPQ, 0); | | 4380 | urtwn_write_2(sc, R92C_RQPN_NPQ, 0); |
4377 | urtwn_write_2(sc, R92C_RQPN_NPQ, 0x000d); | | 4381 | urtwn_write_2(sc, R92C_RQPN_NPQ, 0x000d); |
4378 | urtwn_write_4(sc, R92C_RQPN, 0x808e000d); | | 4382 | urtwn_write_4(sc, R92C_RQPN, 0x808e000d); |
4379 | | | 4383 | |
4380 | urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R88E_TX_PAGE_BOUNDARY); | | 4384 | urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R88E_TX_PAGE_BOUNDARY); |
4381 | urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R88E_TX_PAGE_BOUNDARY); | | 4385 | urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R88E_TX_PAGE_BOUNDARY); |
4382 | urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R88E_TX_PAGE_BOUNDARY); | | 4386 | urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R88E_TX_PAGE_BOUNDARY); |
4383 | urtwn_write_1(sc, R92C_TRXFF_BNDY, R88E_TX_PAGE_BOUNDARY); | | 4387 | urtwn_write_1(sc, R92C_TRXFF_BNDY, R88E_TX_PAGE_BOUNDARY); |
4384 | urtwn_write_1(sc, R92C_TDECTRL + 1, R88E_TX_PAGE_BOUNDARY); | | 4388 | urtwn_write_1(sc, R92C_TDECTRL + 1, R88E_TX_PAGE_BOUNDARY); |
4385 | | | 4389 | |
4386 | /* Set queue to USB pipe mapping. */ | | 4390 | /* Set queue to USB pipe mapping. */ |
4387 | reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); | | 4391 | reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); |
4388 | reg &= ~R92C_TRXDMA_CTRL_QMAP_M; | | 4392 | reg &= ~R92C_TRXDMA_CTRL_QMAP_M; |
4389 | if (nqueues == 1) | | 4393 | if (nqueues == 1) |
4390 | reg |= R92C_TRXDMA_CTRL_QMAP_LQ; | | 4394 | reg |= R92C_TRXDMA_CTRL_QMAP_LQ; |
4391 | else if (nqueues == 2) | | 4395 | else if (nqueues == 2) |
4392 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; | | 4396 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; |
4393 | else | | 4397 | else |
4394 | reg |= R92C_TRXDMA_CTRL_QMAP_3EP; | | 4398 | reg |= R92C_TRXDMA_CTRL_QMAP_3EP; |
4395 | urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); | | 4399 | urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); |
4396 | | | 4400 | |
4397 | /* Set Tx/Rx transfer page boundary. */ | | 4401 | /* Set Tx/Rx transfer page boundary. */ |
4398 | urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x23ff); | | 4402 | urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x23ff); |
4399 | | | 4403 | |
4400 | /* Set Tx/Rx transfer page size. */ | | 4404 | /* Set Tx/Rx transfer page size. */ |
4401 | urtwn_write_1(sc, R92C_PBP, | | 4405 | urtwn_write_1(sc, R92C_PBP, |
4402 | SM(R92C_PBP_PSRX, R92C_PBP_128) | SM(R92C_PBP_PSTX, R92C_PBP_128)); | | 4406 | SM(R92C_PBP_PSRX, R92C_PBP_128) | SM(R92C_PBP_PSTX, R92C_PBP_128)); |
4403 | | | 4407 | |
4404 | return 0; | | 4408 | return 0; |
4405 | } | | 4409 | } |
4406 | | | 4410 | |
4407 | static void | | 4411 | static void |
4408 | urtwn_mac_init(struct urtwn_softc *sc) | | 4412 | urtwn_mac_init(struct urtwn_softc *sc) |
4409 | { | | 4413 | { |
4410 | size_t i; | | 4414 | size_t i; |
4411 | | | 4415 | |
4412 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4416 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4413 | | | 4417 | |
4414 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4418 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4415 | | | 4419 | |
4416 | /* Write MAC initialization values. */ | | 4420 | /* Write MAC initialization values. */ |
4417 | if (ISSET(sc->chip, URTWN_CHIP_88E)) { | | 4421 | if (ISSET(sc->chip, URTWN_CHIP_88E)) { |
4418 | for (i = 0; i < __arraycount(rtl8188eu_mac); i++) | | 4422 | for (i = 0; i < __arraycount(rtl8188eu_mac); i++) |
4419 | urtwn_write_1(sc, rtl8188eu_mac[i].reg, | | 4423 | urtwn_write_1(sc, rtl8188eu_mac[i].reg, |
4420 | rtl8188eu_mac[i].val); | | 4424 | rtl8188eu_mac[i].val); |
4421 | } else if (ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 4425 | } else if (ISSET(sc->chip, URTWN_CHIP_92EU)) { |
4422 | for (i = 0; i < __arraycount(rtl8192eu_mac); i++) | | 4426 | for (i = 0; i < __arraycount(rtl8192eu_mac); i++) |
4423 | urtwn_write_1(sc, rtl8192eu_mac[i].reg, | | 4427 | urtwn_write_1(sc, rtl8192eu_mac[i].reg, |
4424 | rtl8192eu_mac[i].val); | | 4428 | rtl8192eu_mac[i].val); |
4425 | } else { | | 4429 | } else { |
4426 | for (i = 0; i < __arraycount(rtl8192cu_mac); i++) | | 4430 | for (i = 0; i < __arraycount(rtl8192cu_mac); i++) |
4427 | urtwn_write_1(sc, rtl8192cu_mac[i].reg, | | 4431 | urtwn_write_1(sc, rtl8192cu_mac[i].reg, |
4428 | rtl8192cu_mac[i].val); | | 4432 | rtl8192cu_mac[i].val); |
4429 | } | | 4433 | } |
4430 | } | | 4434 | } |
4431 | | | 4435 | |
4432 | static void | | 4436 | static void |
4433 | urtwn_bb_init(struct urtwn_softc *sc) | | 4437 | urtwn_bb_init(struct urtwn_softc *sc) |
4434 | { | | 4438 | { |
4435 | const struct rtwn_bb_prog *prog; | | 4439 | const struct rtwn_bb_prog *prog; |
4436 | uint32_t reg; | | 4440 | uint32_t reg; |
4437 | uint8_t crystalcap; | | 4441 | uint8_t crystalcap; |
4438 | size_t i; | | 4442 | size_t i; |
4439 | | | 4443 | |
4440 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 4444 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
4441 | | | 4445 | |
4442 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 4446 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
4443 | | | 4447 | |
4444 | /* Enable BB and RF. */ | | 4448 | /* Enable BB and RF. */ |
4445 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, | | 4449 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, |
4446 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) | | | 4450 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) | |
4447 | R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | | | 4451 | R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | |
4448 | R92C_SYS_FUNC_EN_DIO_RF); | | 4452 | R92C_SYS_FUNC_EN_DIO_RF); |
4449 | | | 4453 | |
4450 | if (!ISSET(sc->chip, URTWN_CHIP_88E) && | | 4454 | if (!ISSET(sc->chip, URTWN_CHIP_88E) && |
4451 | !ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 4455 | !ISSET(sc->chip, URTWN_CHIP_92EU)) { |
4452 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x83); | | 4456 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x83); |
4453 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL + 1, 0xdb); | | 4457 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL + 1, 0xdb); |
4454 | } | | 4458 | } |
4455 | | | 4459 | |
4456 | urtwn_write_1(sc, R92C_RF_CTRL, | | 4460 | urtwn_write_1(sc, R92C_RF_CTRL, |
4457 | R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); | | 4461 | R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); |
4458 | urtwn_write_1(sc, R92C_SYS_FUNC_EN, | | 4462 | urtwn_write_1(sc, R92C_SYS_FUNC_EN, |
4459 | R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | | | 4463 | R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | |
4460 | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); | | 4464 | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); |
4461 | | | 4465 | |
4462 | if (!ISSET(sc->chip, URTWN_CHIP_88E) && | | 4466 | if (!ISSET(sc->chip, URTWN_CHIP_88E) && |
4463 | !ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 4467 | !ISSET(sc->chip, URTWN_CHIP_92EU)) { |
4464 | urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); | | 4468 | urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); |
4465 | urtwn_write_1(sc, 0x15, 0xe9); | | 4469 | urtwn_write_1(sc, 0x15, 0xe9); |
4466 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); | | 4470 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); |
4467 | } | | 4471 | } |
4468 | | | 4472 | |
4469 | /* Select BB programming based on board type. */ | | 4473 | /* Select BB programming based on board type. */ |
4470 | if (ISSET(sc->chip, URTWN_CHIP_88E)) | | 4474 | if (ISSET(sc->chip, URTWN_CHIP_88E)) |
4471 | prog = &rtl8188eu_bb_prog; | | 4475 | prog = &rtl8188eu_bb_prog; |
4472 | else if (ISSET(sc->chip, URTWN_CHIP_92EU)) | | 4476 | else if (ISSET(sc->chip, URTWN_CHIP_92EU)) |
4473 | prog = &rtl8192eu_bb_prog; | | 4477 | prog = &rtl8192eu_bb_prog; |
4474 | else if (!(sc->chip & URTWN_CHIP_92C)) { | | 4478 | else if (!(sc->chip & URTWN_CHIP_92C)) { |
4475 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD) { | | 4479 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD) { |
4476 | prog = &rtl8188ce_bb_prog; | | 4480 | prog = &rtl8188ce_bb_prog; |
4477 | } else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) { | | 4481 | } else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) { |
4478 | prog = &rtl8188ru_bb_prog; | | 4482 | prog = &rtl8188ru_bb_prog; |
4479 | } else { | | 4483 | } else { |
4480 | prog = &rtl8188cu_bb_prog; | | 4484 | prog = &rtl8188cu_bb_prog; |
4481 | } | | 4485 | } |
4482 | } else { | | 4486 | } else { |
4483 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD) { | | 4487 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD) { |
4484 | prog = &rtl8192ce_bb_prog; | | 4488 | prog = &rtl8192ce_bb_prog; |
4485 | } else { | | 4489 | } else { |
4486 | prog = &rtl8192cu_bb_prog; | | 4490 | prog = &rtl8192cu_bb_prog; |
4487 | } | | 4491 | } |
4488 | } | | 4492 | } |
4489 | /* Write BB initialization values. */ | | 4493 | /* Write BB initialization values. */ |
4490 | for (i = 0; i < prog->count; i++) { | | 4494 | for (i = 0; i < prog->count; i++) { |
4491 | /* additional delay depend on registers */ | | 4495 | /* additional delay depend on registers */ |
4492 | switch (prog->regs[i]) { | | 4496 | switch (prog->regs[i]) { |
4493 | case 0xfe: | | 4497 | case 0xfe: |
4494 | urtwn_delay_ms(sc, 50); | | 4498 | urtwn_delay_ms(sc, 50); |
4495 | break; | | 4499 | break; |
4496 | case 0xfd: | | 4500 | case 0xfd: |
4497 | urtwn_delay_ms(sc, 5); | | 4501 | urtwn_delay_ms(sc, 5); |
4498 | break; | | 4502 | break; |
4499 | case 0xfc: | | 4503 | case 0xfc: |
4500 | urtwn_delay_ms(sc, 1); | | 4504 | urtwn_delay_ms(sc, 1); |
4501 | break; | | 4505 | break; |
4502 | case 0xfb: | | 4506 | case 0xfb: |
4503 | DELAY(50); | | 4507 | DELAY(50); |
4504 | break; | | 4508 | break; |
4505 | case 0xfa: | | 4509 | case 0xfa: |
4506 | DELAY(5); | | 4510 | DELAY(5); |
4507 | break; | | 4511 | break; |
4508 | case 0xf9: | | 4512 | case 0xf9: |
4509 | DELAY(1); | | 4513 | DELAY(1); |
4510 | break; | | 4514 | break; |
4511 | } | | 4515 | } |
4512 | urtwn_bb_write(sc, prog->regs[i], prog->vals[i]); | | 4516 | urtwn_bb_write(sc, prog->regs[i], prog->vals[i]); |
4513 | DELAY(1); | | 4517 | DELAY(1); |
4514 | } | | 4518 | } |
4515 | | | 4519 | |
4516 | if (sc->chip & URTWN_CHIP_92C_1T2R) { | | 4520 | if (sc->chip & URTWN_CHIP_92C_1T2R) { |
4517 | /* 8192C 1T only configuration. */ | | 4521 | /* 8192C 1T only configuration. */ |