]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rtwn/rtl8188e/r88e_fw.c
rtwn: Add a USB ID for Buffalo WI-U2-433DHP
[FreeBSD/FreeBSD.git] / sys / dev / rtwn / rtl8188e / r88e_fw.c
1 /*      $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $   */
2
3 /*-
4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5  * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6  * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "opt_wlan.h"
25
26 #include <sys/param.h>
27 #include <sys/lock.h>
28 #include <sys/mutex.h>
29 #include <sys/mbuf.h>
30 #include <sys/kernel.h>
31 #include <sys/socket.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/queue.h>
35 #include <sys/taskqueue.h>
36 #include <sys/bus.h>
37 #include <sys/endian.h>
38 #include <sys/linker.h>
39
40 #include <net/if.h>
41 #include <net/ethernet.h>
42 #include <net/if_media.h>
43
44 #include <net80211/ieee80211_var.h>
45 #include <net80211/ieee80211_radiotap.h>
46
47 #include <dev/rtwn/if_rtwnreg.h>
48 #include <dev/rtwn/if_rtwnvar.h>
49
50 #include <dev/rtwn/if_rtwn_debug.h>
51
52 #include <dev/rtwn/rtl8188e/r88e.h>
53 #include <dev/rtwn/rtl8188e/r88e_reg.h>
54 #include <dev/rtwn/rtl8188e/r88e_fw_cmd.h>
55
56
57 #ifndef RTWN_WITHOUT_UCODE
58 int
59 r88e_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
60 {
61         struct r88e_fw_cmd cmd;
62         int ntries, error;
63
64         if (!(sc->sc_flags & RTWN_FW_LOADED)) {
65                 RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware "
66                     "was not loaded; command (id %d) will be discarded\n",
67                     __func__, id);
68                 return (0);
69         }
70
71         /* Wait for current FW box to be empty. */
72         for (ntries = 0; ntries < 100; ntries++) {
73                 if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
74                         break;
75                 rtwn_delay(sc, 2000);
76         }
77         if (ntries == 100) {
78                 device_printf(sc->sc_dev,
79                     "could not send firmware command\n");
80                 return (ETIMEDOUT);
81         }
82         memset(&cmd, 0, sizeof(cmd));
83         cmd.id = id;
84         KASSERT(len <= sizeof(cmd.msg),
85             ("%s: firmware command too long (%d > %zu)\n",
86             __func__, len, sizeof(cmd.msg)));
87         memcpy(cmd.msg, buf, len);
88
89         /* Write the first word last since that will trigger the FW. */
90         if (len > 3) {
91                 error = rtwn_write_4(sc, R88E_HMEBOX_EXT(sc->fwcur),
92                     *(uint32_t *)((uint8_t *)&cmd + 4));
93                 if (error != 0)
94                         return (error);
95         }
96         error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *(uint32_t *)&cmd);
97         if (error != 0)
98                 return (error);
99
100         sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
101
102         return (0);
103 }
104
105 void
106 r88e_fw_reset(struct rtwn_softc *sc, int reason)
107 {
108         uint16_t reg;
109
110         reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
111         rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
112
113         if (reason != RTWN_FW_RESET_SHUTDOWN) {
114                 rtwn_write_2(sc, R92C_SYS_FUNC_EN,
115                     reg | R92C_SYS_FUNC_EN_CPUEN);
116         }
117 }
118
119 void
120 r88e_fw_download_enable(struct rtwn_softc *sc, int enable)
121 {
122         if (enable) {
123                 /* MCU firmware download enable. */
124                 rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
125                 /* 8051 reset. */
126                 rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
127                     0, 2);
128         } else {
129                 /* MCU download disable. */
130                 rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
131                 /* Reserved for f/w extension. */
132                 rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
133         }
134 }
135 #endif
136
137 void
138 r88e_macid_enable_link(struct rtwn_softc *sc, int id, int enable)
139 {
140         uint32_t reg;
141
142         reg = R88E_MACID_NO_LINK;
143         if (id > 32)
144                 reg += 4;
145
146         if (enable)
147                 rtwn_setbits_4(sc, reg, 1 << (id % 32), 0);
148         else
149                 rtwn_setbits_4(sc, reg, 0, 1 << (id % 32));
150
151         /* XXX max macid for tx reports */
152 }
153
154 void
155 r88e_set_media_status(struct rtwn_softc *sc, int macid)
156 {
157         struct r88e_fw_cmd_msrrpt status;
158
159         if (macid & RTWN_MACID_VALID)
160                 status.msrb0 = R88E_MSRRPT_B0_ASSOC;
161         else
162                 status.msrb0 = R88E_MSRRPT_B0_DISASSOC;
163         status.macid = (macid & ~RTWN_MACID_VALID);
164
165         r88e_macid_enable_link(sc, status.macid,
166             (macid & RTWN_MACID_VALID) != 0);
167
168 #ifndef RTWN_WITHOUT_UCODE
169         if (r88e_fw_cmd(sc, R88E_CMD_MSR_RPT, &status, sizeof(status)) != 0) {
170                 device_printf(sc->sc_dev, "%s: cannot change media status!\n",
171                     __func__);
172         }
173 #endif
174 }
175
176 #ifndef RTWN_WITHOUT_UCODE
177 int
178 r88e_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null,
179     int qos_null)
180 {
181         struct r88e_fw_cmd_rsvdpage rsvd;
182
183         rsvd.probe_resp = probe_resp;
184         rsvd.ps_poll = 0;
185         rsvd.null_data = null;
186         rsvd.null_data_qos = qos_null;
187         rsvd.null_data_qos_bt = 0;
188         return (r88e_fw_cmd(sc, R88E_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd)));
189 }
190
191 int
192 r88e_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
193     int off)
194 {
195         struct r88e_fw_cmd_pwrmode mode;
196         int error;
197
198         if (off && vap->iv_state == IEEE80211_S_RUN &&
199             (vap->iv_flags & IEEE80211_F_PMGTON)) {
200                 mode.mode = R88E_PWRMODE_LEG;
201                 /*
202                  * TODO: switch to RFOFF state
203                  * (something is missing here - Rx stops with it).
204                  */
205 #ifdef RTWN_TODO
206                 mode.pwr_state = R88E_PWRMODE_STATE_RFOFF;
207 #else
208                 mode.pwr_state = R88E_PWRMODE_STATE_RFON;
209 #endif
210         } else {
211                 mode.mode = R88E_PWRMODE_CAM;
212                 mode.pwr_state = R88E_PWRMODE_STATE_ALLON;
213         }
214         mode.pwrb1 =
215             SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) |
216             SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN);
217         /* XXX ignored */
218         mode.bcn_pass = 0;
219         mode.queue_uapsd = 0;
220         error = r88e_fw_cmd(sc, R88E_CMD_SET_PWRMODE, &mode, sizeof(mode));
221         if (error != 0) {
222                 device_printf(sc->sc_dev,
223                     "%s: CMD_SET_PWRMODE was not sent, error %d\n",
224                     __func__, error);
225         }
226
227         return (error);
228 }
229 #endif