| @@ -1,1866 +1,1870 @@ | | | @@ -1,1866 +1,1870 @@ |
1 | /* $NetBSD: if_urtwn.c,v 1.34.4.15 2016/12/05 10:55:18 skrll Exp $ */ | | 1 | /* $NetBSD: if_urtwn.c,v 1.34.4.16 2017/01/28 12:04:17 skrll 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 | /*- | | 22 | /*- |
23 | * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU | | 23 | * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU |
24 | * RTL8192EU. | | 24 | * RTL8192EU. |
25 | */ | | 25 | */ |
26 | | | 26 | |
27 | #include <sys/cdefs.h> | | 27 | #include <sys/cdefs.h> |
28 | __KERNEL_RCSID(0, "$NetBSD: if_urtwn.c,v 1.34.4.15 2016/12/05 10:55:18 skrll Exp $"); | | 28 | __KERNEL_RCSID(0, "$NetBSD: if_urtwn.c,v 1.34.4.16 2017/01/28 12:04:17 skrll Exp $"); |
29 | | | 29 | |
30 | #ifdef _KERNEL_OPT | | 30 | #ifdef _KERNEL_OPT |
31 | #include "opt_inet.h" | | 31 | #include "opt_inet.h" |
32 | #include "opt_usb.h" | | 32 | #include "opt_usb.h" |
33 | #endif | | 33 | #endif |
34 | | | 34 | |
35 | #include <sys/param.h> | | 35 | #include <sys/param.h> |
36 | #include <sys/sockio.h> | | 36 | #include <sys/sockio.h> |
37 | #include <sys/sysctl.h> | | 37 | #include <sys/sysctl.h> |
38 | #include <sys/mbuf.h> | | 38 | #include <sys/mbuf.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | #include <sys/socket.h> | | 40 | #include <sys/socket.h> |
41 | #include <sys/systm.h> | | 41 | #include <sys/systm.h> |
42 | #include <sys/module.h> | | 42 | #include <sys/module.h> |
43 | #include <sys/conf.h> | | 43 | #include <sys/conf.h> |
44 | #include <sys/device.h> | | 44 | #include <sys/device.h> |
45 | | | 45 | |
46 | #include <sys/bus.h> | | 46 | #include <sys/bus.h> |
47 | #include <machine/endian.h> | | 47 | #include <machine/endian.h> |
48 | #include <sys/intr.h> | | 48 | #include <sys/intr.h> |
49 | | | 49 | |
50 | #include <net/bpf.h> | | 50 | #include <net/bpf.h> |
51 | #include <net/if.h> | | 51 | #include <net/if.h> |
52 | #include <net/if_arp.h> | | 52 | #include <net/if_arp.h> |
53 | #include <net/if_dl.h> | | 53 | #include <net/if_dl.h> |
54 | #include <net/if_ether.h> | | 54 | #include <net/if_ether.h> |
55 | #include <net/if_media.h> | | 55 | #include <net/if_media.h> |
56 | #include <net/if_types.h> | | 56 | #include <net/if_types.h> |
57 | | | 57 | |
58 | #include <netinet/in.h> | | 58 | #include <netinet/in.h> |
59 | #include <netinet/in_systm.h> | | 59 | #include <netinet/in_systm.h> |
60 | #include <netinet/in_var.h> | | 60 | #include <netinet/in_var.h> |
61 | #include <netinet/ip.h> | | 61 | #include <netinet/ip.h> |
62 | #include <netinet/if_inarp.h> | | 62 | #include <netinet/if_inarp.h> |
63 | | | 63 | |
64 | #include <net80211/ieee80211_netbsd.h> | | 64 | #include <net80211/ieee80211_netbsd.h> |
65 | #include <net80211/ieee80211_var.h> | | 65 | #include <net80211/ieee80211_var.h> |
66 | #include <net80211/ieee80211_radiotap.h> | | 66 | #include <net80211/ieee80211_radiotap.h> |
67 | | | 67 | |
68 | #include <dev/firmload.h> | | 68 | #include <dev/firmload.h> |
69 | | | 69 | |
70 | #include <dev/usb/usb.h> | | 70 | #include <dev/usb/usb.h> |
71 | #include <dev/usb/usbdi.h> | | 71 | #include <dev/usb/usbdi.h> |
72 | #include <dev/usb/usbdivar.h> | | 72 | #include <dev/usb/usbdivar.h> |
73 | #include <dev/usb/usbdi_util.h> | | 73 | #include <dev/usb/usbdi_util.h> |
74 | #include <dev/usb/usbdevs.h> | | 74 | #include <dev/usb/usbdevs.h> |
75 | | | 75 | |
76 | #include <dev/usb/if_urtwnreg.h> | | 76 | #include <dev/usb/if_urtwnreg.h> |
77 | #include <dev/usb/if_urtwnvar.h> | | 77 | #include <dev/usb/if_urtwnvar.h> |
78 | #include <dev/usb/if_urtwn_data.h> | | 78 | #include <dev/usb/if_urtwn_data.h> |
79 | | | 79 | |
80 | /* | | 80 | /* |
81 | * The sc_write_mtx locking is to prevent sequences of writes from | | 81 | * The sc_write_mtx locking is to prevent sequences of writes from |
82 | * being intermingled with each other. I don't know if this is really | | 82 | * being intermingled with each other. I don't know if this is really |
83 | * needed. I have added it just to be on the safe side. | | 83 | * needed. I have added it just to be on the safe side. |
84 | */ | | 84 | */ |
85 | | | 85 | |
86 | #ifdef URTWN_DEBUG | | 86 | #ifdef URTWN_DEBUG |
87 | #define DBG_INIT __BIT(0) | | 87 | #define DBG_INIT __BIT(0) |
88 | #define DBG_FN __BIT(1) | | 88 | #define DBG_FN __BIT(1) |
89 | #define DBG_TX __BIT(2) | | 89 | #define DBG_TX __BIT(2) |
90 | #define DBG_RX __BIT(3) | | 90 | #define DBG_RX __BIT(3) |
91 | #define DBG_STM __BIT(4) | | 91 | #define DBG_STM __BIT(4) |
92 | #define DBG_RF __BIT(5) | | 92 | #define DBG_RF __BIT(5) |
93 | #define DBG_REG __BIT(6) | | 93 | #define DBG_REG __BIT(6) |
94 | #define DBG_ALL 0xffffffffU | | 94 | #define DBG_ALL 0xffffffffU |
95 | u_int urtwn_debug = 0; | | 95 | u_int urtwn_debug = 0; |
96 | #define DPRINTFN(n, s) \ | | 96 | #define DPRINTFN(n, s) \ |
97 | do { if (urtwn_debug & (n)) printf s; } while (/*CONSTCOND*/0) | | 97 | do { if (urtwn_debug & (n)) printf s; } while (/*CONSTCOND*/0) |
98 | #else | | 98 | #else |
99 | #define DPRINTFN(n, s) | | 99 | #define DPRINTFN(n, s) |
100 | #endif | | 100 | #endif |
101 | | | 101 | |
102 | #define URTWN_DEV(v,p) { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, 0 } | | 102 | #define URTWN_DEV(v,p) { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, 0 } |
103 | #define URTWN_RTL8188E_DEV(v,p) \ | | 103 | #define URTWN_RTL8188E_DEV(v,p) \ |
104 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8188E } | | 104 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8188E } |
105 | #define URTWN_RTL8192EU_DEV(v,p) \ | | 105 | #define URTWN_RTL8192EU_DEV(v,p) \ |
106 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8192E } | | 106 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, FLAG_RTL8192E } |
107 | static const struct urtwn_dev { | | 107 | static const struct urtwn_dev { |
108 | struct usb_devno dev; | | 108 | struct usb_devno dev; |
109 | uint32_t flags; | | 109 | uint32_t flags; |
110 | #define FLAG_RTL8188E __BIT(0) | | 110 | #define FLAG_RTL8188E __BIT(0) |
111 | #define FLAG_RTL8192E __BIT(1) | | 111 | #define FLAG_RTL8192E __BIT(1) |
112 | } urtwn_devs[] = { | | 112 | } urtwn_devs[] = { |
113 | URTWN_DEV(ABOCOM, RTL8188CU_1), | | 113 | URTWN_DEV(ABOCOM, RTL8188CU_1), |
114 | URTWN_DEV(ABOCOM, RTL8188CU_2), | | 114 | URTWN_DEV(ABOCOM, RTL8188CU_2), |
115 | URTWN_DEV(ABOCOM, RTL8192CU), | | 115 | URTWN_DEV(ABOCOM, RTL8192CU), |
116 | URTWN_DEV(ASUSTEK, RTL8192CU), | | 116 | URTWN_DEV(ASUSTEK, RTL8192CU), |
117 | URTWN_DEV(ASUSTEK, RTL8192CU_3), | | 117 | URTWN_DEV(ASUSTEK, RTL8192CU_3), |
118 | URTWN_DEV(ASUSTEK, USBN10NANO), | | 118 | URTWN_DEV(ASUSTEK, USBN10NANO), |
119 | URTWN_DEV(ASUSTEK, RTL8192CU_3), | | 119 | URTWN_DEV(ASUSTEK, RTL8192CU_3), |
120 | URTWN_DEV(AZUREWAVE, RTL8188CE_1), | | 120 | URTWN_DEV(AZUREWAVE, RTL8188CE_1), |
121 | URTWN_DEV(AZUREWAVE, RTL8188CE_2), | | 121 | URTWN_DEV(AZUREWAVE, RTL8188CE_2), |
122 | URTWN_DEV(AZUREWAVE, RTL8188CU), | | 122 | URTWN_DEV(AZUREWAVE, RTL8188CU), |
123 | URTWN_DEV(BELKIN, F7D2102), | | 123 | URTWN_DEV(BELKIN, F7D2102), |
124 | URTWN_DEV(BELKIN, RTL8188CU), | | 124 | URTWN_DEV(BELKIN, RTL8188CU), |
125 | URTWN_DEV(BELKIN, RTL8188CUS), | | 125 | URTWN_DEV(BELKIN, RTL8188CUS), |
126 | URTWN_DEV(BELKIN, RTL8192CU), | | 126 | URTWN_DEV(BELKIN, RTL8192CU), |
127 | URTWN_DEV(BELKIN, RTL8192CU_1), | | 127 | URTWN_DEV(BELKIN, RTL8192CU_1), |
128 | URTWN_DEV(BELKIN, RTL8192CU_2), | | 128 | URTWN_DEV(BELKIN, RTL8192CU_2), |
129 | URTWN_DEV(CHICONY, RTL8188CUS_1), | | 129 | URTWN_DEV(CHICONY, RTL8188CUS_1), |
130 | URTWN_DEV(CHICONY, RTL8188CUS_2), | | 130 | URTWN_DEV(CHICONY, RTL8188CUS_2), |
131 | URTWN_DEV(CHICONY, RTL8188CUS_3), | | 131 | URTWN_DEV(CHICONY, RTL8188CUS_3), |
132 | URTWN_DEV(CHICONY, RTL8188CUS_4), | | 132 | URTWN_DEV(CHICONY, RTL8188CUS_4), |
133 | URTWN_DEV(CHICONY, RTL8188CUS_5), | | 133 | URTWN_DEV(CHICONY, RTL8188CUS_5), |
134 | URTWN_DEV(CHICONY, RTL8188CUS_6), | | 134 | URTWN_DEV(CHICONY, RTL8188CUS_6), |
135 | URTWN_DEV(COMPARE, RTL8192CU), | | 135 | URTWN_DEV(COMPARE, RTL8192CU), |
136 | URTWN_DEV(COREGA, RTL8192CU), | | 136 | URTWN_DEV(COREGA, RTL8192CU), |
137 | URTWN_DEV(DLINK, DWA131B), | | 137 | URTWN_DEV(DLINK, DWA131B), |
138 | URTWN_DEV(DLINK, RTL8188CU), | | 138 | URTWN_DEV(DLINK, RTL8188CU), |
139 | URTWN_DEV(DLINK, RTL8192CU_1), | | 139 | URTWN_DEV(DLINK, RTL8192CU_1), |
140 | URTWN_DEV(DLINK, RTL8192CU_2), | | 140 | URTWN_DEV(DLINK, RTL8192CU_2), |
141 | URTWN_DEV(DLINK, RTL8192CU_3), | | 141 | URTWN_DEV(DLINK, RTL8192CU_3), |
142 | URTWN_DEV(DLINK, RTL8192CU_4), | | 142 | URTWN_DEV(DLINK, RTL8192CU_4), |
143 | URTWN_DEV(EDIMAX, RTL8188CU), | | 143 | URTWN_DEV(EDIMAX, RTL8188CU), |
144 | URTWN_DEV(EDIMAX, RTL8192CU), | | 144 | URTWN_DEV(EDIMAX, RTL8192CU), |
145 | URTWN_DEV(FEIXUN, RTL8188CU), | | 145 | URTWN_DEV(FEIXUN, RTL8188CU), |
146 | URTWN_DEV(FEIXUN, RTL8192CU), | | 146 | URTWN_DEV(FEIXUN, RTL8192CU), |
147 | URTWN_DEV(GUILLEMOT, HWNUP150), | | 147 | URTWN_DEV(GUILLEMOT, HWNUP150), |
148 | URTWN_DEV(GUILLEMOT, RTL8192CU), | | 148 | URTWN_DEV(GUILLEMOT, RTL8192CU), |
149 | URTWN_DEV(HAWKING, RTL8192CU), | | 149 | URTWN_DEV(HAWKING, RTL8192CU), |
150 | URTWN_DEV(HAWKING, RTL8192CU_2), | | 150 | URTWN_DEV(HAWKING, RTL8192CU_2), |
151 | URTWN_DEV(HP3, RTL8188CU), | | 151 | URTWN_DEV(HP3, RTL8188CU), |
152 | URTWN_DEV(IODATA, WNG150UM), | | 152 | URTWN_DEV(IODATA, WNG150UM), |
153 | URTWN_DEV(IODATA, RTL8192CU), | | 153 | URTWN_DEV(IODATA, RTL8192CU), |
154 | URTWN_DEV(NETGEAR, WNA1000M), | | 154 | URTWN_DEV(NETGEAR, WNA1000M), |
155 | URTWN_DEV(NETGEAR, RTL8192CU), | | 155 | URTWN_DEV(NETGEAR, RTL8192CU), |
156 | URTWN_DEV(NETGEAR4, RTL8188CU), | | 156 | URTWN_DEV(NETGEAR4, RTL8188CU), |
157 | URTWN_DEV(NOVATECH, RTL8188CU), | | 157 | URTWN_DEV(NOVATECH, RTL8188CU), |
158 | URTWN_DEV(PLANEX2, RTL8188CU_1), | | 158 | URTWN_DEV(PLANEX2, RTL8188CU_1), |
159 | URTWN_DEV(PLANEX2, RTL8188CU_2), | | 159 | URTWN_DEV(PLANEX2, RTL8188CU_2), |
160 | URTWN_DEV(PLANEX2, RTL8192CU), | | 160 | URTWN_DEV(PLANEX2, RTL8192CU), |
161 | URTWN_DEV(PLANEX2, RTL8188CU_3), | | 161 | URTWN_DEV(PLANEX2, RTL8188CU_3), |
162 | URTWN_DEV(PLANEX2, RTL8188CU_4), | | 162 | URTWN_DEV(PLANEX2, RTL8188CU_4), |
163 | URTWN_DEV(PLANEX2, RTL8188CUS), | | 163 | URTWN_DEV(PLANEX2, RTL8188CUS), |
164 | URTWN_DEV(REALTEK, RTL8188CE_0), | | 164 | URTWN_DEV(REALTEK, RTL8188CE_0), |
165 | URTWN_DEV(REALTEK, RTL8188CE_1), | | 165 | URTWN_DEV(REALTEK, RTL8188CE_1), |
166 | URTWN_DEV(REALTEK, RTL8188CTV), | | 166 | URTWN_DEV(REALTEK, RTL8188CTV), |
167 | URTWN_DEV(REALTEK, RTL8188CU_0), | | 167 | URTWN_DEV(REALTEK, RTL8188CU_0), |
168 | URTWN_DEV(REALTEK, RTL8188CU_1), | | 168 | URTWN_DEV(REALTEK, RTL8188CU_1), |
169 | URTWN_DEV(REALTEK, RTL8188CU_2), | | 169 | URTWN_DEV(REALTEK, RTL8188CU_2), |
170 | URTWN_DEV(REALTEK, RTL8188CU_3), | | 170 | URTWN_DEV(REALTEK, RTL8188CU_3), |
171 | URTWN_DEV(REALTEK, RTL8188CU_COMBO), | | 171 | URTWN_DEV(REALTEK, RTL8188CU_COMBO), |
172 | URTWN_DEV(REALTEK, RTL8188CUS), | | 172 | URTWN_DEV(REALTEK, RTL8188CUS), |
173 | URTWN_DEV(REALTEK, RTL8188RU), | | 173 | URTWN_DEV(REALTEK, RTL8188RU), |
174 | URTWN_DEV(REALTEK, RTL8188RU_2), | | 174 | URTWN_DEV(REALTEK, RTL8188RU_2), |
175 | URTWN_DEV(REALTEK, RTL8188RU_3), | | 175 | URTWN_DEV(REALTEK, RTL8188RU_3), |
176 | URTWN_DEV(REALTEK, RTL8191CU), | | 176 | URTWN_DEV(REALTEK, RTL8191CU), |
177 | URTWN_DEV(REALTEK, RTL8192CE), | | 177 | URTWN_DEV(REALTEK, RTL8192CE), |
178 | URTWN_DEV(REALTEK, RTL8192CU), | | 178 | URTWN_DEV(REALTEK, RTL8192CU), |
179 | URTWN_DEV(SITECOMEU, RTL8188CU), | | 179 | URTWN_DEV(SITECOMEU, RTL8188CU), |
180 | URTWN_DEV(SITECOMEU, RTL8188CU_2), | | 180 | URTWN_DEV(SITECOMEU, RTL8188CU_2), |
181 | URTWN_DEV(SITECOMEU, RTL8192CU), | | 181 | URTWN_DEV(SITECOMEU, RTL8192CU), |
182 | URTWN_DEV(SITECOMEU, RTL8192CUR2), | | 182 | URTWN_DEV(SITECOMEU, RTL8192CUR2), |
183 | URTWN_DEV(TPLINK, RTL8192CU), | | 183 | URTWN_DEV(TPLINK, RTL8192CU), |
184 | URTWN_DEV(TRENDNET, RTL8188CU), | | 184 | URTWN_DEV(TRENDNET, RTL8188CU), |
185 | URTWN_DEV(TRENDNET, RTL8192CU), | | 185 | URTWN_DEV(TRENDNET, RTL8192CU), |
186 | URTWN_DEV(ZYXEL, RTL8192CU), | | 186 | URTWN_DEV(ZYXEL, RTL8192CU), |
187 | | | 187 | |
188 | /* URTWN_RTL8188E */ | | 188 | /* URTWN_RTL8188E */ |
189 | URTWN_RTL8188E_DEV(DLINK, DWA125D1), | | 189 | URTWN_RTL8188E_DEV(DLINK, DWA125D1), |
190 | URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), | | 190 | URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), |
191 | URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), | | 191 | URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), |
192 | URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), | | 192 | URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), |
193 | URTWN_RTL8188E_DEV(ABOCOM, RTL8188EU), | | 193 | URTWN_RTL8188E_DEV(ABOCOM, RTL8188EU), |
194 | | | 194 | |
195 | /* URTWN_RTL8192EU */ | | 195 | /* URTWN_RTL8192EU */ |
196 | URTWN_RTL8192EU_DEV(REALTEK, RTL8192EU), | | 196 | URTWN_RTL8192EU_DEV(REALTEK, RTL8192EU), |
197 | }; | | 197 | }; |
198 | #undef URTWN_DEV | | 198 | #undef URTWN_DEV |
199 | #undef URTWN_RTL8188E_DEV | | 199 | #undef URTWN_RTL8188E_DEV |
200 | #undef URTWN_RTL8192EU_DEV | | 200 | #undef URTWN_RTL8192EU_DEV |
201 | | | 201 | |
202 | static int urtwn_match(device_t, cfdata_t, void *); | | 202 | static int urtwn_match(device_t, cfdata_t, void *); |
203 | static void urtwn_attach(device_t, device_t, void *); | | 203 | static void urtwn_attach(device_t, device_t, void *); |
204 | static int urtwn_detach(device_t, int); | | 204 | static int urtwn_detach(device_t, int); |
205 | static int urtwn_activate(device_t, enum devact); | | 205 | static int urtwn_activate(device_t, enum devact); |
206 | | | 206 | |
207 | CFATTACH_DECL_NEW(urtwn, sizeof(struct urtwn_softc), urtwn_match, | | 207 | CFATTACH_DECL_NEW(urtwn, sizeof(struct urtwn_softc), urtwn_match, |
208 | urtwn_attach, urtwn_detach, urtwn_activate); | | 208 | urtwn_attach, urtwn_detach, urtwn_activate); |
209 | | | 209 | |
210 | static int urtwn_open_pipes(struct urtwn_softc *); | | 210 | static int urtwn_open_pipes(struct urtwn_softc *); |
211 | static void urtwn_close_pipes(struct urtwn_softc *); | | 211 | static void urtwn_close_pipes(struct urtwn_softc *); |
212 | static int urtwn_alloc_rx_list(struct urtwn_softc *); | | 212 | static int urtwn_alloc_rx_list(struct urtwn_softc *); |
213 | static void urtwn_free_rx_list(struct urtwn_softc *); | | 213 | static void urtwn_free_rx_list(struct urtwn_softc *); |
214 | static int urtwn_alloc_tx_list(struct urtwn_softc *); | | 214 | static int urtwn_alloc_tx_list(struct urtwn_softc *); |
215 | static void urtwn_free_tx_list(struct urtwn_softc *); | | 215 | static void urtwn_free_tx_list(struct urtwn_softc *); |
216 | static void urtwn_task(void *); | | 216 | static void urtwn_task(void *); |
217 | static void urtwn_do_async(struct urtwn_softc *, | | 217 | static void urtwn_do_async(struct urtwn_softc *, |
218 | void (*)(struct urtwn_softc *, void *), void *, int); | | 218 | void (*)(struct urtwn_softc *, void *), void *, int); |
219 | static void urtwn_wait_async(struct urtwn_softc *); | | 219 | static void urtwn_wait_async(struct urtwn_softc *); |
220 | static int urtwn_write_region_1(struct urtwn_softc *, uint16_t, uint8_t *, | | 220 | static int urtwn_write_region_1(struct urtwn_softc *, uint16_t, uint8_t *, |
221 | int); | | 221 | int); |
222 | static void urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); | | 222 | static void urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); |
223 | static void urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); | | 223 | static void urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); |
224 | static void urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); | | 224 | static void urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); |
225 | static int urtwn_write_region(struct urtwn_softc *, uint16_t, uint8_t *, | | 225 | static int urtwn_write_region(struct urtwn_softc *, uint16_t, uint8_t *, |
226 | int); | | 226 | int); |
227 | static int urtwn_read_region_1(struct urtwn_softc *, uint16_t, uint8_t *, | | 227 | static int urtwn_read_region_1(struct urtwn_softc *, uint16_t, uint8_t *, |
228 | int); | | 228 | int); |
229 | static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); | | 229 | static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); |
230 | static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); | | 230 | static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); |
231 | static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); | | 231 | static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); |
232 | static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, const void *, int); | | 232 | static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, const void *, int); |
233 | static void urtwn_r92c_rf_write(struct urtwn_softc *, int, uint8_t, | | 233 | static void urtwn_r92c_rf_write(struct urtwn_softc *, int, uint8_t, |
234 | uint32_t); | | 234 | uint32_t); |
235 | static void urtwn_r88e_rf_write(struct urtwn_softc *, int, uint8_t, | | 235 | static void urtwn_r88e_rf_write(struct urtwn_softc *, int, uint8_t, |
236 | uint32_t); | | 236 | uint32_t); |
237 | static void urtwn_r92e_rf_write(struct urtwn_softc *, int, uint8_t, | | 237 | static void urtwn_r92e_rf_write(struct urtwn_softc *, int, uint8_t, |
238 | uint32_t); | | 238 | uint32_t); |
239 | static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); | | 239 | static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); |
240 | static int urtwn_llt_write(struct urtwn_softc *, uint32_t, uint32_t); | | 240 | static int urtwn_llt_write(struct urtwn_softc *, uint32_t, uint32_t); |
241 | static uint8_t urtwn_efuse_read_1(struct urtwn_softc *, uint16_t); | | 241 | static uint8_t urtwn_efuse_read_1(struct urtwn_softc *, uint16_t); |
242 | static void urtwn_efuse_read(struct urtwn_softc *); | | 242 | static void urtwn_efuse_read(struct urtwn_softc *); |
243 | static void urtwn_efuse_switch_power(struct urtwn_softc *); | | 243 | static void urtwn_efuse_switch_power(struct urtwn_softc *); |
244 | static int urtwn_read_chipid(struct urtwn_softc *); | | 244 | static int urtwn_read_chipid(struct urtwn_softc *); |
245 | #ifdef URTWN_DEBUG | | 245 | #ifdef URTWN_DEBUG |
246 | static void urtwn_dump_rom(struct urtwn_softc *, struct r92c_rom *); | | 246 | static void urtwn_dump_rom(struct urtwn_softc *, struct r92c_rom *); |
247 | #endif | | 247 | #endif |
248 | static void urtwn_read_rom(struct urtwn_softc *); | | 248 | static void urtwn_read_rom(struct urtwn_softc *); |
249 | static void urtwn_r88e_read_rom(struct urtwn_softc *); | | 249 | static void urtwn_r88e_read_rom(struct urtwn_softc *); |
250 | static int urtwn_media_change(struct ifnet *); | | 250 | static int urtwn_media_change(struct ifnet *); |
251 | static int urtwn_ra_init(struct urtwn_softc *); | | 251 | static int urtwn_ra_init(struct urtwn_softc *); |
252 | static int urtwn_get_nettype(struct urtwn_softc *); | | 252 | static int urtwn_get_nettype(struct urtwn_softc *); |
253 | static void urtwn_set_nettype0_msr(struct urtwn_softc *, uint8_t); | | 253 | static void urtwn_set_nettype0_msr(struct urtwn_softc *, uint8_t); |
254 | static void urtwn_tsf_sync_enable(struct urtwn_softc *); | | 254 | static void urtwn_tsf_sync_enable(struct urtwn_softc *); |
255 | static void urtwn_set_led(struct urtwn_softc *, int, int); | | 255 | static void urtwn_set_led(struct urtwn_softc *, int, int); |
256 | static void urtwn_calib_to(void *); | | 256 | static void urtwn_calib_to(void *); |
257 | static void urtwn_calib_to_cb(struct urtwn_softc *, void *); | | 257 | static void urtwn_calib_to_cb(struct urtwn_softc *, void *); |
258 | static void urtwn_next_scan(void *); | | 258 | static void urtwn_next_scan(void *); |
259 | static int urtwn_newstate(struct ieee80211com *, enum ieee80211_state, | | 259 | static int urtwn_newstate(struct ieee80211com *, enum ieee80211_state, |
260 | int); | | 260 | int); |
261 | static void urtwn_newstate_cb(struct urtwn_softc *, void *); | | 261 | static void urtwn_newstate_cb(struct urtwn_softc *, void *); |
262 | static int urtwn_wme_update(struct ieee80211com *); | | 262 | static int urtwn_wme_update(struct ieee80211com *); |
263 | static void urtwn_wme_update_cb(struct urtwn_softc *, void *); | | 263 | static void urtwn_wme_update_cb(struct urtwn_softc *, void *); |
264 | static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); | | 264 | static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); |
265 | static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); | | 265 | static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); |
266 | static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); | | 266 | static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); |
267 | static void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int); | | 267 | static void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int); |
268 | static void urtwn_rxeof(struct usbd_xfer *, void *, usbd_status); | | 268 | static void urtwn_rxeof(struct usbd_xfer *, void *, usbd_status); |
269 | static void urtwn_txeof(struct usbd_xfer *, void *, usbd_status); | | 269 | static void urtwn_txeof(struct usbd_xfer *, void *, usbd_status); |
270 | static int urtwn_tx(struct urtwn_softc *, struct mbuf *, | | 270 | static int urtwn_tx(struct urtwn_softc *, struct mbuf *, |
271 | struct ieee80211_node *, struct urtwn_tx_data *); | | 271 | struct ieee80211_node *, struct urtwn_tx_data *); |
272 | static struct urtwn_tx_data * | | 272 | static struct urtwn_tx_data * |
273 | urtwn_get_tx_data(struct urtwn_softc *, size_t); | | 273 | urtwn_get_tx_data(struct urtwn_softc *, size_t); |
274 | static void urtwn_start(struct ifnet *); | | 274 | static void urtwn_start(struct ifnet *); |
275 | static void urtwn_watchdog(struct ifnet *); | | 275 | static void urtwn_watchdog(struct ifnet *); |
276 | static int urtwn_ioctl(struct ifnet *, u_long, void *); | | 276 | static int urtwn_ioctl(struct ifnet *, u_long, void *); |
277 | static int urtwn_r92c_power_on(struct urtwn_softc *); | | 277 | static int urtwn_r92c_power_on(struct urtwn_softc *); |
278 | static int urtwn_r92e_power_on(struct urtwn_softc *); | | 278 | static int urtwn_r92e_power_on(struct urtwn_softc *); |
279 | static int urtwn_r88e_power_on(struct urtwn_softc *); | | 279 | static int urtwn_r88e_power_on(struct urtwn_softc *); |
280 | static int urtwn_llt_init(struct urtwn_softc *); | | 280 | static int urtwn_llt_init(struct urtwn_softc *); |
281 | static void urtwn_fw_reset(struct urtwn_softc *); | | 281 | static void urtwn_fw_reset(struct urtwn_softc *); |
282 | static void urtwn_r88e_fw_reset(struct urtwn_softc *); | | 282 | static void urtwn_r88e_fw_reset(struct urtwn_softc *); |
283 | static int urtwn_fw_loadpage(struct urtwn_softc *, int, uint8_t *, int); | | 283 | static int urtwn_fw_loadpage(struct urtwn_softc *, int, uint8_t *, int); |
284 | static int urtwn_load_firmware(struct urtwn_softc *); | | 284 | static int urtwn_load_firmware(struct urtwn_softc *); |
285 | static int urtwn_r92c_dma_init(struct urtwn_softc *); | | 285 | static int urtwn_r92c_dma_init(struct urtwn_softc *); |
286 | static int urtwn_r88e_dma_init(struct urtwn_softc *); | | 286 | static int urtwn_r88e_dma_init(struct urtwn_softc *); |
287 | static void urtwn_mac_init(struct urtwn_softc *); | | 287 | static void urtwn_mac_init(struct urtwn_softc *); |
288 | static void urtwn_bb_init(struct urtwn_softc *); | | 288 | static void urtwn_bb_init(struct urtwn_softc *); |
289 | static void urtwn_rf_init(struct urtwn_softc *); | | 289 | static void urtwn_rf_init(struct urtwn_softc *); |
290 | static void urtwn_cam_init(struct urtwn_softc *); | | 290 | static void urtwn_cam_init(struct urtwn_softc *); |
291 | static void urtwn_pa_bias_init(struct urtwn_softc *); | | 291 | static void urtwn_pa_bias_init(struct urtwn_softc *); |
292 | static void urtwn_rxfilter_init(struct urtwn_softc *); | | 292 | static void urtwn_rxfilter_init(struct urtwn_softc *); |
293 | static void urtwn_edca_init(struct urtwn_softc *); | | 293 | static void urtwn_edca_init(struct urtwn_softc *); |
294 | static void urtwn_write_txpower(struct urtwn_softc *, int, uint16_t[]); | | 294 | static void urtwn_write_txpower(struct urtwn_softc *, int, uint16_t[]); |
295 | static void urtwn_get_txpower(struct urtwn_softc *, size_t, u_int, u_int, | | 295 | static void urtwn_get_txpower(struct urtwn_softc *, size_t, u_int, u_int, |
296 | uint16_t[]); | | 296 | uint16_t[]); |
297 | static void urtwn_r88e_get_txpower(struct urtwn_softc *, size_t, u_int, | | 297 | static void urtwn_r88e_get_txpower(struct urtwn_softc *, size_t, u_int, |
298 | u_int, uint16_t[]); | | 298 | u_int, uint16_t[]); |
299 | static void urtwn_set_txpower(struct urtwn_softc *, u_int, u_int); | | 299 | static void urtwn_set_txpower(struct urtwn_softc *, u_int, u_int); |
300 | static void urtwn_set_chan(struct urtwn_softc *, struct ieee80211_channel *, | | 300 | static void urtwn_set_chan(struct urtwn_softc *, struct ieee80211_channel *, |
301 | u_int); | | 301 | u_int); |
302 | static void urtwn_iq_calib(struct urtwn_softc *, bool); | | 302 | static void urtwn_iq_calib(struct urtwn_softc *, bool); |
303 | static void urtwn_lc_calib(struct urtwn_softc *); | | 303 | static void urtwn_lc_calib(struct urtwn_softc *); |
304 | static void urtwn_temp_calib(struct urtwn_softc *); | | 304 | static void urtwn_temp_calib(struct urtwn_softc *); |
305 | static int urtwn_init(struct ifnet *); | | 305 | static int urtwn_init(struct ifnet *); |
306 | static void urtwn_stop(struct ifnet *, int); | | 306 | static void urtwn_stop(struct ifnet *, int); |
307 | static int urtwn_reset(struct ifnet *); | | 307 | static int urtwn_reset(struct ifnet *); |
308 | static void urtwn_chip_stop(struct urtwn_softc *); | | 308 | static void urtwn_chip_stop(struct urtwn_softc *); |
309 | static void urtwn_newassoc(struct ieee80211_node *, int); | | 309 | static void urtwn_newassoc(struct ieee80211_node *, int); |
310 | static void urtwn_delay_ms(struct urtwn_softc *, int ms); | | 310 | static void urtwn_delay_ms(struct urtwn_softc *, int ms); |
311 | | | 311 | |
312 | /* Aliases. */ | | 312 | /* Aliases. */ |
313 | #define urtwn_bb_write urtwn_write_4 | | 313 | #define urtwn_bb_write urtwn_write_4 |
314 | #define urtwn_bb_read urtwn_read_4 | | 314 | #define urtwn_bb_read urtwn_read_4 |
315 | | | 315 | |
316 | #define urtwn_lookup(d,v,p) ((const struct urtwn_dev *)usb_lookup(d,v,p)) | | 316 | #define urtwn_lookup(d,v,p) ((const struct urtwn_dev *)usb_lookup(d,v,p)) |
317 | | | 317 | |
318 | static const uint16_t addaReg[] = { | | 318 | static const uint16_t addaReg[] = { |
319 | R92C_FPGA0_XCD_SWITCHCTL, R92C_BLUETOOTH, R92C_RX_WAIT_CCA, | | 319 | R92C_FPGA0_XCD_SWITCHCTL, R92C_BLUETOOTH, R92C_RX_WAIT_CCA, |
320 | R92C_TX_CCK_RFON, R92C_TX_CCK_BBON, R92C_TX_OFDM_RFON, | | 320 | R92C_TX_CCK_RFON, R92C_TX_CCK_BBON, R92C_TX_OFDM_RFON, |
321 | R92C_TX_OFDM_BBON, R92C_TX_TO_RX, R92C_TX_TO_TX, R92C_RX_CCK, | | 321 | R92C_TX_OFDM_BBON, R92C_TX_TO_RX, R92C_TX_TO_TX, R92C_RX_CCK, |
322 | R92C_RX_OFDM, R92C_RX_WAIT_RIFS, R92C_RX_TO_RX, | | 322 | R92C_RX_OFDM, R92C_RX_WAIT_RIFS, R92C_RX_TO_RX, |
323 | R92C_STANDBY, R92C_SLEEP, R92C_PMPD_ANAEN | | 323 | R92C_STANDBY, R92C_SLEEP, R92C_PMPD_ANAEN |
324 | }; | | 324 | }; |
325 | | | 325 | |
326 | static int | | 326 | static int |
327 | urtwn_match(device_t parent, cfdata_t match, void *aux) | | 327 | urtwn_match(device_t parent, cfdata_t match, void *aux) |
328 | { | | 328 | { |
329 | struct usb_attach_arg *uaa = aux; | | 329 | struct usb_attach_arg *uaa = aux; |
330 | | | 330 | |
331 | return urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product) != | | 331 | return urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product) != |
332 | NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | | 332 | NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; |
333 | } | | 333 | } |
334 | | | 334 | |
335 | static void | | 335 | static void |
336 | urtwn_attach(device_t parent, device_t self, void *aux) | | 336 | urtwn_attach(device_t parent, device_t self, void *aux) |
337 | { | | 337 | { |
338 | struct urtwn_softc *sc = device_private(self); | | 338 | struct urtwn_softc *sc = device_private(self); |
339 | struct ieee80211com *ic = &sc->sc_ic; | | 339 | struct ieee80211com *ic = &sc->sc_ic; |
340 | struct ifnet *ifp = &sc->sc_if; | | 340 | struct ifnet *ifp = &sc->sc_if; |
341 | struct usb_attach_arg *uaa = aux; | | 341 | struct usb_attach_arg *uaa = aux; |
342 | char *devinfop; | | 342 | char *devinfop; |
343 | const struct urtwn_dev *dev; | | 343 | const struct urtwn_dev *dev; |
344 | usb_device_request_t req; | | 344 | usb_device_request_t req; |
345 | size_t i; | | 345 | size_t i; |
346 | int error; | | 346 | int error; |
347 | | | 347 | |
348 | sc->sc_dev = self; | | 348 | sc->sc_dev = self; |
349 | sc->sc_udev = uaa->uaa_device; | | 349 | sc->sc_udev = uaa->uaa_device; |
350 | | | 350 | |
351 | sc->chip = 0; | | 351 | sc->chip = 0; |
352 | dev = urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product); | | 352 | dev = urtwn_lookup(urtwn_devs, uaa->uaa_vendor, uaa->uaa_product); |
353 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8188E)) | | 353 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8188E)) |
354 | SET(sc->chip, URTWN_CHIP_88E); | | 354 | SET(sc->chip, URTWN_CHIP_88E); |
355 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8192E)) | | 355 | if (dev != NULL && ISSET(dev->flags, FLAG_RTL8192E)) |
356 | SET(sc->chip, URTWN_CHIP_92EU); | | 356 | SET(sc->chip, URTWN_CHIP_92EU); |
357 | | | 357 | |
358 | aprint_naive("\n"); | | 358 | aprint_naive("\n"); |
359 | aprint_normal("\n"); | | 359 | aprint_normal("\n"); |
360 | | | 360 | |
361 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 361 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
362 | | | 362 | |
363 | devinfop = usbd_devinfo_alloc(sc->sc_udev, 0); | | 363 | devinfop = usbd_devinfo_alloc(sc->sc_udev, 0); |
364 | aprint_normal_dev(self, "%s\n", devinfop); | | 364 | aprint_normal_dev(self, "%s\n", devinfop); |
365 | usbd_devinfo_free(devinfop); | | 365 | usbd_devinfo_free(devinfop); |
366 | | | 366 | |
367 | req.bmRequestType = UT_WRITE_DEVICE; | | 367 | req.bmRequestType = UT_WRITE_DEVICE; |
368 | req.bRequest = UR_SET_FEATURE; | | 368 | req.bRequest = UR_SET_FEATURE; |
369 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); | | 369 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); |
370 | USETW(req.wIndex, UHF_PORT_SUSPEND); | | 370 | USETW(req.wIndex, UHF_PORT_SUSPEND); |
371 | USETW(req.wLength, 0); | | 371 | USETW(req.wLength, 0); |
372 | | | 372 | |
373 | (void) usbd_do_request(sc->sc_udev, &req, 0); | | 373 | (void) usbd_do_request(sc->sc_udev, &req, 0); |
374 | | | 374 | |
| | | 375 | cv_init(&sc->sc_task_cv, "urtwntsk"); |
375 | mutex_init(&sc->sc_task_mtx, MUTEX_DEFAULT, IPL_NET); | | 376 | mutex_init(&sc->sc_task_mtx, MUTEX_DEFAULT, IPL_NET); |
376 | mutex_init(&sc->sc_tx_mtx, MUTEX_DEFAULT, IPL_NONE); | | 377 | mutex_init(&sc->sc_tx_mtx, MUTEX_DEFAULT, IPL_NONE); |
377 | mutex_init(&sc->sc_rx_mtx, MUTEX_DEFAULT, IPL_NONE); | | 378 | mutex_init(&sc->sc_rx_mtx, MUTEX_DEFAULT, IPL_NONE); |
378 | mutex_init(&sc->sc_fwcmd_mtx, MUTEX_DEFAULT, IPL_NONE); | | 379 | mutex_init(&sc->sc_fwcmd_mtx, MUTEX_DEFAULT, IPL_NONE); |
379 | mutex_init(&sc->sc_write_mtx, MUTEX_DEFAULT, IPL_NONE); | | 380 | mutex_init(&sc->sc_write_mtx, MUTEX_DEFAULT, IPL_NONE); |
380 | | | 381 | |
381 | usb_init_task(&sc->sc_task, urtwn_task, sc, 0); | | 382 | usb_init_task(&sc->sc_task, urtwn_task, sc, 0); |
382 | | | 383 | |
383 | callout_init(&sc->sc_scan_to, 0); | | 384 | callout_init(&sc->sc_scan_to, 0); |
384 | callout_setfunc(&sc->sc_scan_to, urtwn_next_scan, sc); | | 385 | callout_setfunc(&sc->sc_scan_to, urtwn_next_scan, sc); |
385 | callout_init(&sc->sc_calib_to, 0); | | 386 | callout_init(&sc->sc_calib_to, 0); |
386 | callout_setfunc(&sc->sc_calib_to, urtwn_calib_to, sc); | | 387 | callout_setfunc(&sc->sc_calib_to, urtwn_calib_to, sc); |
387 | | | 388 | |
388 | error = usbd_set_config_no(sc->sc_udev, 1, 0); | | 389 | error = usbd_set_config_no(sc->sc_udev, 1, 0); |
389 | if (error != 0) { | | 390 | if (error != 0) { |
390 | aprint_error_dev(self, "failed to set configuration" | | 391 | aprint_error_dev(self, "failed to set configuration" |
391 | ", err=%s\n", usbd_errstr(error)); | | 392 | ", err=%s\n", usbd_errstr(error)); |
392 | goto fail; | | 393 | goto fail; |
393 | } | | 394 | } |
394 | | | 395 | |
395 | /* Get the first interface handle. */ | | 396 | /* Get the first interface handle. */ |
396 | error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); | | 397 | error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); |
397 | if (error != 0) { | | 398 | if (error != 0) { |
398 | aprint_error_dev(self, "could not get interface handle\n"); | | 399 | aprint_error_dev(self, "could not get interface handle\n"); |
399 | goto fail; | | 400 | goto fail; |
400 | } | | 401 | } |
401 | | | 402 | |
402 | error = urtwn_read_chipid(sc); | | 403 | error = urtwn_read_chipid(sc); |
403 | if (error != 0) { | | 404 | if (error != 0) { |
404 | aprint_error_dev(self, "unsupported test chip\n"); | | 405 | aprint_error_dev(self, "unsupported test chip\n"); |
405 | goto fail; | | 406 | goto fail; |
406 | } | | 407 | } |
407 | | | 408 | |
408 | /* Determine number of Tx/Rx chains. */ | | 409 | /* Determine number of Tx/Rx chains. */ |
409 | if (sc->chip & URTWN_CHIP_92C) { | | 410 | if (sc->chip & URTWN_CHIP_92C) { |
410 | sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; | | 411 | sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; |
411 | sc->nrxchains = 2; | | 412 | sc->nrxchains = 2; |
412 | } else if (sc->chip & URTWN_CHIP_92EU) { | | 413 | } else if (sc->chip & URTWN_CHIP_92EU) { |
413 | sc->ntxchains = 2; | | 414 | sc->ntxchains = 2; |
414 | sc->nrxchains = 2; | | 415 | sc->nrxchains = 2; |
415 | } else { | | 416 | } else { |
416 | sc->ntxchains = 1; | | 417 | sc->ntxchains = 1; |
417 | sc->nrxchains = 1; | | 418 | sc->nrxchains = 1; |
418 | } | | 419 | } |
419 | | | 420 | |
420 | if (ISSET(sc->chip, URTWN_CHIP_88E) || | | 421 | if (ISSET(sc->chip, URTWN_CHIP_88E) || |
421 | ISSET(sc->chip, URTWN_CHIP_92EU)) | | 422 | ISSET(sc->chip, URTWN_CHIP_92EU)) |
422 | urtwn_r88e_read_rom(sc); | | 423 | urtwn_r88e_read_rom(sc); |
423 | else | | 424 | else |
424 | urtwn_read_rom(sc); | | 425 | urtwn_read_rom(sc); |
425 | | | 426 | |
426 | aprint_normal_dev(self, "MAC/BB RTL%s, RF 6052 %zdT%zdR, address %s\n", | | 427 | aprint_normal_dev(self, "MAC/BB RTL%s, RF 6052 %zdT%zdR, address %s\n", |
427 | (sc->chip & URTWN_CHIP_92EU) ? "8192EU" : | | 428 | (sc->chip & URTWN_CHIP_92EU) ? "8192EU" : |
428 | (sc->chip & URTWN_CHIP_92C) ? "8192CU" : | | 429 | (sc->chip & URTWN_CHIP_92C) ? "8192CU" : |
429 | (sc->chip & URTWN_CHIP_88E) ? "8188EU" : | | 430 | (sc->chip & URTWN_CHIP_88E) ? "8188EU" : |
430 | (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : | | 431 | (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : |
431 | (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : | | 432 | (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : |
432 | "8188CUS", sc->ntxchains, sc->nrxchains, | | 433 | "8188CUS", sc->ntxchains, sc->nrxchains, |
433 | ether_sprintf(ic->ic_myaddr)); | | 434 | ether_sprintf(ic->ic_myaddr)); |
434 | | | 435 | |
435 | error = urtwn_open_pipes(sc); | | 436 | error = urtwn_open_pipes(sc); |
436 | if (error != 0) { | | 437 | if (error != 0) { |
437 | aprint_error_dev(sc->sc_dev, "could not open pipes\n"); | | 438 | aprint_error_dev(sc->sc_dev, "could not open pipes\n"); |
438 | goto fail; | | 439 | goto fail; |
439 | } | | 440 | } |
440 | aprint_normal_dev(self, "%d rx pipe%s, %d tx pipe%s\n", | | 441 | aprint_normal_dev(self, "%d rx pipe%s, %d tx pipe%s\n", |
441 | sc->rx_npipe, sc->rx_npipe > 1 ? "s" : "", | | 442 | sc->rx_npipe, sc->rx_npipe > 1 ? "s" : "", |
442 | sc->tx_npipe, sc->tx_npipe > 1 ? "s" : ""); | | 443 | sc->tx_npipe, sc->tx_npipe > 1 ? "s" : ""); |
443 | | | 444 | |
444 | /* | | 445 | /* |
445 | * Setup the 802.11 device. | | 446 | * Setup the 802.11 device. |
446 | */ | | 447 | */ |
447 | ic->ic_ifp = ifp; | | 448 | ic->ic_ifp = ifp; |
448 | ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */ | | 449 | ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */ |
449 | ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */ | | 450 | ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */ |
450 | ic->ic_state = IEEE80211_S_INIT; | | 451 | ic->ic_state = IEEE80211_S_INIT; |
451 | | | 452 | |
452 | /* Set device capabilities. */ | | 453 | /* Set device capabilities. */ |
453 | ic->ic_caps = | | 454 | ic->ic_caps = |
454 | IEEE80211_C_MONITOR | /* Monitor mode supported. */ | | 455 | IEEE80211_C_MONITOR | /* Monitor mode supported. */ |
455 | IEEE80211_C_IBSS | /* IBSS mode supported */ | | 456 | IEEE80211_C_IBSS | /* IBSS mode supported */ |
456 | IEEE80211_C_HOSTAP | /* HostAp mode supported */ | | 457 | IEEE80211_C_HOSTAP | /* HostAp mode supported */ |
457 | IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ | | 458 | IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ |
458 | IEEE80211_C_SHSLOT | /* Short slot time supported. */ | | 459 | IEEE80211_C_SHSLOT | /* Short slot time supported. */ |
459 | IEEE80211_C_WME | /* 802.11e */ | | 460 | IEEE80211_C_WME | /* 802.11e */ |
460 | IEEE80211_C_WPA; /* 802.11i */ | | 461 | IEEE80211_C_WPA; /* 802.11i */ |
461 | | | 462 | |
462 | /* Set supported .11b and .11g rates. */ | | 463 | /* Set supported .11b and .11g rates. */ |
463 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | | 464 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; |
464 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; | | 465 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; |
465 | | | 466 | |
466 | /* Set supported .11b and .11g channels (1 through 14). */ | | 467 | /* Set supported .11b and .11g channels (1 through 14). */ |
467 | for (i = 1; i <= 14; i++) { | | 468 | for (i = 1; i <= 14; i++) { |
468 | ic->ic_channels[i].ic_freq = | | 469 | ic->ic_channels[i].ic_freq = |
469 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); | | 470 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); |
470 | ic->ic_channels[i].ic_flags = | | 471 | ic->ic_channels[i].ic_flags = |
471 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | | | 472 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | |
472 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; | | 473 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; |
473 | } | | 474 | } |
474 | | | 475 | |
475 | ifp->if_softc = sc; | | 476 | ifp->if_softc = sc; |
476 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 477 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
477 | ifp->if_init = urtwn_init; | | 478 | ifp->if_init = urtwn_init; |
478 | ifp->if_ioctl = urtwn_ioctl; | | 479 | ifp->if_ioctl = urtwn_ioctl; |
479 | ifp->if_start = urtwn_start; | | 480 | ifp->if_start = urtwn_start; |
480 | ifp->if_watchdog = urtwn_watchdog; | | 481 | ifp->if_watchdog = urtwn_watchdog; |
481 | IFQ_SET_READY(&ifp->if_snd); | | 482 | IFQ_SET_READY(&ifp->if_snd); |
482 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | | 483 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); |
483 | | | 484 | |
484 | if_attach(ifp); | | 485 | if_attach(ifp); |
485 | ieee80211_ifattach(ic); | | 486 | ieee80211_ifattach(ic); |
486 | | | 487 | |
487 | /* override default methods */ | | 488 | /* override default methods */ |
488 | ic->ic_newassoc = urtwn_newassoc; | | 489 | ic->ic_newassoc = urtwn_newassoc; |
489 | ic->ic_reset = urtwn_reset; | | 490 | ic->ic_reset = urtwn_reset; |
490 | ic->ic_wme.wme_update = urtwn_wme_update; | | 491 | ic->ic_wme.wme_update = urtwn_wme_update; |
491 | | | 492 | |
492 | /* Override state transition machine. */ | | 493 | /* Override state transition machine. */ |
493 | sc->sc_newstate = ic->ic_newstate; | | 494 | sc->sc_newstate = ic->ic_newstate; |
494 | ic->ic_newstate = urtwn_newstate; | | 495 | ic->ic_newstate = urtwn_newstate; |
495 | ieee80211_media_init(ic, urtwn_media_change, ieee80211_media_status); | | 496 | ieee80211_media_init(ic, urtwn_media_change, ieee80211_media_status); |
496 | | | 497 | |
497 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, | | 498 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, |
498 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, | | 499 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, |
499 | &sc->sc_drvbpf); | | 500 | &sc->sc_drvbpf); |
500 | | | 501 | |
501 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu); | | 502 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu); |
502 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); | | 503 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); |
503 | sc->sc_rxtap.wr_ihdr.it_present = htole32(URTWN_RX_RADIOTAP_PRESENT); | | 504 | sc->sc_rxtap.wr_ihdr.it_present = htole32(URTWN_RX_RADIOTAP_PRESENT); |
504 | | | 505 | |
505 | sc->sc_txtap_len = sizeof(sc->sc_txtapu); | | 506 | sc->sc_txtap_len = sizeof(sc->sc_txtapu); |
506 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); | | 507 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); |
507 | sc->sc_txtap.wt_ihdr.it_present = htole32(URTWN_TX_RADIOTAP_PRESENT); | | 508 | sc->sc_txtap.wt_ihdr.it_present = htole32(URTWN_TX_RADIOTAP_PRESENT); |
508 | | | 509 | |
509 | ieee80211_announce(ic); | | 510 | ieee80211_announce(ic); |
510 | | | 511 | |
511 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); | | 512 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); |
512 | | | 513 | |
513 | if (!pmf_device_register(self, NULL, NULL)) | | 514 | if (!pmf_device_register(self, NULL, NULL)) |
514 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 515 | aprint_error_dev(self, "couldn't establish power handler\n"); |
515 | | | 516 | |
516 | SET(sc->sc_flags, URTWN_FLAG_ATTACHED); | | 517 | SET(sc->sc_flags, URTWN_FLAG_ATTACHED); |
517 | return; | | 518 | return; |
518 | | | 519 | |
519 | fail: | | 520 | fail: |
520 | sc->sc_dying = 1; | | 521 | sc->sc_dying = 1; |
521 | aprint_error_dev(self, "attach failed\n"); | | 522 | aprint_error_dev(self, "attach failed\n"); |
522 | } | | 523 | } |
523 | | | 524 | |
524 | static int | | 525 | static int |
525 | urtwn_detach(device_t self, int flags) | | 526 | urtwn_detach(device_t self, int flags) |
526 | { | | 527 | { |
527 | struct urtwn_softc *sc = device_private(self); | | 528 | struct urtwn_softc *sc = device_private(self); |
528 | struct ifnet *ifp = &sc->sc_if; | | 529 | struct ifnet *ifp = &sc->sc_if; |
529 | int s; | | 530 | int s; |
530 | | | 531 | |
531 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 532 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
532 | | | 533 | |
533 | pmf_device_deregister(self); | | 534 | pmf_device_deregister(self); |
534 | | | 535 | |
535 | s = splusb(); | | 536 | s = splusb(); |
536 | | | 537 | |
537 | sc->sc_dying = 1; | | 538 | sc->sc_dying = 1; |
538 | | | 539 | |
539 | callout_stop(&sc->sc_scan_to); | | 540 | callout_stop(&sc->sc_scan_to); |
540 | callout_stop(&sc->sc_calib_to); | | 541 | callout_stop(&sc->sc_calib_to); |
541 | | | 542 | |
542 | if (ISSET(sc->sc_flags, URTWN_FLAG_ATTACHED)) { | | 543 | if (ISSET(sc->sc_flags, URTWN_FLAG_ATTACHED)) { |
543 | usb_rem_task(sc->sc_udev, &sc->sc_task); | | 544 | usb_rem_task(sc->sc_udev, &sc->sc_task); |
544 | urtwn_stop(ifp, 0); | | 545 | urtwn_stop(ifp, 0); |
545 | | | 546 | |
546 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | | 547 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
547 | bpf_detach(ifp); | | 548 | bpf_detach(ifp); |
548 | ieee80211_ifdetach(&sc->sc_ic); | | 549 | ieee80211_ifdetach(&sc->sc_ic); |
549 | if_detach(ifp); | | 550 | if_detach(ifp); |
550 | | | 551 | |
551 | /* Close Tx/Rx pipes. Abort done by urtwn_stop. */ | | 552 | /* Close Tx/Rx pipes. Abort done by urtwn_stop. */ |
552 | urtwn_close_pipes(sc); | | 553 | urtwn_close_pipes(sc); |
553 | } | | 554 | } |
554 | | | 555 | |
555 | splx(s); | | 556 | splx(s); |
556 | | | 557 | |
557 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); | | 558 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); |
558 | | | 559 | |
559 | callout_destroy(&sc->sc_scan_to); | | 560 | callout_destroy(&sc->sc_scan_to); |
560 | callout_destroy(&sc->sc_calib_to); | | 561 | callout_destroy(&sc->sc_calib_to); |
561 | | | 562 | |
| | | 563 | cv_destroy(&sc->sc_task_cv); |
562 | mutex_destroy(&sc->sc_write_mtx); | | 564 | mutex_destroy(&sc->sc_write_mtx); |
563 | mutex_destroy(&sc->sc_fwcmd_mtx); | | 565 | mutex_destroy(&sc->sc_fwcmd_mtx); |
564 | mutex_destroy(&sc->sc_tx_mtx); | | 566 | mutex_destroy(&sc->sc_tx_mtx); |
565 | mutex_destroy(&sc->sc_rx_mtx); | | 567 | mutex_destroy(&sc->sc_rx_mtx); |
566 | mutex_destroy(&sc->sc_task_mtx); | | 568 | mutex_destroy(&sc->sc_task_mtx); |
567 | | | 569 | |
568 | return 0; | | 570 | return 0; |
569 | } | | 571 | } |
570 | | | 572 | |
571 | static int | | 573 | static int |
572 | urtwn_activate(device_t self, enum devact act) | | 574 | urtwn_activate(device_t self, enum devact act) |
573 | { | | 575 | { |
574 | struct urtwn_softc *sc = device_private(self); | | 576 | struct urtwn_softc *sc = device_private(self); |
575 | | | 577 | |
576 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 578 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
577 | | | 579 | |
578 | switch (act) { | | 580 | switch (act) { |
579 | case DVACT_DEACTIVATE: | | 581 | case DVACT_DEACTIVATE: |
580 | if_deactivate(sc->sc_ic.ic_ifp); | | 582 | if_deactivate(sc->sc_ic.ic_ifp); |
581 | return 0; | | 583 | return 0; |
582 | default: | | 584 | default: |
583 | return EOPNOTSUPP; | | 585 | return EOPNOTSUPP; |
584 | } | | 586 | } |
585 | } | | 587 | } |
586 | | | 588 | |
587 | static int | | 589 | static int |
588 | urtwn_open_pipes(struct urtwn_softc *sc) | | 590 | urtwn_open_pipes(struct urtwn_softc *sc) |
589 | { | | 591 | { |
590 | /* Bulk-out endpoints addresses (from highest to lowest prio). */ | | 592 | /* Bulk-out endpoints addresses (from highest to lowest prio). */ |
591 | static uint8_t epaddr[3]; | | 593 | static uint8_t epaddr[3]; |
592 | static uint8_t rxepaddr[3]; | | 594 | static uint8_t rxepaddr[3]; |
593 | usb_interface_descriptor_t *id; | | 595 | usb_interface_descriptor_t *id; |
594 | usb_endpoint_descriptor_t *ed; | | 596 | usb_endpoint_descriptor_t *ed; |
595 | size_t i, ntx = 0, nrx = 0; | | 597 | size_t i, ntx = 0, nrx = 0; |
596 | int error; | | 598 | int error; |
597 | | | 599 | |
598 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 600 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
599 | | | 601 | |
600 | /* Determine the number of bulk-out pipes. */ | | 602 | /* Determine the number of bulk-out pipes. */ |
601 | id = usbd_get_interface_descriptor(sc->sc_iface); | | 603 | id = usbd_get_interface_descriptor(sc->sc_iface); |
602 | for (i = 0; i < id->bNumEndpoints; i++) { | | 604 | for (i = 0; i < id->bNumEndpoints; i++) { |
603 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | | 605 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); |
604 | if (ed != NULL && | | 606 | if (ed != NULL && |
605 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && | | 607 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && |
606 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) { | | 608 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) { |
607 | epaddr[ntx] = ed->bEndpointAddress; | | 609 | epaddr[ntx] = ed->bEndpointAddress; |
608 | ntx++; | | 610 | ntx++; |
609 | } | | 611 | } |
610 | if (ed != NULL && | | 612 | if (ed != NULL && |
611 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && | | 613 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && |
612 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { | | 614 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { |
613 | rxepaddr[nrx] = ed->bEndpointAddress; | | 615 | rxepaddr[nrx] = ed->bEndpointAddress; |
614 | nrx++; | | 616 | nrx++; |
615 | } | | 617 | } |
616 | } | | 618 | } |
617 | DPRINTFN(DBG_INIT, ("%s: %s: found %zd bulk-out pipes\n", | | 619 | DPRINTFN(DBG_INIT, ("%s: %s: found %zd bulk-out pipes\n", |
618 | device_xname(sc->sc_dev), __func__, ntx)); | | 620 | device_xname(sc->sc_dev), __func__, ntx)); |
619 | if (ntx == 0 || ntx > R92C_MAX_EPOUT) { | | 621 | if (ntx == 0 || ntx > R92C_MAX_EPOUT) { |
620 | aprint_error_dev(sc->sc_dev, | | 622 | aprint_error_dev(sc->sc_dev, |
621 | "%zd: invalid number of Tx bulk pipes\n", ntx); | | 623 | "%zd: invalid number of Tx bulk pipes\n", ntx); |
622 | return EIO; | | 624 | return EIO; |
623 | } | | 625 | } |
624 | sc->rx_npipe = nrx; | | 626 | sc->rx_npipe = nrx; |
625 | sc->tx_npipe = ntx; | | 627 | sc->tx_npipe = ntx; |
626 | | | 628 | |
627 | /* Open bulk-in pipe at address 0x81. */ | | 629 | /* Open bulk-in pipe at address 0x81. */ |
628 | for (i = 0; i < nrx; i++) { | | 630 | for (i = 0; i < nrx; i++) { |
629 | error = usbd_open_pipe(sc->sc_iface, rxepaddr[i], | | 631 | error = usbd_open_pipe(sc->sc_iface, rxepaddr[i], |
630 | USBD_EXCLUSIVE_USE, &sc->rx_pipe[i]); | | 632 | USBD_EXCLUSIVE_USE, &sc->rx_pipe[i]); |
631 | if (error != 0) { | | 633 | if (error != 0) { |
632 | aprint_error_dev(sc->sc_dev, | | 634 | aprint_error_dev(sc->sc_dev, |
633 | "could not open Rx bulk pipe 0x%02x: %d\n", | | 635 | "could not open Rx bulk pipe 0x%02x: %d\n", |
634 | rxepaddr[i], error); | | 636 | rxepaddr[i], error); |
635 | goto fail; | | 637 | goto fail; |
636 | } | | 638 | } |
637 | } | | 639 | } |
638 | | | 640 | |
639 | /* Open bulk-out pipes (up to 3). */ | | 641 | /* Open bulk-out pipes (up to 3). */ |
640 | for (i = 0; i < ntx; i++) { | | 642 | for (i = 0; i < ntx; i++) { |
641 | error = usbd_open_pipe(sc->sc_iface, epaddr[i], | | 643 | error = usbd_open_pipe(sc->sc_iface, epaddr[i], |
642 | USBD_EXCLUSIVE_USE, &sc->tx_pipe[i]); | | 644 | USBD_EXCLUSIVE_USE, &sc->tx_pipe[i]); |
643 | if (error != 0) { | | 645 | if (error != 0) { |
644 | aprint_error_dev(sc->sc_dev, | | 646 | aprint_error_dev(sc->sc_dev, |
645 | "could not open Tx bulk pipe 0x%02x: %d\n", | | 647 | "could not open Tx bulk pipe 0x%02x: %d\n", |
646 | epaddr[i], error); | | 648 | epaddr[i], error); |
647 | goto fail; | | 649 | goto fail; |
648 | } | | 650 | } |
649 | } | | 651 | } |
650 | | | 652 | |
651 | /* Map 802.11 access categories to USB pipes. */ | | 653 | /* Map 802.11 access categories to USB pipes. */ |
652 | sc->ac2idx[WME_AC_BK] = | | 654 | sc->ac2idx[WME_AC_BK] = |
653 | sc->ac2idx[WME_AC_BE] = (ntx == 3) ? 2 : ((ntx == 2) ? 1 : 0); | | 655 | sc->ac2idx[WME_AC_BE] = (ntx == 3) ? 2 : ((ntx == 2) ? 1 : 0); |
654 | sc->ac2idx[WME_AC_VI] = (ntx == 3) ? 1 : 0; | | 656 | sc->ac2idx[WME_AC_VI] = (ntx == 3) ? 1 : 0; |
655 | sc->ac2idx[WME_AC_VO] = 0; /* Always use highest prio. */ | | 657 | sc->ac2idx[WME_AC_VO] = 0; /* Always use highest prio. */ |
656 | | | 658 | |
657 | fail: | | 659 | fail: |
658 | if (error != 0) | | 660 | if (error != 0) |
659 | urtwn_close_pipes(sc); | | 661 | urtwn_close_pipes(sc); |
660 | return error; | | 662 | return error; |
661 | } | | 663 | } |
662 | | | 664 | |
663 | static void | | 665 | static void |
664 | urtwn_close_pipes(struct urtwn_softc *sc) | | 666 | urtwn_close_pipes(struct urtwn_softc *sc) |
665 | { | | 667 | { |
666 | struct usbd_pipe *pipe; | | 668 | struct usbd_pipe *pipe; |
667 | size_t i; | | 669 | size_t i; |
668 | | | 670 | |
669 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 671 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
670 | | | 672 | |
671 | /* Close Rx pipes. */ | | 673 | /* Close Rx pipes. */ |
672 | CTASSERT(sizeof(pipe) == sizeof(void *)); | | 674 | CTASSERT(sizeof(pipe) == sizeof(void *)); |
673 | for (i = 0; i < sc->rx_npipe; i++) { | | 675 | for (i = 0; i < sc->rx_npipe; i++) { |
674 | pipe = atomic_swap_ptr(&sc->rx_pipe[i], NULL); | | 676 | pipe = atomic_swap_ptr(&sc->rx_pipe[i], NULL); |
675 | if (pipe != NULL) { | | 677 | if (pipe != NULL) { |
676 | usbd_close_pipe(pipe); | | 678 | usbd_close_pipe(pipe); |
677 | } | | 679 | } |
678 | } | | 680 | } |
679 | | | 681 | |
680 | /* Close Tx pipes. */ | | 682 | /* Close Tx pipes. */ |
681 | for (i = 0; i < sc->tx_npipe; i++) { | | 683 | for (i = 0; i < sc->tx_npipe; i++) { |
682 | pipe = atomic_swap_ptr(&sc->tx_pipe[i], NULL); | | 684 | pipe = atomic_swap_ptr(&sc->tx_pipe[i], NULL); |
683 | if (pipe != NULL) { | | 685 | if (pipe != NULL) { |
684 | usbd_close_pipe(pipe); | | 686 | usbd_close_pipe(pipe); |
685 | } | | 687 | } |
686 | } | | 688 | } |
687 | } | | 689 | } |
688 | | | 690 | |
689 | static int | | 691 | static int |
690 | urtwn_alloc_rx_list(struct urtwn_softc *sc) | | 692 | urtwn_alloc_rx_list(struct urtwn_softc *sc) |
691 | { | | 693 | { |
692 | struct urtwn_rx_data *data; | | 694 | struct urtwn_rx_data *data; |
693 | size_t i; | | 695 | size_t i; |
694 | int error = 0; | | 696 | int error = 0; |
695 | | | 697 | |
696 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 698 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
697 | | | 699 | |
698 | for (size_t j = 0; j < sc->rx_npipe; j++) { | | 700 | for (size_t j = 0; j < sc->rx_npipe; j++) { |
699 | TAILQ_INIT(&sc->rx_free_list[j]); | | 701 | TAILQ_INIT(&sc->rx_free_list[j]); |
700 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { | | 702 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { |
701 | data = &sc->rx_data[j][i]; | | 703 | data = &sc->rx_data[j][i]; |
702 | | | 704 | |
703 | data->sc = sc; /* Backpointer for callbacks. */ | | 705 | data->sc = sc; /* Backpointer for callbacks. */ |
704 | | | 706 | |
705 | error = usbd_create_xfer(sc->rx_pipe[j], URTWN_RXBUFSZ, | | 707 | error = usbd_create_xfer(sc->rx_pipe[j], URTWN_RXBUFSZ, |
706 | USBD_SHORT_XFER_OK, 0, &data->xfer); | | 708 | USBD_SHORT_XFER_OK, 0, &data->xfer); |
707 | if (error) { | | 709 | if (error) { |
708 | aprint_error_dev(sc->sc_dev, | | 710 | aprint_error_dev(sc->sc_dev, |
709 | "could not allocate xfer\n"); | | 711 | "could not allocate xfer\n"); |
710 | break; | | 712 | break; |
711 | } | | 713 | } |
712 | | | 714 | |
713 | data->buf = usbd_get_buffer(data->xfer); | | 715 | data->buf = usbd_get_buffer(data->xfer); |
714 | TAILQ_INSERT_TAIL(&sc->rx_free_list[j], data, next); | | 716 | TAILQ_INSERT_TAIL(&sc->rx_free_list[j], data, next); |
715 | } | | 717 | } |
716 | } | | 718 | } |
717 | if (error != 0) | | 719 | if (error != 0) |
718 | urtwn_free_rx_list(sc); | | 720 | urtwn_free_rx_list(sc); |
719 | return error; | | 721 | return error; |
720 | } | | 722 | } |
721 | | | 723 | |
722 | static void | | 724 | static void |
723 | urtwn_free_rx_list(struct urtwn_softc *sc) | | 725 | urtwn_free_rx_list(struct urtwn_softc *sc) |
724 | { | | 726 | { |
725 | struct usbd_xfer *xfer; | | 727 | struct usbd_xfer *xfer; |
726 | size_t i; | | 728 | size_t i; |
727 | | | 729 | |
728 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 730 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
729 | | | 731 | |
730 | /* NB: Caller must abort pipe first. */ | | 732 | /* NB: Caller must abort pipe first. */ |
731 | for (size_t j = 0; j < sc->rx_npipe; j++) { | | 733 | for (size_t j = 0; j < sc->rx_npipe; j++) { |
732 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { | | 734 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { |
733 | CTASSERT(sizeof(xfer) == sizeof(void *)); | | 735 | CTASSERT(sizeof(xfer) == sizeof(void *)); |
734 | xfer = atomic_swap_ptr(&sc->rx_data[j][i].xfer, NULL); | | 736 | xfer = atomic_swap_ptr(&sc->rx_data[j][i].xfer, NULL); |
735 | if (xfer != NULL) | | 737 | if (xfer != NULL) |
736 | usbd_destroy_xfer(xfer); | | 738 | usbd_destroy_xfer(xfer); |
737 | } | | 739 | } |
738 | } | | 740 | } |
739 | } | | 741 | } |
740 | | | 742 | |
741 | static int | | 743 | static int |
742 | urtwn_alloc_tx_list(struct urtwn_softc *sc) | | 744 | urtwn_alloc_tx_list(struct urtwn_softc *sc) |
743 | { | | 745 | { |
744 | struct urtwn_tx_data *data; | | 746 | struct urtwn_tx_data *data; |
745 | size_t i; | | 747 | size_t i; |
746 | int error = 0; | | 748 | int error = 0; |
747 | | | 749 | |
748 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 750 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
749 | | | 751 | |
750 | mutex_enter(&sc->sc_tx_mtx); | | 752 | mutex_enter(&sc->sc_tx_mtx); |
751 | for (size_t j = 0; j < sc->tx_npipe; j++) { | | 753 | for (size_t j = 0; j < sc->tx_npipe; j++) { |
752 | TAILQ_INIT(&sc->tx_free_list[j]); | | 754 | TAILQ_INIT(&sc->tx_free_list[j]); |
753 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { | | 755 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { |
754 | data = &sc->tx_data[j][i]; | | 756 | data = &sc->tx_data[j][i]; |
755 | | | 757 | |
756 | data->sc = sc; /* Backpointer for callbacks. */ | | 758 | data->sc = sc; /* Backpointer for callbacks. */ |
757 | data->pidx = j; | | 759 | data->pidx = j; |
758 | | | 760 | |
759 | error = usbd_create_xfer(sc->tx_pipe[j], | | 761 | error = usbd_create_xfer(sc->tx_pipe[j], |
760 | URTWN_TXBUFSZ, USBD_FORCE_SHORT_XFER, 0, | | 762 | URTWN_TXBUFSZ, USBD_FORCE_SHORT_XFER, 0, |
761 | &data->xfer); | | 763 | &data->xfer); |
762 | if (error) { | | 764 | if (error) { |
763 | aprint_error_dev(sc->sc_dev, | | 765 | aprint_error_dev(sc->sc_dev, |
764 | "could not allocate xfer\n"); | | 766 | "could not allocate xfer\n"); |
765 | goto fail; | | 767 | goto fail; |
766 | } | | 768 | } |
767 | | | 769 | |
768 | data->buf = usbd_get_buffer(data->xfer); | | 770 | data->buf = usbd_get_buffer(data->xfer); |
769 | | | 771 | |
770 | /* Append this Tx buffer to our free list. */ | | 772 | /* Append this Tx buffer to our free list. */ |
771 | TAILQ_INSERT_TAIL(&sc->tx_free_list[j], data, next); | | 773 | TAILQ_INSERT_TAIL(&sc->tx_free_list[j], data, next); |
772 | } | | 774 | } |
773 | } | | 775 | } |
774 | mutex_exit(&sc->sc_tx_mtx); | | 776 | mutex_exit(&sc->sc_tx_mtx); |
775 | return 0; | | 777 | return 0; |
776 | | | 778 | |
777 | fail: | | 779 | fail: |
778 | urtwn_free_tx_list(sc); | | 780 | urtwn_free_tx_list(sc); |
779 | mutex_exit(&sc->sc_tx_mtx); | | 781 | mutex_exit(&sc->sc_tx_mtx); |
780 | return error; | | 782 | return error; |
781 | } | | 783 | } |
782 | | | 784 | |
783 | static void | | 785 | static void |
784 | urtwn_free_tx_list(struct urtwn_softc *sc) | | 786 | urtwn_free_tx_list(struct urtwn_softc *sc) |
785 | { | | 787 | { |
786 | struct usbd_xfer *xfer; | | 788 | struct usbd_xfer *xfer; |
787 | size_t i; | | 789 | size_t i; |
788 | | | 790 | |
789 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 791 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
790 | | | 792 | |
791 | /* NB: Caller must abort pipe first. */ | | 793 | /* NB: Caller must abort pipe first. */ |
792 | for (size_t j = 0; j < sc->tx_npipe; j++) { | | 794 | for (size_t j = 0; j < sc->tx_npipe; j++) { |
793 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { | | 795 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) { |
794 | CTASSERT(sizeof(xfer) == sizeof(void *)); | | 796 | CTASSERT(sizeof(xfer) == sizeof(void *)); |
795 | xfer = atomic_swap_ptr(&sc->tx_data[j][i].xfer, NULL); | | 797 | xfer = atomic_swap_ptr(&sc->tx_data[j][i].xfer, NULL); |
796 | if (xfer != NULL) | | 798 | if (xfer != NULL) |
797 | usbd_destroy_xfer(xfer); | | 799 | usbd_destroy_xfer(xfer); |
798 | } | | 800 | } |
799 | } | | 801 | } |
800 | } | | 802 | } |
801 | | | 803 | |
802 | static void | | 804 | static void |
803 | urtwn_task(void *arg) | | 805 | urtwn_task(void *arg) |
804 | { | | 806 | { |
805 | struct urtwn_softc *sc = arg; | | 807 | struct urtwn_softc *sc = arg; |
806 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; | | 808 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; |
807 | struct urtwn_host_cmd *cmd; | | 809 | struct urtwn_host_cmd *cmd; |
808 | int s; | | 810 | int s; |
809 | | | 811 | |
810 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 812 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
811 | | | 813 | |
812 | /* Process host commands. */ | | 814 | /* Process host commands. */ |
813 | s = splusb(); | | 815 | s = splusb(); |
814 | mutex_spin_enter(&sc->sc_task_mtx); | | 816 | mutex_spin_enter(&sc->sc_task_mtx); |
815 | while (ring->next != ring->cur) { | | 817 | while (ring->next != ring->cur) { |
816 | cmd = &ring->cmd[ring->next]; | | 818 | cmd = &ring->cmd[ring->next]; |
817 | mutex_spin_exit(&sc->sc_task_mtx); | | 819 | mutex_spin_exit(&sc->sc_task_mtx); |
818 | splx(s); | | 820 | splx(s); |
819 | /* Invoke callback with kernel lock held. */ | | 821 | /* Invoke callback with kernel lock held. */ |
820 | cmd->cb(sc, cmd->data); | | 822 | cmd->cb(sc, cmd->data); |
821 | s = splusb(); | | 823 | s = splusb(); |
822 | mutex_spin_enter(&sc->sc_task_mtx); | | 824 | mutex_spin_enter(&sc->sc_task_mtx); |
823 | ring->queued--; | | 825 | ring->queued--; |
824 | ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT; | | 826 | ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT; |
825 | } | | 827 | } |
| | | 828 | cv_broadcast(&sc->sc_task_cv); |
826 | mutex_spin_exit(&sc->sc_task_mtx); | | 829 | mutex_spin_exit(&sc->sc_task_mtx); |
827 | wakeup(&sc->cmdq); | | | |
828 | splx(s); | | 830 | splx(s); |
829 | } | | 831 | } |
830 | | | 832 | |
831 | static void | | 833 | static void |
832 | urtwn_do_async(struct urtwn_softc *sc, void (*cb)(struct urtwn_softc *, void *), | | 834 | urtwn_do_async(struct urtwn_softc *sc, void (*cb)(struct urtwn_softc *, void *), |
833 | void *arg, int len) | | 835 | void *arg, int len) |
834 | { | | 836 | { |
835 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; | | 837 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; |
836 | struct urtwn_host_cmd *cmd; | | 838 | struct urtwn_host_cmd *cmd; |
837 | int s; | | 839 | int s; |
838 | | | 840 | |
839 | DPRINTFN(DBG_FN, ("%s: %s: cb=%p, arg=%p, len=%d\n", | | 841 | DPRINTFN(DBG_FN, ("%s: %s: cb=%p, arg=%p, len=%d\n", |
840 | device_xname(sc->sc_dev), __func__, cb, arg, len)); | | 842 | device_xname(sc->sc_dev), __func__, cb, arg, len)); |
841 | | | 843 | |
842 | s = splusb(); | | 844 | s = splusb(); |
843 | mutex_spin_enter(&sc->sc_task_mtx); | | 845 | mutex_spin_enter(&sc->sc_task_mtx); |
844 | cmd = &ring->cmd[ring->cur]; | | 846 | cmd = &ring->cmd[ring->cur]; |
845 | cmd->cb = cb; | | 847 | cmd->cb = cb; |
846 | KASSERT(len <= sizeof(cmd->data)); | | 848 | KASSERT(len <= sizeof(cmd->data)); |
847 | memcpy(cmd->data, arg, len); | | 849 | memcpy(cmd->data, arg, len); |
848 | ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT; | | 850 | ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT; |
849 | | | 851 | |
850 | /* If there is no pending command already, schedule a task. */ | | 852 | /* If there is no pending command already, schedule a task. */ |
851 | if (!sc->sc_dying && ++ring->queued == 1) { | | 853 | if (!sc->sc_dying && ++ring->queued == 1) { |
852 | mutex_spin_exit(&sc->sc_task_mtx); | | 854 | mutex_spin_exit(&sc->sc_task_mtx); |
853 | usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER); | | 855 | usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER); |
854 | } else | | 856 | } else |
855 | mutex_spin_exit(&sc->sc_task_mtx); | | 857 | mutex_spin_exit(&sc->sc_task_mtx); |
856 | splx(s); | | 858 | splx(s); |
857 | } | | 859 | } |
858 | | | 860 | |
859 | static void | | 861 | static void |
860 | urtwn_wait_async(struct urtwn_softc *sc) | | 862 | urtwn_wait_async(struct urtwn_softc *sc) |
861 | { | | 863 | { |
862 | | | 864 | |
863 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 865 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
864 | | | 866 | |
865 | /* Wait for all queued asynchronous commands to complete. */ | | 867 | /* Wait for all queued asynchronous commands to complete. */ |
| | | 868 | mutex_spin_enter(&sc->sc_task_mtx); |
866 | while (sc->cmdq.queued > 0) | | 869 | while (sc->cmdq.queued > 0) |
867 | tsleep(&sc->cmdq, 0, "endtask", 0); | | 870 | cv_wait(&sc->sc_task_cv, &sc->sc_task_mtx); |
| | | 871 | mutex_spin_exit(&sc->sc_task_mtx); |
868 | } | | 872 | } |
869 | | | 873 | |
870 | static int | | 874 | static int |
871 | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | | 875 | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, |
872 | int len) | | 876 | int len) |
873 | { | | 877 | { |
874 | usb_device_request_t req; | | 878 | usb_device_request_t req; |
875 | usbd_status error; | | 879 | usbd_status error; |
876 | | | 880 | |
877 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 881 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
878 | | | 882 | |
879 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | | 883 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
880 | req.bRequest = R92C_REQ_REGS; | | 884 | req.bRequest = R92C_REQ_REGS; |
881 | USETW(req.wValue, addr); | | 885 | USETW(req.wValue, addr); |
882 | USETW(req.wIndex, 0); | | 886 | USETW(req.wIndex, 0); |
883 | USETW(req.wLength, len); | | 887 | USETW(req.wLength, len); |
884 | error = usbd_do_request(sc->sc_udev, &req, buf); | | 888 | error = usbd_do_request(sc->sc_udev, &req, buf); |
885 | if (error != USBD_NORMAL_COMPLETION) { | | 889 | if (error != USBD_NORMAL_COMPLETION) { |
886 | DPRINTFN(DBG_REG, ("%s: %s: error=%d: addr=0x%x, len=%d\n", | | 890 | DPRINTFN(DBG_REG, ("%s: %s: error=%d: addr=0x%x, len=%d\n", |
887 | device_xname(sc->sc_dev), __func__, error, addr, len)); | | 891 | device_xname(sc->sc_dev), __func__, error, addr, len)); |
888 | } | | 892 | } |
889 | return error; | | 893 | return error; |
890 | } | | 894 | } |
891 | | | 895 | |
892 | static void | | 896 | static void |
893 | urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) | | 897 | urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) |
894 | { | | 898 | { |
895 | | | 899 | |
896 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", | | 900 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", |
897 | device_xname(sc->sc_dev), __func__, addr, val)); | | 901 | device_xname(sc->sc_dev), __func__, addr, val)); |
898 | | | 902 | |
899 | urtwn_write_region_1(sc, addr, &val, 1); | | 903 | urtwn_write_region_1(sc, addr, &val, 1); |
900 | } | | 904 | } |
901 | | | 905 | |
902 | static void | | 906 | static void |
903 | urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) | | 907 | urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) |
904 | { | | 908 | { |
905 | uint8_t buf[2]; | | 909 | uint8_t buf[2]; |
906 | | | 910 | |
907 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", | | 911 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", |
908 | device_xname(sc->sc_dev), __func__, addr, val)); | | 912 | device_xname(sc->sc_dev), __func__, addr, val)); |
909 | | | 913 | |
910 | buf[0] = (uint8_t)val; | | 914 | buf[0] = (uint8_t)val; |
911 | buf[1] = (uint8_t)(val >> 8); | | 915 | buf[1] = (uint8_t)(val >> 8); |
912 | urtwn_write_region_1(sc, addr, buf, 2); | | 916 | urtwn_write_region_1(sc, addr, buf, 2); |
913 | } | | 917 | } |
914 | | | 918 | |
915 | static void | | 919 | static void |
916 | urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) | | 920 | urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) |
917 | { | | 921 | { |
918 | uint8_t buf[4]; | | 922 | uint8_t buf[4]; |
919 | | | 923 | |
920 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", | | 924 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", |
921 | device_xname(sc->sc_dev), __func__, addr, val)); | | 925 | device_xname(sc->sc_dev), __func__, addr, val)); |
922 | | | 926 | |
923 | buf[0] = (uint8_t)val; | | 927 | buf[0] = (uint8_t)val; |
924 | buf[1] = (uint8_t)(val >> 8); | | 928 | buf[1] = (uint8_t)(val >> 8); |
925 | buf[2] = (uint8_t)(val >> 16); | | 929 | buf[2] = (uint8_t)(val >> 16); |
926 | buf[3] = (uint8_t)(val >> 24); | | 930 | buf[3] = (uint8_t)(val >> 24); |
927 | urtwn_write_region_1(sc, addr, buf, 4); | | 931 | urtwn_write_region_1(sc, addr, buf, 4); |
928 | } | | 932 | } |
929 | | | 933 | |
930 | static int | | 934 | static int |
931 | urtwn_write_region(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, int len) | | 935 | urtwn_write_region(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, int len) |
932 | { | | 936 | { |
933 | | | 937 | |
934 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, len=0x%x\n", | | 938 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, len=0x%x\n", |
935 | device_xname(sc->sc_dev), __func__, addr, len)); | | 939 | device_xname(sc->sc_dev), __func__, addr, len)); |
936 | | | 940 | |
937 | return urtwn_write_region_1(sc, addr, buf, len); | | 941 | return urtwn_write_region_1(sc, addr, buf, len); |
938 | } | | 942 | } |
939 | | | 943 | |
940 | static int | | 944 | static int |
941 | urtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | | 945 | urtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, |
942 | int len) | | 946 | int len) |
943 | { | | 947 | { |
944 | usb_device_request_t req; | | 948 | usb_device_request_t req; |
945 | usbd_status error; | | 949 | usbd_status error; |
946 | | | 950 | |
947 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | | 951 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
948 | req.bRequest = R92C_REQ_REGS; | | 952 | req.bRequest = R92C_REQ_REGS; |
949 | USETW(req.wValue, addr); | | 953 | USETW(req.wValue, addr); |
950 | USETW(req.wIndex, 0); | | 954 | USETW(req.wIndex, 0); |
951 | USETW(req.wLength, len); | | 955 | USETW(req.wLength, len); |
952 | error = usbd_do_request(sc->sc_udev, &req, buf); | | 956 | error = usbd_do_request(sc->sc_udev, &req, buf); |
953 | if (error != USBD_NORMAL_COMPLETION) { | | 957 | if (error != USBD_NORMAL_COMPLETION) { |
954 | DPRINTFN(DBG_REG, ("%s: %s: error=%d: addr=0x%x, len=%d\n", | | 958 | DPRINTFN(DBG_REG, ("%s: %s: error=%d: addr=0x%x, len=%d\n", |
955 | device_xname(sc->sc_dev), __func__, error, addr, len)); | | 959 | device_xname(sc->sc_dev), __func__, error, addr, len)); |
956 | } | | 960 | } |
957 | return error; | | 961 | return error; |
958 | } | | 962 | } |
959 | | | 963 | |
960 | static uint8_t | | 964 | static uint8_t |
961 | urtwn_read_1(struct urtwn_softc *sc, uint16_t addr) | | 965 | urtwn_read_1(struct urtwn_softc *sc, uint16_t addr) |
962 | { | | 966 | { |
963 | uint8_t val; | | 967 | uint8_t val; |
964 | | | 968 | |
965 | if (urtwn_read_region_1(sc, addr, &val, 1) != USBD_NORMAL_COMPLETION) | | 969 | if (urtwn_read_region_1(sc, addr, &val, 1) != USBD_NORMAL_COMPLETION) |
966 | return 0xff; | | 970 | return 0xff; |
967 | | | 971 | |
968 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", | | 972 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", |
969 | device_xname(sc->sc_dev), __func__, addr, val)); | | 973 | device_xname(sc->sc_dev), __func__, addr, val)); |
970 | return val; | | 974 | return val; |
971 | } | | 975 | } |
972 | | | 976 | |
973 | static uint16_t | | 977 | static uint16_t |
974 | urtwn_read_2(struct urtwn_softc *sc, uint16_t addr) | | 978 | urtwn_read_2(struct urtwn_softc *sc, uint16_t addr) |
975 | { | | 979 | { |
976 | uint8_t buf[2]; | | 980 | uint8_t buf[2]; |
977 | uint16_t val; | | 981 | uint16_t val; |
978 | | | 982 | |
979 | if (urtwn_read_region_1(sc, addr, buf, 2) != USBD_NORMAL_COMPLETION) | | 983 | if (urtwn_read_region_1(sc, addr, buf, 2) != USBD_NORMAL_COMPLETION) |
980 | return 0xffff; | | 984 | return 0xffff; |
981 | | | 985 | |
982 | val = LE_READ_2(&buf[0]); | | 986 | val = LE_READ_2(&buf[0]); |
983 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", | | 987 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", |
984 | device_xname(sc->sc_dev), __func__, addr, val)); | | 988 | device_xname(sc->sc_dev), __func__, addr, val)); |
985 | return val; | | 989 | return val; |
986 | } | | 990 | } |
987 | | | 991 | |
988 | static uint32_t | | 992 | static uint32_t |
989 | urtwn_read_4(struct urtwn_softc *sc, uint16_t addr) | | 993 | urtwn_read_4(struct urtwn_softc *sc, uint16_t addr) |
990 | { | | 994 | { |
991 | uint8_t buf[4]; | | 995 | uint8_t buf[4]; |
992 | uint32_t val; | | 996 | uint32_t val; |
993 | | | 997 | |
994 | if (urtwn_read_region_1(sc, addr, buf, 4) != USBD_NORMAL_COMPLETION) | | 998 | if (urtwn_read_region_1(sc, addr, buf, 4) != USBD_NORMAL_COMPLETION) |
995 | return 0xffffffff; | | 999 | return 0xffffffff; |
996 | | | 1000 | |
997 | val = LE_READ_4(&buf[0]); | | 1001 | val = LE_READ_4(&buf[0]); |
998 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", | | 1002 | DPRINTFN(DBG_REG, ("%s: %s: addr=0x%x, val=0x%x\n", |
999 | device_xname(sc->sc_dev), __func__, addr, val)); | | 1003 | device_xname(sc->sc_dev), __func__, addr, val)); |
1000 | return val; | | 1004 | return val; |
1001 | } | | 1005 | } |
1002 | | | 1006 | |
1003 | static int | | 1007 | static int |
1004 | urtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len) | | 1008 | urtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len) |
1005 | { | | 1009 | { |
1006 | struct r92c_fw_cmd cmd; | | 1010 | struct r92c_fw_cmd cmd; |
1007 | uint8_t *cp; | | 1011 | uint8_t *cp; |
1008 | int fwcur; | | 1012 | int fwcur; |
1009 | int ntries; | | 1013 | int ntries; |
1010 | | | 1014 | |
1011 | DPRINTFN(DBG_REG, ("%s: %s: id=%d, buf=%p, len=%d\n", | | 1015 | DPRINTFN(DBG_REG, ("%s: %s: id=%d, buf=%p, len=%d\n", |
1012 | device_xname(sc->sc_dev), __func__, id, buf, len)); | | 1016 | device_xname(sc->sc_dev), __func__, id, buf, len)); |
1013 | | | 1017 | |
1014 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1018 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1015 | | | 1019 | |
1016 | mutex_enter(&sc->sc_fwcmd_mtx); | | 1020 | mutex_enter(&sc->sc_fwcmd_mtx); |
1017 | fwcur = sc->fwcur; | | 1021 | fwcur = sc->fwcur; |
1018 | sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; | | 1022 | sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; |
1019 | mutex_exit(&sc->sc_fwcmd_mtx); | | 1023 | mutex_exit(&sc->sc_fwcmd_mtx); |
1020 | | | 1024 | |
1021 | /* Wait for current FW box to be empty. */ | | 1025 | /* Wait for current FW box to be empty. */ |
1022 | for (ntries = 0; ntries < 100; ntries++) { | | 1026 | for (ntries = 0; ntries < 100; ntries++) { |
1023 | if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << fwcur))) | | 1027 | if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << fwcur))) |
1024 | break; | | 1028 | break; |
1025 | DELAY(10); | | 1029 | DELAY(10); |
1026 | } | | 1030 | } |
1027 | if (ntries == 100) { | | 1031 | if (ntries == 100) { |
1028 | aprint_error_dev(sc->sc_dev, | | 1032 | aprint_error_dev(sc->sc_dev, |
1029 | "could not send firmware command %d\n", id); | | 1033 | "could not send firmware command %d\n", id); |
1030 | return ETIMEDOUT; | | 1034 | return ETIMEDOUT; |
1031 | } | | 1035 | } |
1032 | | | 1036 | |
1033 | memset(&cmd, 0, sizeof(cmd)); | | 1037 | memset(&cmd, 0, sizeof(cmd)); |
1034 | KASSERT(len <= sizeof(cmd.msg)); | | 1038 | KASSERT(len <= sizeof(cmd.msg)); |
1035 | memcpy(cmd.msg, buf, len); | | 1039 | memcpy(cmd.msg, buf, len); |
1036 | | | 1040 | |
1037 | /* Write the first word last since that will trigger the FW. */ | | 1041 | /* Write the first word last since that will trigger the FW. */ |
1038 | cp = (uint8_t *)&cmd; | | 1042 | cp = (uint8_t *)&cmd; |
1039 | cmd.id = id; | | 1043 | cmd.id = id; |
1040 | if (len >= 4) { | | 1044 | if (len >= 4) { |
1041 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 1045 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { |
1042 | cmd.id |= R92C_CMD_FLAG_EXT; | | 1046 | cmd.id |= R92C_CMD_FLAG_EXT; |
1043 | urtwn_write_region(sc, R92C_HMEBOX_EXT(fwcur), | | 1047 | urtwn_write_region(sc, R92C_HMEBOX_EXT(fwcur), |
1044 | &cp[1], 2); | | 1048 | &cp[1], 2); |
1045 | urtwn_write_4(sc, R92C_HMEBOX(fwcur), | | 1049 | urtwn_write_4(sc, R92C_HMEBOX(fwcur), |
1046 | cp[0] + (cp[3] << 8) + (cp[4] << 16) + | | 1050 | cp[0] + (cp[3] << 8) + (cp[4] << 16) + |
1047 | (cp[5] << 24)); | | 1051 | (cp[5] << 24)); |
1048 | } else { | | 1052 | } else { |
1049 | urtwn_write_region(sc, R92E_HMEBOX_EXT(fwcur), | | 1053 | urtwn_write_region(sc, R92E_HMEBOX_EXT(fwcur), |
1050 | &cp[4], 2); | | 1054 | &cp[4], 2); |
1051 | urtwn_write_4(sc, R92C_HMEBOX(fwcur), | | 1055 | urtwn_write_4(sc, R92C_HMEBOX(fwcur), |
1052 | cp[0] + (cp[1] << 8) + (cp[2] << 16) + | | 1056 | cp[0] + (cp[1] << 8) + (cp[2] << 16) + |
1053 | (cp[3] << 24)); | | 1057 | (cp[3] << 24)); |
1054 | } | | 1058 | } |
1055 | } else { | | 1059 | } else { |
1056 | urtwn_write_region(sc, R92C_HMEBOX(fwcur), cp, len); | | 1060 | urtwn_write_region(sc, R92C_HMEBOX(fwcur), cp, len); |
1057 | } | | 1061 | } |
1058 | | | 1062 | |
1059 | return 0; | | 1063 | return 0; |
1060 | } | | 1064 | } |
1061 | | | 1065 | |
1062 | static __inline void | | 1066 | static __inline void |
1063 | urtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val) | | 1067 | urtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val) |
1064 | { | | 1068 | { |
1065 | | | 1069 | |
1066 | sc->sc_rf_write(sc, chain, addr, val); | | 1070 | sc->sc_rf_write(sc, chain, addr, val); |
1067 | } | | 1071 | } |
1068 | | | 1072 | |
1069 | static void | | 1073 | static void |
1070 | urtwn_r92c_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, | | 1074 | urtwn_r92c_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, |
1071 | uint32_t val) | | 1075 | uint32_t val) |
1072 | { | | 1076 | { |
1073 | | | 1077 | |
1074 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), | | 1078 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), |
1075 | SM(R92C_LSSI_PARAM_ADDR, addr) | SM(R92C_LSSI_PARAM_DATA, val)); | | 1079 | SM(R92C_LSSI_PARAM_ADDR, addr) | SM(R92C_LSSI_PARAM_DATA, val)); |
1076 | } | | 1080 | } |
1077 | | | 1081 | |
1078 | static void | | 1082 | static void |
1079 | urtwn_r88e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, | | 1083 | urtwn_r88e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, |
1080 | uint32_t val) | | 1084 | uint32_t val) |
1081 | { | | 1085 | { |
1082 | | | 1086 | |
1083 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), | | 1087 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), |
1084 | SM(R88E_LSSI_PARAM_ADDR, addr) | SM(R92C_LSSI_PARAM_DATA, val)); | | 1088 | SM(R88E_LSSI_PARAM_ADDR, addr) | SM(R92C_LSSI_PARAM_DATA, val)); |
1085 | } | | 1089 | } |
1086 | | | 1090 | |
1087 | static void | | 1091 | static void |
1088 | urtwn_r92e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, | | 1092 | urtwn_r92e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, |
1089 | uint32_t val) | | 1093 | uint32_t val) |
1090 | { | | 1094 | { |
1091 | | | 1095 | |
1092 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), | | 1096 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), |
1093 | SM(R88E_LSSI_PARAM_ADDR, addr) | SM(R92C_LSSI_PARAM_DATA, val)); | | 1097 | SM(R88E_LSSI_PARAM_ADDR, addr) | SM(R92C_LSSI_PARAM_DATA, val)); |
1094 | } | | 1098 | } |
1095 | | | 1099 | |
1096 | static uint32_t | | 1100 | static uint32_t |
1097 | urtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr) | | 1101 | urtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr) |
1098 | { | | 1102 | { |
1099 | uint32_t reg[R92C_MAX_CHAINS], val; | | 1103 | uint32_t reg[R92C_MAX_CHAINS], val; |
1100 | | | 1104 | |
1101 | reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); | | 1105 | reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); |
1102 | if (chain != 0) { | | 1106 | if (chain != 0) { |
1103 | reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); | | 1107 | reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); |
1104 | } | | 1108 | } |
1105 | | | 1109 | |
1106 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), | | 1110 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), |
1107 | reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); | | 1111 | reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); |
1108 | DELAY(1000); | | 1112 | DELAY(1000); |
1109 | | | 1113 | |
1110 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), | | 1114 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), |
1111 | RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | | | 1115 | RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | |
1112 | R92C_HSSI_PARAM2_READ_EDGE); | | 1116 | R92C_HSSI_PARAM2_READ_EDGE); |
1113 | DELAY(1000); | | 1117 | DELAY(1000); |
1114 | | | 1118 | |
1115 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), | | 1119 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), |
1116 | reg[0] | R92C_HSSI_PARAM2_READ_EDGE); | | 1120 | reg[0] | R92C_HSSI_PARAM2_READ_EDGE); |
1117 | DELAY(1000); | | 1121 | DELAY(1000); |
1118 | | | 1122 | |
1119 | if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) { | | 1123 | if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) { |
1120 | val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); | | 1124 | val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); |
1121 | } else { | | 1125 | } else { |
1122 | val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); | | 1126 | val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); |
1123 | } | | 1127 | } |
1124 | return MS(val, R92C_LSSI_READBACK_DATA); | | 1128 | return MS(val, R92C_LSSI_READBACK_DATA); |
1125 | } | | 1129 | } |
1126 | | | 1130 | |
1127 | static int | | 1131 | static int |
1128 | urtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) | | 1132 | urtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) |
1129 | { | | 1133 | { |
1130 | int ntries; | | 1134 | int ntries; |
1131 | | | 1135 | |
1132 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1136 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1133 | | | 1137 | |
1134 | urtwn_write_4(sc, R92C_LLT_INIT, | | 1138 | urtwn_write_4(sc, R92C_LLT_INIT, |
1135 | SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | | | 1139 | SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | |
1136 | SM(R92C_LLT_INIT_ADDR, addr) | | | 1140 | SM(R92C_LLT_INIT_ADDR, addr) | |
1137 | SM(R92C_LLT_INIT_DATA, data)); | | 1141 | SM(R92C_LLT_INIT_DATA, data)); |
1138 | /* Wait for write operation to complete. */ | | 1142 | /* Wait for write operation to complete. */ |
1139 | for (ntries = 0; ntries < 20; ntries++) { | | 1143 | for (ntries = 0; ntries < 20; ntries++) { |
1140 | if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == | | 1144 | if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == |
1141 | R92C_LLT_INIT_OP_NO_ACTIVE) { | | 1145 | R92C_LLT_INIT_OP_NO_ACTIVE) { |
1142 | /* Done */ | | 1146 | /* Done */ |
1143 | return 0; | | 1147 | return 0; |
1144 | } | | 1148 | } |
1145 | DELAY(5); | | 1149 | DELAY(5); |
1146 | } | | 1150 | } |
1147 | return ETIMEDOUT; | | 1151 | return ETIMEDOUT; |
1148 | } | | 1152 | } |
1149 | | | 1153 | |
1150 | static uint8_t | | 1154 | static uint8_t |
1151 | urtwn_efuse_read_1(struct urtwn_softc *sc, uint16_t addr) | | 1155 | urtwn_efuse_read_1(struct urtwn_softc *sc, uint16_t addr) |
1152 | { | | 1156 | { |
1153 | uint32_t reg; | | 1157 | uint32_t reg; |
1154 | int ntries; | | 1158 | int ntries; |
1155 | | | 1159 | |
1156 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1160 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1157 | | | 1161 | |
1158 | reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); | | 1162 | reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); |
1159 | reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr); | | 1163 | reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr); |
1160 | reg &= ~R92C_EFUSE_CTRL_VALID; | | 1164 | reg &= ~R92C_EFUSE_CTRL_VALID; |
1161 | urtwn_write_4(sc, R92C_EFUSE_CTRL, reg); | | 1165 | urtwn_write_4(sc, R92C_EFUSE_CTRL, reg); |
1162 | | | 1166 | |
1163 | /* Wait for read operation to complete. */ | | 1167 | /* Wait for read operation to complete. */ |
1164 | for (ntries = 0; ntries < 100; ntries++) { | | 1168 | for (ntries = 0; ntries < 100; ntries++) { |
1165 | reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); | | 1169 | reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); |
1166 | if (reg & R92C_EFUSE_CTRL_VALID) { | | 1170 | if (reg & R92C_EFUSE_CTRL_VALID) { |
1167 | /* Done */ | | 1171 | /* Done */ |
1168 | return MS(reg, R92C_EFUSE_CTRL_DATA); | | 1172 | return MS(reg, R92C_EFUSE_CTRL_DATA); |
1169 | } | | 1173 | } |
1170 | DELAY(5); | | 1174 | DELAY(5); |
1171 | } | | 1175 | } |
1172 | aprint_error_dev(sc->sc_dev, | | 1176 | aprint_error_dev(sc->sc_dev, |
1173 | "could not read efuse byte at address 0x%04x\n", addr); | | 1177 | "could not read efuse byte at address 0x%04x\n", addr); |
1174 | return 0xff; | | 1178 | return 0xff; |
1175 | } | | 1179 | } |
1176 | | | 1180 | |
1177 | static void | | 1181 | static void |
1178 | urtwn_efuse_read(struct urtwn_softc *sc) | | 1182 | urtwn_efuse_read(struct urtwn_softc *sc) |
1179 | { | | 1183 | { |
1180 | uint8_t *rom = (uint8_t *)&sc->rom; | | 1184 | uint8_t *rom = (uint8_t *)&sc->rom; |
1181 | uint32_t reg; | | 1185 | uint32_t reg; |
1182 | uint16_t addr = 0; | | 1186 | uint16_t addr = 0; |
1183 | uint8_t off, msk; | | 1187 | uint8_t off, msk; |
1184 | size_t i; | | 1188 | size_t i; |
1185 | | | 1189 | |
1186 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1190 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1187 | | | 1191 | |
1188 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1192 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1189 | | | 1193 | |
1190 | urtwn_efuse_switch_power(sc); | | 1194 | urtwn_efuse_switch_power(sc); |
1191 | | | 1195 | |
1192 | memset(&sc->rom, 0xff, sizeof(sc->rom)); | | 1196 | memset(&sc->rom, 0xff, sizeof(sc->rom)); |
1193 | while (addr < 512) { | | 1197 | while (addr < 512) { |
1194 | reg = urtwn_efuse_read_1(sc, addr); | | 1198 | reg = urtwn_efuse_read_1(sc, addr); |
1195 | if (reg == 0xff) | | 1199 | if (reg == 0xff) |
1196 | break; | | 1200 | break; |
1197 | addr++; | | 1201 | addr++; |
1198 | off = reg >> 4; | | 1202 | off = reg >> 4; |
1199 | msk = reg & 0xf; | | 1203 | msk = reg & 0xf; |
1200 | for (i = 0; i < 4; i++) { | | 1204 | for (i = 0; i < 4; i++) { |
1201 | if (msk & (1U << i)) | | 1205 | if (msk & (1U << i)) |
1202 | continue; | | 1206 | continue; |
1203 | | | 1207 | |
1204 | rom[off * 8 + i * 2 + 0] = urtwn_efuse_read_1(sc, addr); | | 1208 | rom[off * 8 + i * 2 + 0] = urtwn_efuse_read_1(sc, addr); |
1205 | addr++; | | 1209 | addr++; |
1206 | rom[off * 8 + i * 2 + 1] = urtwn_efuse_read_1(sc, addr); | | 1210 | rom[off * 8 + i * 2 + 1] = urtwn_efuse_read_1(sc, addr); |
1207 | addr++; | | 1211 | addr++; |
1208 | } | | 1212 | } |
1209 | } | | 1213 | } |
1210 | #ifdef URTWN_DEBUG | | 1214 | #ifdef URTWN_DEBUG |
1211 | if (urtwn_debug & DBG_INIT) { | | 1215 | if (urtwn_debug & DBG_INIT) { |
1212 | /* Dump ROM content. */ | | 1216 | /* Dump ROM content. */ |
1213 | printf("%s: %s", device_xname(sc->sc_dev), __func__); | | 1217 | printf("%s: %s", device_xname(sc->sc_dev), __func__); |
1214 | for (i = 0; i < (int)sizeof(sc->rom); i++) | | 1218 | for (i = 0; i < (int)sizeof(sc->rom); i++) |
1215 | printf(":%02x", rom[i]); | | 1219 | printf(":%02x", rom[i]); |
1216 | printf("\n"); | | 1220 | printf("\n"); |
1217 | } | | 1221 | } |
1218 | #endif | | 1222 | #endif |
1219 | } | | 1223 | } |
1220 | | | 1224 | |
1221 | static void | | 1225 | static void |
1222 | urtwn_efuse_switch_power(struct urtwn_softc *sc) | | 1226 | urtwn_efuse_switch_power(struct urtwn_softc *sc) |
1223 | { | | 1227 | { |
1224 | uint32_t reg; | | 1228 | uint32_t reg; |
1225 | | | 1229 | |
1226 | reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL); | | 1230 | reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL); |
1227 | if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { | | 1231 | if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { |
1228 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL, | | 1232 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL, |
1229 | reg | R92C_SYS_ISO_CTRL_PWC_EV12V); | | 1233 | reg | R92C_SYS_ISO_CTRL_PWC_EV12V); |
1230 | } | | 1234 | } |
1231 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); | | 1235 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); |
1232 | if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { | | 1236 | if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { |
1233 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, | | 1237 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, |
1234 | reg | R92C_SYS_FUNC_EN_ELDR); | | 1238 | reg | R92C_SYS_FUNC_EN_ELDR); |
1235 | } | | 1239 | } |
1236 | reg = urtwn_read_2(sc, R92C_SYS_CLKR); | | 1240 | reg = urtwn_read_2(sc, R92C_SYS_CLKR); |
1237 | if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != | | 1241 | if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != |
1238 | (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { | | 1242 | (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { |
1239 | urtwn_write_2(sc, R92C_SYS_CLKR, | | 1243 | urtwn_write_2(sc, R92C_SYS_CLKR, |
1240 | reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); | | 1244 | reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); |
1241 | } | | 1245 | } |
1242 | } | | 1246 | } |
1243 | | | 1247 | |
1244 | static int | | 1248 | static int |
1245 | urtwn_read_chipid(struct urtwn_softc *sc) | | 1249 | urtwn_read_chipid(struct urtwn_softc *sc) |
1246 | { | | 1250 | { |
1247 | uint32_t reg; | | 1251 | uint32_t reg; |
1248 | | | 1252 | |
1249 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1253 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1250 | | | 1254 | |
1251 | if (ISSET(sc->chip, URTWN_CHIP_88E) || | | 1255 | if (ISSET(sc->chip, URTWN_CHIP_88E) || |
1252 | ISSET(sc->chip, URTWN_CHIP_92EU)) | | 1256 | ISSET(sc->chip, URTWN_CHIP_92EU)) |
1253 | return 0; | | 1257 | return 0; |
1254 | | | 1258 | |
1255 | reg = urtwn_read_4(sc, R92C_SYS_CFG); | | 1259 | reg = urtwn_read_4(sc, R92C_SYS_CFG); |
1256 | if (reg & R92C_SYS_CFG_TRP_VAUX_EN) { | | 1260 | if (reg & R92C_SYS_CFG_TRP_VAUX_EN) { |
1257 | /* test chip, not supported */ | | 1261 | /* test chip, not supported */ |
1258 | return EIO; | | 1262 | return EIO; |
1259 | } | | 1263 | } |
1260 | if (reg & R92C_SYS_CFG_TYPE_92C) { | | 1264 | if (reg & R92C_SYS_CFG_TYPE_92C) { |
1261 | sc->chip |= URTWN_CHIP_92C; | | 1265 | sc->chip |= URTWN_CHIP_92C; |
1262 | /* Check if it is a castrated 8192C. */ | | 1266 | /* Check if it is a castrated 8192C. */ |
1263 | if (MS(urtwn_read_4(sc, R92C_HPON_FSM), | | 1267 | if (MS(urtwn_read_4(sc, R92C_HPON_FSM), |
1264 | R92C_HPON_FSM_CHIP_BONDING_ID) == | | 1268 | R92C_HPON_FSM_CHIP_BONDING_ID) == |
1265 | R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) { | | 1269 | R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) { |
1266 | sc->chip |= URTWN_CHIP_92C_1T2R; | | 1270 | sc->chip |= URTWN_CHIP_92C_1T2R; |
1267 | } | | 1271 | } |
1268 | } | | 1272 | } |
1269 | if (reg & R92C_SYS_CFG_VENDOR_UMC) { | | 1273 | if (reg & R92C_SYS_CFG_VENDOR_UMC) { |
1270 | sc->chip |= URTWN_CHIP_UMC; | | 1274 | sc->chip |= URTWN_CHIP_UMC; |
1271 | if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) { | | 1275 | if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) { |
1272 | sc->chip |= URTWN_CHIP_UMC_A_CUT; | | 1276 | sc->chip |= URTWN_CHIP_UMC_A_CUT; |
1273 | } | | 1277 | } |
1274 | } | | 1278 | } |
1275 | return 0; | | 1279 | return 0; |
1276 | } | | 1280 | } |
1277 | | | 1281 | |
1278 | #ifdef URTWN_DEBUG | | 1282 | #ifdef URTWN_DEBUG |
1279 | static void | | 1283 | static void |
1280 | urtwn_dump_rom(struct urtwn_softc *sc, struct r92c_rom *rp) | | 1284 | urtwn_dump_rom(struct urtwn_softc *sc, struct r92c_rom *rp) |
1281 | { | | 1285 | { |
1282 | | | 1286 | |
1283 | aprint_normal_dev(sc->sc_dev, | | 1287 | aprint_normal_dev(sc->sc_dev, |
1284 | "id 0x%04x, dbg_sel 0x%x, vid 0x%x, pid 0x%x\n", | | 1288 | "id 0x%04x, dbg_sel 0x%x, vid 0x%x, pid 0x%x\n", |
1285 | rp->id, rp->dbg_sel, rp->vid, rp->pid); | | 1289 | rp->id, rp->dbg_sel, rp->vid, rp->pid); |
1286 | | | 1290 | |
1287 | aprint_normal_dev(sc->sc_dev, | | 1291 | aprint_normal_dev(sc->sc_dev, |
1288 | "usb_opt 0x%x, ep_setting 0x%x, usb_phy 0x%x\n", | | 1292 | "usb_opt 0x%x, ep_setting 0x%x, usb_phy 0x%x\n", |
1289 | rp->usb_opt, rp->ep_setting, rp->usb_phy); | | 1293 | rp->usb_opt, rp->ep_setting, rp->usb_phy); |
1290 | | | 1294 | |
1291 | aprint_normal_dev(sc->sc_dev, | | 1295 | aprint_normal_dev(sc->sc_dev, |
1292 | "macaddr %02x:%02x:%02x:%02x:%02x:%02x\n", | | 1296 | "macaddr %02x:%02x:%02x:%02x:%02x:%02x\n", |
1293 | rp->macaddr[0], rp->macaddr[1], | | 1297 | rp->macaddr[0], rp->macaddr[1], |
1294 | rp->macaddr[2], rp->macaddr[3], | | 1298 | rp->macaddr[2], rp->macaddr[3], |
1295 | rp->macaddr[4], rp->macaddr[5]); | | 1299 | rp->macaddr[4], rp->macaddr[5]); |
1296 | | | 1300 | |
1297 | aprint_normal_dev(sc->sc_dev, | | 1301 | aprint_normal_dev(sc->sc_dev, |
1298 | "string %s, subcustomer_id 0x%x\n", | | 1302 | "string %s, subcustomer_id 0x%x\n", |
1299 | rp->string, rp->subcustomer_id); | | 1303 | rp->string, rp->subcustomer_id); |
1300 | | | 1304 | |
1301 | aprint_normal_dev(sc->sc_dev, | | 1305 | aprint_normal_dev(sc->sc_dev, |
1302 | "cck_tx_pwr c0: %d %d %d, c1: %d %d %d\n", | | 1306 | "cck_tx_pwr c0: %d %d %d, c1: %d %d %d\n", |
1303 | rp->cck_tx_pwr[0][0], rp->cck_tx_pwr[0][1], rp->cck_tx_pwr[0][2], | | 1307 | rp->cck_tx_pwr[0][0], rp->cck_tx_pwr[0][1], rp->cck_tx_pwr[0][2], |
1304 | rp->cck_tx_pwr[1][0], rp->cck_tx_pwr[1][1], rp->cck_tx_pwr[1][2]); | | 1308 | rp->cck_tx_pwr[1][0], rp->cck_tx_pwr[1][1], rp->cck_tx_pwr[1][2]); |
1305 | | | 1309 | |
1306 | aprint_normal_dev(sc->sc_dev, | | 1310 | aprint_normal_dev(sc->sc_dev, |
1307 | "ht40_1s_tx_pwr c0 %d %d %d, c1 %d %d %d\n", | | 1311 | "ht40_1s_tx_pwr c0 %d %d %d, c1 %d %d %d\n", |
1308 | rp->ht40_1s_tx_pwr[0][0], rp->ht40_1s_tx_pwr[0][1], | | 1312 | rp->ht40_1s_tx_pwr[0][0], rp->ht40_1s_tx_pwr[0][1], |
1309 | rp->ht40_1s_tx_pwr[0][2], | | 1313 | rp->ht40_1s_tx_pwr[0][2], |
1310 | rp->ht40_1s_tx_pwr[1][0], rp->ht40_1s_tx_pwr[1][1], | | 1314 | rp->ht40_1s_tx_pwr[1][0], rp->ht40_1s_tx_pwr[1][1], |
1311 | rp->ht40_1s_tx_pwr[1][2]); | | 1315 | rp->ht40_1s_tx_pwr[1][2]); |
1312 | | | 1316 | |
1313 | aprint_normal_dev(sc->sc_dev, | | 1317 | aprint_normal_dev(sc->sc_dev, |
1314 | "ht40_2s_tx_pwr_diff c0: %d %d %d, c1: %d %d %d\n", | | 1318 | "ht40_2s_tx_pwr_diff c0: %d %d %d, c1: %d %d %d\n", |
1315 | rp->ht40_2s_tx_pwr_diff[0] & 0xf, rp->ht40_2s_tx_pwr_diff[1] & 0xf, | | 1319 | rp->ht40_2s_tx_pwr_diff[0] & 0xf, rp->ht40_2s_tx_pwr_diff[1] & 0xf, |
1316 | rp->ht40_2s_tx_pwr_diff[2] & 0xf, | | 1320 | rp->ht40_2s_tx_pwr_diff[2] & 0xf, |
1317 | rp->ht40_2s_tx_pwr_diff[0] >> 4, rp->ht40_2s_tx_pwr_diff[1] & 0xf, | | 1321 | rp->ht40_2s_tx_pwr_diff[0] >> 4, rp->ht40_2s_tx_pwr_diff[1] & 0xf, |
1318 | rp->ht40_2s_tx_pwr_diff[2] >> 4); | | 1322 | rp->ht40_2s_tx_pwr_diff[2] >> 4); |
1319 | | | 1323 | |
1320 | aprint_normal_dev(sc->sc_dev, | | 1324 | aprint_normal_dev(sc->sc_dev, |
1321 | "ht20_tx_pwr_diff c0: %d %d %d, c1: %d %d %d\n", | | 1325 | "ht20_tx_pwr_diff c0: %d %d %d, c1: %d %d %d\n", |
1322 | rp->ht20_tx_pwr_diff[0] & 0xf, rp->ht20_tx_pwr_diff[1] & 0xf, | | 1326 | rp->ht20_tx_pwr_diff[0] & 0xf, rp->ht20_tx_pwr_diff[1] & 0xf, |
1323 | rp->ht20_tx_pwr_diff[2] & 0xf, | | 1327 | rp->ht20_tx_pwr_diff[2] & 0xf, |
1324 | rp->ht20_tx_pwr_diff[0] >> 4, rp->ht20_tx_pwr_diff[1] >> 4, | | 1328 | rp->ht20_tx_pwr_diff[0] >> 4, rp->ht20_tx_pwr_diff[1] >> 4, |
1325 | rp->ht20_tx_pwr_diff[2] >> 4); | | 1329 | rp->ht20_tx_pwr_diff[2] >> 4); |
1326 | | | 1330 | |
1327 | aprint_normal_dev(sc->sc_dev, | | 1331 | aprint_normal_dev(sc->sc_dev, |
1328 | "ofdm_tx_pwr_diff c0: %d %d %d, c1: %d %d %d\n", | | 1332 | "ofdm_tx_pwr_diff c0: %d %d %d, c1: %d %d %d\n", |
1329 | rp->ofdm_tx_pwr_diff[0] & 0xf, rp->ofdm_tx_pwr_diff[1] & 0xf, | | 1333 | rp->ofdm_tx_pwr_diff[0] & 0xf, rp->ofdm_tx_pwr_diff[1] & 0xf, |
1330 | rp->ofdm_tx_pwr_diff[2] & 0xf, | | 1334 | rp->ofdm_tx_pwr_diff[2] & 0xf, |
1331 | rp->ofdm_tx_pwr_diff[0] >> 4, rp->ofdm_tx_pwr_diff[1] >> 4, | | 1335 | rp->ofdm_tx_pwr_diff[0] >> 4, rp->ofdm_tx_pwr_diff[1] >> 4, |
1332 | rp->ofdm_tx_pwr_diff[2] >> 4); | | 1336 | rp->ofdm_tx_pwr_diff[2] >> 4); |
1333 | | | 1337 | |
1334 | aprint_normal_dev(sc->sc_dev, | | 1338 | aprint_normal_dev(sc->sc_dev, |
1335 | "ht40_max_pwr_offset c0: %d %d %d, c1: %d %d %d\n", | | 1339 | "ht40_max_pwr_offset c0: %d %d %d, c1: %d %d %d\n", |
1336 | rp->ht40_max_pwr[0] & 0xf, rp->ht40_max_pwr[1] & 0xf, | | 1340 | rp->ht40_max_pwr[0] & 0xf, rp->ht40_max_pwr[1] & 0xf, |
1337 | rp->ht40_max_pwr[2] & 0xf, | | 1341 | rp->ht40_max_pwr[2] & 0xf, |
1338 | rp->ht40_max_pwr[0] >> 4, rp->ht40_max_pwr[1] >> 4, | | 1342 | rp->ht40_max_pwr[0] >> 4, rp->ht40_max_pwr[1] >> 4, |
1339 | rp->ht40_max_pwr[2] >> 4); | | 1343 | rp->ht40_max_pwr[2] >> 4); |
1340 | | | 1344 | |
1341 | aprint_normal_dev(sc->sc_dev, | | 1345 | aprint_normal_dev(sc->sc_dev, |
1342 | "ht20_max_pwr_offset c0: %d %d %d, c1: %d %d %d\n", | | 1346 | "ht20_max_pwr_offset c0: %d %d %d, c1: %d %d %d\n", |
1343 | rp->ht20_max_pwr[0] & 0xf, rp->ht20_max_pwr[1] & 0xf, | | 1347 | rp->ht20_max_pwr[0] & 0xf, rp->ht20_max_pwr[1] & 0xf, |
1344 | rp->ht20_max_pwr[2] & 0xf, | | 1348 | rp->ht20_max_pwr[2] & 0xf, |
1345 | rp->ht20_max_pwr[0] >> 4, rp->ht20_max_pwr[1] >> 4, | | 1349 | rp->ht20_max_pwr[0] >> 4, rp->ht20_max_pwr[1] >> 4, |
1346 | rp->ht20_max_pwr[2] >> 4); | | 1350 | rp->ht20_max_pwr[2] >> 4); |
1347 | | | 1351 | |
1348 | aprint_normal_dev(sc->sc_dev, | | 1352 | aprint_normal_dev(sc->sc_dev, |
1349 | "xtal_calib %d, tssi %d %d, thermal %d\n", | | 1353 | "xtal_calib %d, tssi %d %d, thermal %d\n", |
1350 | rp->xtal_calib, rp->tssi[0], rp->tssi[1], rp->thermal_meter); | | 1354 | rp->xtal_calib, rp->tssi[0], rp->tssi[1], rp->thermal_meter); |
1351 | | | 1355 | |
1352 | aprint_normal_dev(sc->sc_dev, | | 1356 | aprint_normal_dev(sc->sc_dev, |
1353 | "rf_opt1 0x%x, rf_opt2 0x%x, rf_opt3 0x%x, rf_opt4 0x%x\n", | | 1357 | "rf_opt1 0x%x, rf_opt2 0x%x, rf_opt3 0x%x, rf_opt4 0x%x\n", |
1354 | rp->rf_opt1, rp->rf_opt2, rp->rf_opt3, rp->rf_opt4); | | 1358 | rp->rf_opt1, rp->rf_opt2, rp->rf_opt3, rp->rf_opt4); |
1355 | | | 1359 | |
1356 | aprint_normal_dev(sc->sc_dev, | | 1360 | aprint_normal_dev(sc->sc_dev, |
1357 | "channnel_plan %d, version %d customer_id 0x%x\n", | | 1361 | "channnel_plan %d, version %d customer_id 0x%x\n", |
1358 | rp->channel_plan, rp->version, rp->curstomer_id); | | 1362 | rp->channel_plan, rp->version, rp->curstomer_id); |
1359 | } | | 1363 | } |
1360 | #endif | | 1364 | #endif |
1361 | | | 1365 | |
1362 | static void | | 1366 | static void |
1363 | urtwn_read_rom(struct urtwn_softc *sc) | | 1367 | urtwn_read_rom(struct urtwn_softc *sc) |
1364 | { | | 1368 | { |
1365 | struct ieee80211com *ic = &sc->sc_ic; | | 1369 | struct ieee80211com *ic = &sc->sc_ic; |
1366 | struct r92c_rom *rom = &sc->rom; | | 1370 | struct r92c_rom *rom = &sc->rom; |
1367 | | | 1371 | |
1368 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1372 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1369 | | | 1373 | |
1370 | mutex_enter(&sc->sc_write_mtx); | | 1374 | mutex_enter(&sc->sc_write_mtx); |
1371 | | | 1375 | |
1372 | /* Read full ROM image. */ | | 1376 | /* Read full ROM image. */ |
1373 | urtwn_efuse_read(sc); | | 1377 | urtwn_efuse_read(sc); |
1374 | #ifdef URTWN_DEBUG | | 1378 | #ifdef URTWN_DEBUG |
1375 | if (urtwn_debug & DBG_REG) | | 1379 | if (urtwn_debug & DBG_REG) |
1376 | urtwn_dump_rom(sc, rom); | | 1380 | urtwn_dump_rom(sc, rom); |
1377 | #endif | | 1381 | #endif |
1378 | | | 1382 | |
1379 | /* XXX Weird but this is what the vendor driver does. */ | | 1383 | /* XXX Weird but this is what the vendor driver does. */ |
1380 | sc->pa_setting = urtwn_efuse_read_1(sc, 0x1fa); | | 1384 | sc->pa_setting = urtwn_efuse_read_1(sc, 0x1fa); |
1381 | sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); | | 1385 | sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); |
1382 | sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); | | 1386 | sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); |
1383 | | | 1387 | |
1384 | DPRINTFN(DBG_INIT, | | 1388 | DPRINTFN(DBG_INIT, |
1385 | ("%s: %s: PA setting=0x%x, board=0x%x, regulatory=%d\n", | | 1389 | ("%s: %s: PA setting=0x%x, board=0x%x, regulatory=%d\n", |
1386 | device_xname(sc->sc_dev), __func__, sc->pa_setting, | | 1390 | device_xname(sc->sc_dev), __func__, sc->pa_setting, |
1387 | sc->board_type, sc->regulatory)); | | 1391 | sc->board_type, sc->regulatory)); |
1388 | | | 1392 | |
1389 | IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr); | | 1393 | IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr); |
1390 | | | 1394 | |
1391 | sc->sc_rf_write = urtwn_r92c_rf_write; | | 1395 | sc->sc_rf_write = urtwn_r92c_rf_write; |
1392 | sc->sc_power_on = urtwn_r92c_power_on; | | 1396 | sc->sc_power_on = urtwn_r92c_power_on; |
1393 | sc->sc_dma_init = urtwn_r92c_dma_init; | | 1397 | sc->sc_dma_init = urtwn_r92c_dma_init; |
1394 | | | 1398 | |
1395 | mutex_exit(&sc->sc_write_mtx); | | 1399 | mutex_exit(&sc->sc_write_mtx); |
1396 | } | | 1400 | } |
1397 | | | 1401 | |
1398 | static void | | 1402 | static void |
1399 | urtwn_r88e_read_rom(struct urtwn_softc *sc) | | 1403 | urtwn_r88e_read_rom(struct urtwn_softc *sc) |
1400 | { | | 1404 | { |
1401 | struct ieee80211com *ic = &sc->sc_ic; | | 1405 | struct ieee80211com *ic = &sc->sc_ic; |
1402 | uint8_t *rom = sc->r88e_rom; | | 1406 | uint8_t *rom = sc->r88e_rom; |
1403 | uint32_t reg; | | 1407 | uint32_t reg; |
1404 | uint16_t addr = 0; | | 1408 | uint16_t addr = 0; |
1405 | uint8_t off, msk, tmp; | | 1409 | uint8_t off, msk, tmp; |
1406 | int i; | | 1410 | int i; |
1407 | | | 1411 | |
1408 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1412 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1409 | | | 1413 | |
1410 | mutex_enter(&sc->sc_write_mtx); | | 1414 | mutex_enter(&sc->sc_write_mtx); |
1411 | | | 1415 | |
1412 | off = 0; | | 1416 | off = 0; |
1413 | urtwn_efuse_switch_power(sc); | | 1417 | urtwn_efuse_switch_power(sc); |
1414 | | | 1418 | |
1415 | /* Read full ROM image. */ | | 1419 | /* Read full ROM image. */ |
1416 | memset(&sc->r88e_rom, 0xff, sizeof(sc->r88e_rom)); | | 1420 | memset(&sc->r88e_rom, 0xff, sizeof(sc->r88e_rom)); |
1417 | while (addr < 4096) { | | 1421 | while (addr < 4096) { |
1418 | reg = urtwn_efuse_read_1(sc, addr); | | 1422 | reg = urtwn_efuse_read_1(sc, addr); |
1419 | if (reg == 0xff) | | 1423 | if (reg == 0xff) |
1420 | break; | | 1424 | break; |
1421 | addr++; | | 1425 | addr++; |
1422 | if ((reg & 0x1f) == 0x0f) { | | 1426 | if ((reg & 0x1f) == 0x0f) { |
1423 | tmp = (reg & 0xe0) >> 5; | | 1427 | tmp = (reg & 0xe0) >> 5; |
1424 | reg = urtwn_efuse_read_1(sc, addr); | | 1428 | reg = urtwn_efuse_read_1(sc, addr); |
1425 | if ((reg & 0x0f) != 0x0f) | | 1429 | if ((reg & 0x0f) != 0x0f) |
1426 | off = ((reg & 0xf0) >> 1) | tmp; | | 1430 | off = ((reg & 0xf0) >> 1) | tmp; |
1427 | addr++; | | 1431 | addr++; |
1428 | } else | | 1432 | } else |
1429 | off = reg >> 4; | | 1433 | off = reg >> 4; |
1430 | msk = reg & 0xf; | | 1434 | msk = reg & 0xf; |
1431 | for (i = 0; i < 4; i++) { | | 1435 | for (i = 0; i < 4; i++) { |
1432 | if (msk & (1 << i)) | | 1436 | if (msk & (1 << i)) |
1433 | continue; | | 1437 | continue; |
1434 | rom[off * 8 + i * 2 + 0] = urtwn_efuse_read_1(sc, addr); | | 1438 | rom[off * 8 + i * 2 + 0] = urtwn_efuse_read_1(sc, addr); |
1435 | addr++; | | 1439 | addr++; |
1436 | rom[off * 8 + i * 2 + 1] = urtwn_efuse_read_1(sc, addr); | | 1440 | rom[off * 8 + i * 2 + 1] = urtwn_efuse_read_1(sc, addr); |
1437 | addr++; | | 1441 | addr++; |
1438 | } | | 1442 | } |
1439 | } | | 1443 | } |
1440 | #ifdef URTWN_DEBUG | | 1444 | #ifdef URTWN_DEBUG |
1441 | if (urtwn_debug & DBG_REG) { | | 1445 | if (urtwn_debug & DBG_REG) { |
1442 | } | | 1446 | } |
1443 | #endif | | 1447 | #endif |
1444 | | | 1448 | |
1445 | addr = 0x10; | | 1449 | addr = 0x10; |
1446 | for (i = 0; i < 6; i++) | | 1450 | for (i = 0; i < 6; i++) |
1447 | sc->cck_tx_pwr[i] = sc->r88e_rom[addr++]; | | 1451 | sc->cck_tx_pwr[i] = sc->r88e_rom[addr++]; |
1448 | for (i = 0; i < 5; i++) | | 1452 | for (i = 0; i < 5; i++) |
1449 | sc->ht40_tx_pwr[i] = sc->r88e_rom[addr++]; | | 1453 | sc->ht40_tx_pwr[i] = sc->r88e_rom[addr++]; |
1450 | sc->bw20_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf0) >> 4; | | 1454 | sc->bw20_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf0) >> 4; |
1451 | if (sc->bw20_tx_pwr_diff & 0x08) | | 1455 | if (sc->bw20_tx_pwr_diff & 0x08) |
1452 | sc->bw20_tx_pwr_diff |= 0xf0; | | 1456 | sc->bw20_tx_pwr_diff |= 0xf0; |
1453 | sc->ofdm_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf); | | 1457 | sc->ofdm_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf); |
1454 | if (sc->ofdm_tx_pwr_diff & 0x08) | | 1458 | if (sc->ofdm_tx_pwr_diff & 0x08) |
1455 | sc->ofdm_tx_pwr_diff |= 0xf0; | | 1459 | sc->ofdm_tx_pwr_diff |= 0xf0; |
1456 | sc->regulatory = MS(sc->r88e_rom[0xc1], R92C_ROM_RF1_REGULATORY); | | 1460 | sc->regulatory = MS(sc->r88e_rom[0xc1], R92C_ROM_RF1_REGULATORY); |
1457 | | | 1461 | |
1458 | IEEE80211_ADDR_COPY(ic->ic_myaddr, &sc->r88e_rom[0xd7]); | | 1462 | IEEE80211_ADDR_COPY(ic->ic_myaddr, &sc->r88e_rom[0xd7]); |
1459 | | | 1463 | |
1460 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 1464 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { |
1461 | sc->sc_power_on = urtwn_r92e_power_on; | | 1465 | sc->sc_power_on = urtwn_r92e_power_on; |
1462 | sc->sc_rf_write = urtwn_r92e_rf_write; | | 1466 | sc->sc_rf_write = urtwn_r92e_rf_write; |
1463 | } else { | | 1467 | } else { |
1464 | sc->sc_power_on = urtwn_r88e_power_on; | | 1468 | sc->sc_power_on = urtwn_r88e_power_on; |
1465 | sc->sc_rf_write = urtwn_r88e_rf_write; | | 1469 | sc->sc_rf_write = urtwn_r88e_rf_write; |
1466 | } | | 1470 | } |
1467 | sc->sc_dma_init = urtwn_r88e_dma_init; | | 1471 | sc->sc_dma_init = urtwn_r88e_dma_init; |
1468 | | | 1472 | |
1469 | mutex_exit(&sc->sc_write_mtx); | | 1473 | mutex_exit(&sc->sc_write_mtx); |
1470 | } | | 1474 | } |
1471 | | | 1475 | |
1472 | static int | | 1476 | static int |
1473 | urtwn_media_change(struct ifnet *ifp) | | 1477 | urtwn_media_change(struct ifnet *ifp) |
1474 | { | | 1478 | { |
1475 | #ifdef URTWN_DEBUG | | 1479 | #ifdef URTWN_DEBUG |
1476 | struct urtwn_softc *sc = ifp->if_softc; | | 1480 | struct urtwn_softc *sc = ifp->if_softc; |
1477 | #endif | | 1481 | #endif |
1478 | int error; | | 1482 | int error; |
1479 | | | 1483 | |
1480 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1484 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1481 | | | 1485 | |
1482 | if ((error = ieee80211_media_change(ifp)) != ENETRESET) | | 1486 | if ((error = ieee80211_media_change(ifp)) != ENETRESET) |
1483 | return error; | | 1487 | return error; |
1484 | | | 1488 | |
1485 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | | 1489 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == |
1486 | (IFF_UP | IFF_RUNNING)) { | | 1490 | (IFF_UP | IFF_RUNNING)) { |
1487 | urtwn_init(ifp); | | 1491 | urtwn_init(ifp); |
1488 | } | | 1492 | } |
1489 | return 0; | | 1493 | return 0; |
1490 | } | | 1494 | } |
1491 | | | 1495 | |
1492 | /* | | 1496 | /* |
1493 | * Initialize rate adaptation in firmware. | | 1497 | * Initialize rate adaptation in firmware. |
1494 | */ | | 1498 | */ |
1495 | static int | | 1499 | static int |
1496 | urtwn_ra_init(struct urtwn_softc *sc) | | 1500 | urtwn_ra_init(struct urtwn_softc *sc) |
1497 | { | | 1501 | { |
1498 | static const uint8_t map[] = { | | 1502 | static const uint8_t map[] = { |
1499 | 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 | | 1503 | 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 |
1500 | }; | | 1504 | }; |
1501 | struct ieee80211com *ic = &sc->sc_ic; | | 1505 | struct ieee80211com *ic = &sc->sc_ic; |
1502 | struct ieee80211_node *ni = ic->ic_bss; | | 1506 | struct ieee80211_node *ni = ic->ic_bss; |
1503 | struct ieee80211_rateset *rs = &ni->ni_rates; | | 1507 | struct ieee80211_rateset *rs = &ni->ni_rates; |
1504 | struct r92c_fw_cmd_macid_cfg cmd; | | 1508 | struct r92c_fw_cmd_macid_cfg cmd; |
1505 | uint32_t rates, basicrates; | | 1509 | uint32_t rates, basicrates; |
1506 | uint32_t mask, rrsr_mask, rrsr_rate; | | 1510 | uint32_t mask, rrsr_mask, rrsr_rate; |
1507 | uint8_t mode; | | 1511 | uint8_t mode; |
1508 | size_t maxrate, maxbasicrate, i, j; | | 1512 | size_t maxrate, maxbasicrate, i, j; |
1509 | int error; | | 1513 | int error; |
1510 | | | 1514 | |
1511 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1515 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1512 | | | 1516 | |
1513 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1517 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1514 | | | 1518 | |
1515 | /* Get normal and basic rates mask. */ | | 1519 | /* Get normal and basic rates mask. */ |
1516 | rates = basicrates = 1; | | 1520 | rates = basicrates = 1; |
1517 | maxrate = maxbasicrate = 0; | | 1521 | maxrate = maxbasicrate = 0; |
1518 | for (i = 0; i < rs->rs_nrates; i++) { | | 1522 | for (i = 0; i < rs->rs_nrates; i++) { |
1519 | /* Convert 802.11 rate to HW rate index. */ | | 1523 | /* Convert 802.11 rate to HW rate index. */ |
1520 | for (j = 0; j < __arraycount(map); j++) { | | 1524 | for (j = 0; j < __arraycount(map); j++) { |
1521 | if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j]) { | | 1525 | if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j]) { |
1522 | break; | | 1526 | break; |
1523 | } | | 1527 | } |
1524 | } | | 1528 | } |
1525 | if (j == __arraycount(map)) { | | 1529 | if (j == __arraycount(map)) { |
1526 | /* Unknown rate, skip. */ | | 1530 | /* Unknown rate, skip. */ |
1527 | continue; | | 1531 | continue; |
1528 | } | | 1532 | } |
1529 | | | 1533 | |
1530 | rates |= 1U << j; | | 1534 | rates |= 1U << j; |
1531 | if (j > maxrate) { | | 1535 | if (j > maxrate) { |
1532 | maxrate = j; | | 1536 | maxrate = j; |
1533 | } | | 1537 | } |
1534 | | | 1538 | |
1535 | if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { | | 1539 | if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { |
1536 | basicrates |= 1U << j; | | 1540 | basicrates |= 1U << j; |
1537 | if (j > maxbasicrate) { | | 1541 | if (j > maxbasicrate) { |
1538 | maxbasicrate = j; | | 1542 | maxbasicrate = j; |
1539 | } | | 1543 | } |
1540 | } | | 1544 | } |
1541 | } | | 1545 | } |
1542 | if (ic->ic_curmode == IEEE80211_MODE_11B) { | | 1546 | if (ic->ic_curmode == IEEE80211_MODE_11B) { |
1543 | mode = R92C_RAID_11B; | | 1547 | mode = R92C_RAID_11B; |
1544 | } else { | | 1548 | } else { |
1545 | mode = R92C_RAID_11BG; | | 1549 | mode = R92C_RAID_11BG; |
1546 | } | | 1550 | } |
1547 | DPRINTFN(DBG_INIT, ("%s: %s: mode=0x%x rates=0x%x, basicrates=0x%x, " | | 1551 | DPRINTFN(DBG_INIT, ("%s: %s: mode=0x%x rates=0x%x, basicrates=0x%x, " |
1548 | "maxrate=%zx, maxbasicrate=%zx\n", | | 1552 | "maxrate=%zx, maxbasicrate=%zx\n", |
1549 | device_xname(sc->sc_dev), __func__, mode, rates, basicrates, | | 1553 | device_xname(sc->sc_dev), __func__, mode, rates, basicrates, |
1550 | maxrate, maxbasicrate)); | | 1554 | maxrate, maxbasicrate)); |
1551 | | | 1555 | |
1552 | if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) { | | 1556 | if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) { |
1553 | maxbasicrate |= R92C_RATE_SHORTGI; | | 1557 | maxbasicrate |= R92C_RATE_SHORTGI; |
1554 | maxrate |= R92C_RATE_SHORTGI; | | 1558 | maxrate |= R92C_RATE_SHORTGI; |
1555 | } | | 1559 | } |
1556 | | | 1560 | |
1557 | /* Set rates mask for group addressed frames. */ | | 1561 | /* Set rates mask for group addressed frames. */ |
1558 | cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID; | | 1562 | cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID; |
1559 | if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) | | 1563 | if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) |
1560 | cmd.macid |= URTWN_MACID_SHORTGI; | | 1564 | cmd.macid |= URTWN_MACID_SHORTGI; |
1561 | | | 1565 | |
1562 | mask = (mode << 28) | basicrates; | | 1566 | mask = (mode << 28) | basicrates; |
1563 | cmd.mask[0] = (uint8_t)mask; | | 1567 | cmd.mask[0] = (uint8_t)mask; |
1564 | cmd.mask[1] = (uint8_t)(mask >> 8); | | 1568 | cmd.mask[1] = (uint8_t)(mask >> 8); |
1565 | cmd.mask[2] = (uint8_t)(mask >> 16); | | 1569 | cmd.mask[2] = (uint8_t)(mask >> 16); |
1566 | cmd.mask[3] = (uint8_t)(mask >> 24); | | 1570 | cmd.mask[3] = (uint8_t)(mask >> 24); |
1567 | error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); | | 1571 | error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); |
1568 | if (error != 0) { | | 1572 | if (error != 0) { |
1569 | aprint_error_dev(sc->sc_dev, | | 1573 | aprint_error_dev(sc->sc_dev, |
1570 | "could not add broadcast station\n"); | | 1574 | "could not add broadcast station\n"); |
1571 | return error; | | 1575 | return error; |
1572 | } | | 1576 | } |
1573 | /* Set initial MRR rate. */ | | 1577 | /* Set initial MRR rate. */ |
1574 | DPRINTFN(DBG_INIT, ("%s: %s: maxbasicrate=%zd\n", | | 1578 | DPRINTFN(DBG_INIT, ("%s: %s: maxbasicrate=%zd\n", |
1575 | device_xname(sc->sc_dev), __func__, maxbasicrate)); | | 1579 | device_xname(sc->sc_dev), __func__, maxbasicrate)); |
1576 | urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC), maxbasicrate); | | 1580 | urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC), maxbasicrate); |
1577 | | | 1581 | |
1578 | /* Set rates mask for unicast frames. */ | | 1582 | /* Set rates mask for unicast frames. */ |
1579 | cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID; | | 1583 | cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID; |
1580 | if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) | | 1584 | if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) |
1581 | cmd.macid |= URTWN_MACID_SHORTGI; | | 1585 | cmd.macid |= URTWN_MACID_SHORTGI; |
1582 | | | 1586 | |
1583 | mask = (mode << 28) | rates; | | 1587 | mask = (mode << 28) | rates; |
1584 | cmd.mask[0] = (uint8_t)mask; | | 1588 | cmd.mask[0] = (uint8_t)mask; |
1585 | cmd.mask[1] = (uint8_t)(mask >> 8); | | 1589 | cmd.mask[1] = (uint8_t)(mask >> 8); |
1586 | cmd.mask[2] = (uint8_t)(mask >> 16); | | 1590 | cmd.mask[2] = (uint8_t)(mask >> 16); |
1587 | cmd.mask[3] = (uint8_t)(mask >> 24); | | 1591 | cmd.mask[3] = (uint8_t)(mask >> 24); |
1588 | error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); | | 1592 | error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); |
1589 | if (error != 0) { | | 1593 | if (error != 0) { |
1590 | aprint_error_dev(sc->sc_dev, "could not add BSS station\n"); | | 1594 | aprint_error_dev(sc->sc_dev, "could not add BSS station\n"); |
1591 | return error; | | 1595 | return error; |
1592 | } | | 1596 | } |
1593 | /* Set initial MRR rate. */ | | 1597 | /* Set initial MRR rate. */ |
1594 | DPRINTFN(DBG_INIT, ("%s: %s: maxrate=%zd\n", device_xname(sc->sc_dev), | | 1598 | DPRINTFN(DBG_INIT, ("%s: %s: maxrate=%zd\n", device_xname(sc->sc_dev), |
1595 | __func__, maxrate)); | | 1599 | __func__, maxrate)); |
1596 | urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS), maxrate); | | 1600 | urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS), maxrate); |
1597 | | | 1601 | |
1598 | rrsr_rate = ic->ic_fixed_rate; | | 1602 | rrsr_rate = ic->ic_fixed_rate; |
1599 | if (rrsr_rate == -1) | | 1603 | if (rrsr_rate == -1) |
1600 | rrsr_rate = 11; | | 1604 | rrsr_rate = 11; |
1601 | | | 1605 | |
1602 | rrsr_mask = 0xffff >> (15 - rrsr_rate); | | 1606 | rrsr_mask = 0xffff >> (15 - rrsr_rate); |
1603 | urtwn_write_2(sc, R92C_RRSR, rrsr_mask); | | 1607 | urtwn_write_2(sc, R92C_RRSR, rrsr_mask); |
1604 | | | 1608 | |
1605 | /* Indicate highest supported rate. */ | | 1609 | /* Indicate highest supported rate. */ |
1606 | ni->ni_txrate = rs->rs_nrates - 1; | | 1610 | ni->ni_txrate = rs->rs_nrates - 1; |
1607 | | | 1611 | |
1608 | return 0; | | 1612 | return 0; |
1609 | } | | 1613 | } |
1610 | | | 1614 | |
1611 | static int | | 1615 | static int |
1612 | urtwn_get_nettype(struct urtwn_softc *sc) | | 1616 | urtwn_get_nettype(struct urtwn_softc *sc) |
1613 | { | | 1617 | { |
1614 | struct ieee80211com *ic = &sc->sc_ic; | | 1618 | struct ieee80211com *ic = &sc->sc_ic; |
1615 | int type; | | 1619 | int type; |
1616 | | | 1620 | |
1617 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1621 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1618 | | | 1622 | |
1619 | switch (ic->ic_opmode) { | | 1623 | switch (ic->ic_opmode) { |
1620 | case IEEE80211_M_STA: | | 1624 | case IEEE80211_M_STA: |
1621 | type = R92C_CR_NETTYPE_INFRA; | | 1625 | type = R92C_CR_NETTYPE_INFRA; |
1622 | break; | | 1626 | break; |
1623 | | | 1627 | |
1624 | case IEEE80211_M_IBSS: | | 1628 | case IEEE80211_M_IBSS: |
1625 | type = R92C_CR_NETTYPE_ADHOC; | | 1629 | type = R92C_CR_NETTYPE_ADHOC; |
1626 | break; | | 1630 | break; |
1627 | | | 1631 | |
1628 | default: | | 1632 | default: |
1629 | type = R92C_CR_NETTYPE_NOLINK; | | 1633 | type = R92C_CR_NETTYPE_NOLINK; |
1630 | break; | | 1634 | break; |
1631 | } | | 1635 | } |
1632 | | | 1636 | |
1633 | return type; | | 1637 | return type; |
1634 | } | | 1638 | } |
1635 | | | 1639 | |
1636 | static void | | 1640 | static void |
1637 | urtwn_set_nettype0_msr(struct urtwn_softc *sc, uint8_t type) | | 1641 | urtwn_set_nettype0_msr(struct urtwn_softc *sc, uint8_t type) |
1638 | { | | 1642 | { |
1639 | uint8_t reg; | | 1643 | uint8_t reg; |
1640 | | | 1644 | |
1641 | DPRINTFN(DBG_FN, ("%s: %s: type=%d\n", device_xname(sc->sc_dev), | | 1645 | DPRINTFN(DBG_FN, ("%s: %s: type=%d\n", device_xname(sc->sc_dev), |
1642 | __func__, type)); | | 1646 | __func__, type)); |
1643 | | | 1647 | |
1644 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1648 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1645 | | | 1649 | |
1646 | reg = urtwn_read_1(sc, R92C_CR + 2) & 0x0c; | | 1650 | reg = urtwn_read_1(sc, R92C_CR + 2) & 0x0c; |
1647 | urtwn_write_1(sc, R92C_CR + 2, reg | type); | | 1651 | urtwn_write_1(sc, R92C_CR + 2, reg | type); |
1648 | } | | 1652 | } |
1649 | | | 1653 | |
1650 | static void | | 1654 | static void |
1651 | urtwn_tsf_sync_enable(struct urtwn_softc *sc) | | 1655 | urtwn_tsf_sync_enable(struct urtwn_softc *sc) |
1652 | { | | 1656 | { |
1653 | struct ieee80211_node *ni = sc->sc_ic.ic_bss; | | 1657 | struct ieee80211_node *ni = sc->sc_ic.ic_bss; |
1654 | uint64_t tsf; | | 1658 | uint64_t tsf; |
1655 | | | 1659 | |
1656 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1660 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1657 | | | 1661 | |
1658 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1662 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1659 | | | 1663 | |
1660 | /* Enable TSF synchronization. */ | | 1664 | /* Enable TSF synchronization. */ |
1661 | urtwn_write_1(sc, R92C_BCN_CTRL, | | 1665 | urtwn_write_1(sc, R92C_BCN_CTRL, |
1662 | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); | | 1666 | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); |
1663 | | | 1667 | |
1664 | /* Correct TSF */ | | 1668 | /* Correct TSF */ |
1665 | urtwn_write_1(sc, R92C_BCN_CTRL, | | 1669 | urtwn_write_1(sc, R92C_BCN_CTRL, |
1666 | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN); | | 1670 | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN); |
1667 | | | 1671 | |
1668 | /* Set initial TSF. */ | | 1672 | /* Set initial TSF. */ |
1669 | tsf = ni->ni_tstamp.tsf; | | 1673 | tsf = ni->ni_tstamp.tsf; |
1670 | tsf = le64toh(tsf); | | 1674 | tsf = le64toh(tsf); |
1671 | tsf = tsf - (tsf % (ni->ni_intval * IEEE80211_DUR_TU)); | | 1675 | tsf = tsf - (tsf % (ni->ni_intval * IEEE80211_DUR_TU)); |
1672 | tsf -= IEEE80211_DUR_TU; | | 1676 | tsf -= IEEE80211_DUR_TU; |
1673 | urtwn_write_4(sc, R92C_TSFTR + 0, (uint32_t)tsf); | | 1677 | urtwn_write_4(sc, R92C_TSFTR + 0, (uint32_t)tsf); |
1674 | urtwn_write_4(sc, R92C_TSFTR + 4, (uint32_t)(tsf >> 32)); | | 1678 | urtwn_write_4(sc, R92C_TSFTR + 4, (uint32_t)(tsf >> 32)); |
1675 | | | 1679 | |
1676 | urtwn_write_1(sc, R92C_BCN_CTRL, | | 1680 | urtwn_write_1(sc, R92C_BCN_CTRL, |
1677 | urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); | | 1681 | urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); |
1678 | } | | 1682 | } |
1679 | | | 1683 | |
1680 | static void | | 1684 | static void |
1681 | urtwn_set_led(struct urtwn_softc *sc, int led, int on) | | 1685 | urtwn_set_led(struct urtwn_softc *sc, int led, int on) |
1682 | { | | 1686 | { |
1683 | uint8_t reg; | | 1687 | uint8_t reg; |
1684 | | | 1688 | |
1685 | DPRINTFN(DBG_FN, ("%s: %s: led=%d, on=%d\n", device_xname(sc->sc_dev), | | 1689 | DPRINTFN(DBG_FN, ("%s: %s: led=%d, on=%d\n", device_xname(sc->sc_dev), |
1686 | __func__, led, on)); | | 1690 | __func__, led, on)); |
1687 | | | 1691 | |
1688 | KASSERT(mutex_owned(&sc->sc_write_mtx)); | | 1692 | KASSERT(mutex_owned(&sc->sc_write_mtx)); |
1689 | | | 1693 | |
1690 | if (led == URTWN_LED_LINK) { | | 1694 | if (led == URTWN_LED_LINK) { |
1691 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 1695 | if (ISSET(sc->chip, URTWN_CHIP_92EU)) { |
1692 | urtwn_write_1(sc, 0x64, urtwn_read_1(sc, 0x64) & 0xfe); | | 1696 | urtwn_write_1(sc, 0x64, urtwn_read_1(sc, 0x64) & 0xfe); |
1693 | reg = urtwn_read_1(sc, R92C_LEDCFG1) & R92E_LEDSON; | | 1697 | reg = urtwn_read_1(sc, R92C_LEDCFG1) & R92E_LEDSON; |
1694 | urtwn_write_1(sc, R92C_LEDCFG1, reg | | | 1698 | urtwn_write_1(sc, R92C_LEDCFG1, reg | |
1695 | (R92C_LEDCFG0_DIS << 1)); | | 1699 | (R92C_LEDCFG0_DIS << 1)); |
1696 | if (on) { | | 1700 | if (on) { |
1697 | reg = urtwn_read_1(sc, R92C_LEDCFG1) & | | 1701 | reg = urtwn_read_1(sc, R92C_LEDCFG1) & |
1698 | R92E_LEDSON; | | 1702 | R92E_LEDSON; |
1699 | urtwn_write_1(sc, R92C_LEDCFG1, reg); | | 1703 | urtwn_write_1(sc, R92C_LEDCFG1, reg); |
1700 | } | | 1704 | } |
1701 | } else if (ISSET(sc->chip, URTWN_CHIP_88E)) { | | 1705 | } else if (ISSET(sc->chip, URTWN_CHIP_88E)) { |
1702 | reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; | | 1706 | reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; |
1703 | urtwn_write_1(sc, R92C_LEDCFG2, reg | 0x60); | | 1707 | urtwn_write_1(sc, R92C_LEDCFG2, reg | 0x60); |
1704 | if (!on) { | | 1708 | if (!on) { |
1705 | reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0x90; | | 1709 | reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0x90; |
1706 | urtwn_write_1(sc, R92C_LEDCFG2, | | 1710 | urtwn_write_1(sc, R92C_LEDCFG2, |
1707 | reg | R92C_LEDCFG0_DIS); | | 1711 | reg | R92C_LEDCFG0_DIS); |
1708 | reg = urtwn_read_1(sc, R92C_MAC_PINMUX_CFG); | | 1712 | reg = urtwn_read_1(sc, R92C_MAC_PINMUX_CFG); |
1709 | urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, | | 1713 | urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, |
1710 | reg & 0xfe); | | 1714 | reg & 0xfe); |
1711 | } | | 1715 | } |
1712 | } else { | | 1716 | } else { |
1713 | reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70; | | 1717 | reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70; |
1714 | if (!on) { | | 1718 | if (!on) { |
1715 | reg |= R92C_LEDCFG0_DIS; | | 1719 | reg |= R92C_LEDCFG0_DIS; |
1716 | } | | 1720 | } |
1717 | urtwn_write_1(sc, R92C_LEDCFG0, reg); | | 1721 | urtwn_write_1(sc, R92C_LEDCFG0, reg); |
1718 | } | | 1722 | } |
1719 | sc->ledlink = on; /* Save LED state. */ | | 1723 | sc->ledlink = on; /* Save LED state. */ |
1720 | } | | 1724 | } |
1721 | } | | 1725 | } |
1722 | | | 1726 | |
1723 | static void | | 1727 | static void |
1724 | urtwn_calib_to(void *arg) | | 1728 | urtwn_calib_to(void *arg) |
1725 | { | | 1729 | { |
1726 | struct urtwn_softc *sc = arg; | | 1730 | struct urtwn_softc *sc = arg; |
1727 | | | 1731 | |
1728 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1732 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1729 | | | 1733 | |
1730 | if (sc->sc_dying) | | 1734 | if (sc->sc_dying) |
1731 | return; | | 1735 | return; |
1732 | | | 1736 | |
1733 | /* Do it in a process context. */ | | 1737 | /* Do it in a process context. */ |
1734 | urtwn_do_async(sc, urtwn_calib_to_cb, NULL, 0); | | 1738 | urtwn_do_async(sc, urtwn_calib_to_cb, NULL, 0); |
1735 | } | | 1739 | } |
1736 | | | 1740 | |
1737 | /* ARGSUSED */ | | 1741 | /* ARGSUSED */ |
1738 | static void | | 1742 | static void |
1739 | urtwn_calib_to_cb(struct urtwn_softc *sc, void *arg) | | 1743 | urtwn_calib_to_cb(struct urtwn_softc *sc, void *arg) |
1740 | { | | 1744 | { |
1741 | struct r92c_fw_cmd_rssi cmd; | | 1745 | struct r92c_fw_cmd_rssi cmd; |
1742 | struct r92e_fw_cmd_rssi cmde; | | 1746 | struct r92e_fw_cmd_rssi cmde; |
1743 | | | 1747 | |
1744 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1748 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1745 | | | 1749 | |
1746 | if (sc->sc_ic.ic_state != IEEE80211_S_RUN) | | 1750 | if (sc->sc_ic.ic_state != IEEE80211_S_RUN) |
1747 | goto restart_timer; | | 1751 | goto restart_timer; |
1748 | | | 1752 | |
1749 | mutex_enter(&sc->sc_write_mtx); | | 1753 | mutex_enter(&sc->sc_write_mtx); |
1750 | if (sc->avg_pwdb != -1) { | | 1754 | if (sc->avg_pwdb != -1) { |
1751 | /* Indicate Rx signal strength to FW for rate adaptation. */ | | 1755 | /* Indicate Rx signal strength to FW for rate adaptation. */ |
1752 | memset(&cmd, 0, sizeof(cmd)); | | 1756 | memset(&cmd, 0, sizeof(cmd)); |
1753 | memset(&cmde, 0, sizeof(cmde)); | | 1757 | memset(&cmde, 0, sizeof(cmde)); |
1754 | cmd.macid = 0; /* BSS. */ | | 1758 | cmd.macid = 0; /* BSS. */ |
1755 | cmde.macid = 0; /* BSS. */ | | 1759 | cmde.macid = 0; /* BSS. */ |
1756 | cmd.pwdb = sc->avg_pwdb; | | 1760 | cmd.pwdb = sc->avg_pwdb; |
1757 | cmde.pwdb = sc->avg_pwdb; | | 1761 | cmde.pwdb = sc->avg_pwdb; |
1758 | DPRINTFN(DBG_RF, ("%s: %s: sending RSSI command avg=%d\n", | | 1762 | DPRINTFN(DBG_RF, ("%s: %s: sending RSSI command avg=%d\n", |
1759 | device_xname(sc->sc_dev), __func__, sc->avg_pwdb)); | | 1763 | device_xname(sc->sc_dev), __func__, sc->avg_pwdb)); |
1760 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { | | 1764 | if (!ISSET(sc->chip, URTWN_CHIP_92EU)) { |
1761 | urtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, | | 1765 | urtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, |
1762 | sizeof(cmd)); | | 1766 | sizeof(cmd)); |
1763 | } else { | | 1767 | } else { |
1764 | urtwn_fw_cmd(sc, R92E_CMD_RSSI_REPORT, &cmde, | | 1768 | urtwn_fw_cmd(sc, R92E_CMD_RSSI_REPORT, &cmde, |
1765 | sizeof(cmde)); | | 1769 | sizeof(cmde)); |
1766 | } | | 1770 | } |
1767 | } | | 1771 | } |
1768 | | | 1772 | |
1769 | /* Do temperature compensation. */ | | 1773 | /* Do temperature compensation. */ |
1770 | urtwn_temp_calib(sc); | | 1774 | urtwn_temp_calib(sc); |
1771 | mutex_exit(&sc->sc_write_mtx); | | 1775 | mutex_exit(&sc->sc_write_mtx); |
1772 | | | 1776 | |
1773 | restart_timer: | | 1777 | restart_timer: |
1774 | if (!sc->sc_dying) { | | 1778 | if (!sc->sc_dying) { |
1775 | /* Restart calibration timer. */ | | 1779 | /* Restart calibration timer. */ |
1776 | callout_schedule(&sc->sc_calib_to, hz); | | 1780 | callout_schedule(&sc->sc_calib_to, hz); |
1777 | } | | 1781 | } |
1778 | } | | 1782 | } |
1779 | | | 1783 | |
1780 | static void | | 1784 | static void |
1781 | urtwn_next_scan(void *arg) | | 1785 | urtwn_next_scan(void *arg) |
1782 | { | | 1786 | { |
1783 | struct urtwn_softc *sc = arg; | | 1787 | struct urtwn_softc *sc = arg; |
1784 | int s; | | 1788 | int s; |
1785 | | | 1789 | |
1786 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); | | 1790 | DPRINTFN(DBG_FN, ("%s: %s\n", device_xname(sc->sc_dev), __func__)); |
1787 | | | 1791 | |
1788 | if (sc->sc_dying) | | 1792 | if (sc->sc_dying) |
1789 | return; | | 1793 | return; |
1790 | | | 1794 | |
1791 | s = splnet(); | | 1795 | s = splnet(); |
1792 | if (sc->sc_ic.ic_state == IEEE80211_S_SCAN) | | 1796 | if (sc->sc_ic.ic_state == IEEE80211_S_SCAN) |
1793 | ieee80211_next_scan(&sc->sc_ic); | | 1797 | ieee80211_next_scan(&sc->sc_ic); |
1794 | splx(s); | | 1798 | splx(s); |
1795 | } | | 1799 | } |
1796 | | | 1800 | |
1797 | static void | | 1801 | static void |
1798 | urtwn_newassoc(struct ieee80211_node *ni, int isnew) | | 1802 | urtwn_newassoc(struct ieee80211_node *ni, int isnew) |
1799 | { | | 1803 | { |
1800 | DPRINTFN(DBG_FN, ("%s: new node %s\n", __func__, | | 1804 | DPRINTFN(DBG_FN, ("%s: new node %s\n", __func__, |
1801 | ether_sprintf(ni->ni_macaddr))); | | 1805 | ether_sprintf(ni->ni_macaddr))); |
1802 | /* start with lowest Tx rate */ | | 1806 | /* start with lowest Tx rate */ |
1803 | ni->ni_txrate = 0; | | 1807 | ni->ni_txrate = 0; |
1804 | } | | 1808 | } |
1805 | | | 1809 | |
1806 | static int | | 1810 | static int |
1807 | urtwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | | 1811 | urtwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) |
1808 | { | | 1812 | { |
1809 | struct urtwn_softc *sc = ic->ic_ifp->if_softc; | | 1813 | struct urtwn_softc *sc = ic->ic_ifp->if_softc; |
1810 | struct urtwn_cmd_newstate cmd; | | 1814 | struct urtwn_cmd_newstate cmd; |
1811 | | | 1815 | |
1812 | DPRINTFN(DBG_FN, ("%s: %s: nstate=%s(%d), arg=%d\n", | | 1816 | DPRINTFN(DBG_FN, ("%s: %s: nstate=%s(%d), arg=%d\n", |
1813 | device_xname(sc->sc_dev), __func__, | | 1817 | device_xname(sc->sc_dev), __func__, |
1814 | ieee80211_state_name[nstate], nstate, arg)); | | 1818 | ieee80211_state_name[nstate], nstate, arg)); |
1815 | | | 1819 | |
1816 | callout_stop(&sc->sc_scan_to); | | 1820 | callout_stop(&sc->sc_scan_to); |
1817 | callout_stop(&sc->sc_calib_to); | | 1821 | callout_stop(&sc->sc_calib_to); |
1818 | | | 1822 | |
1819 | /* Do it in a process context. */ | | 1823 | /* Do it in a process context. */ |
1820 | cmd.state = nstate; | | 1824 | cmd.state = nstate; |
1821 | cmd.arg = arg; | | 1825 | cmd.arg = arg; |
1822 | urtwn_do_async(sc, urtwn_newstate_cb, &cmd, sizeof(cmd)); | | 1826 | urtwn_do_async(sc, urtwn_newstate_cb, &cmd, sizeof(cmd)); |
1823 | return 0; | | 1827 | return 0; |
1824 | } | | 1828 | } |
1825 | | | 1829 | |
1826 | static void | | 1830 | static void |
1827 | urtwn_newstate_cb(struct urtwn_softc *sc, void *arg) | | 1831 | urtwn_newstate_cb(struct urtwn_softc *sc, void *arg) |
1828 | { | | 1832 | { |
1829 | struct urtwn_cmd_newstate *cmd = arg; | | 1833 | struct urtwn_cmd_newstate *cmd = arg; |
1830 | struct ieee80211com *ic = &sc->sc_ic; | | 1834 | struct ieee80211com *ic = &sc->sc_ic; |
1831 | struct ieee80211_node *ni; | | 1835 | struct ieee80211_node *ni; |
1832 | enum ieee80211_state ostate = ic->ic_state; | | 1836 | enum ieee80211_state ostate = ic->ic_state; |
1833 | enum ieee80211_state nstate = cmd->state; | | 1837 | enum ieee80211_state nstate = cmd->state; |
1834 | uint32_t reg; | | 1838 | uint32_t reg; |
1835 | uint8_t sifs_time, msr; | | 1839 | uint8_t sifs_time, msr; |
1836 | int s; | | 1840 | int s; |
1837 | | | 1841 | |
1838 | DPRINTFN(DBG_FN|DBG_STM, ("%s: %s: %s(%d)->%s(%d)\n", | | 1842 | DPRINTFN(DBG_FN|DBG_STM, ("%s: %s: %s(%d)->%s(%d)\n", |
1839 | device_xname(sc->sc_dev), __func__, | | 1843 | device_xname(sc->sc_dev), __func__, |
1840 | ieee80211_state_name[ostate], ostate, | | 1844 | ieee80211_state_name[ostate], ostate, |
1841 | ieee80211_state_name[nstate], nstate)); | | 1845 | ieee80211_state_name[nstate], nstate)); |
1842 | | | 1846 | |
1843 | s = splnet(); | | 1847 | s = splnet(); |
1844 | mutex_enter(&sc->sc_write_mtx); | | 1848 | mutex_enter(&sc->sc_write_mtx); |
1845 | | | 1849 | |
1846 | callout_stop(&sc->sc_scan_to); | | 1850 | callout_stop(&sc->sc_scan_to); |
1847 | callout_stop(&sc->sc_calib_to); | | 1851 | callout_stop(&sc->sc_calib_to); |
1848 | | | 1852 | |
1849 | switch (ostate) { | | 1853 | switch (ostate) { |
1850 | case IEEE80211_S_INIT: | | 1854 | case IEEE80211_S_INIT: |
1851 | break; | | 1855 | break; |
1852 | | | 1856 | |
1853 | case IEEE80211_S_SCAN: | | 1857 | case IEEE80211_S_SCAN: |
1854 | if (nstate != IEEE80211_S_SCAN) { | | 1858 | if (nstate != IEEE80211_S_SCAN) { |
1855 | /* | | 1859 | /* |
1856 | * End of scanning | | 1860 | * End of scanning |
1857 | */ | | 1861 | */ |
1858 | /* flush 4-AC Queue after site_survey */ | | 1862 | /* flush 4-AC Queue after site_survey */ |
1859 | urtwn_write_1(sc, R92C_TXPAUSE, 0x0); | | 1863 | urtwn_write_1(sc, R92C_TXPAUSE, 0x0); |
1860 | | | 1864 | |
1861 | /* Allow Rx from our BSSID only. */ | | 1865 | /* Allow Rx from our BSSID only. */ |
1862 | urtwn_write_4(sc, R92C_RCR, | | 1866 | urtwn_write_4(sc, R92C_RCR, |
1863 | urtwn_read_4(sc, R92C_RCR) | | | 1867 | urtwn_read_4(sc, R92C_RCR) | |
1864 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); | | 1868 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); |
1865 | } | | 1869 | } |
1866 | break; | | 1870 | break; |