2 * Copyright (c) 2006 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/dev/netif/acx/acxcmd.c,v 1.11 2008/06/01 03:58:38 sephe Exp $
37 #include <sys/param.h>
39 #include <sys/endian.h>
40 #include <sys/kernel.h>
42 #include <sys/socket.h>
43 #include <sys/sysctl.h>
46 #include <net/if_arp.h>
47 #include <net/if_media.h>
49 #include <netproto/802_11/ieee80211_var.h>
50 #include <netproto/802_11/ieee80211_radiotap.h>
51 #include <netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h>
52 #include <netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h>
56 #include <dev/netif/acx/if_acxreg.h>
57 #include <dev/netif/acx/if_acxvar.h>
58 #include <dev/netif/acx/acxcmd.h>
60 #define CMDPRM_WRITE_REGION_1(sc, r, rlen) \
61 bus_space_write_region_1((sc)->sc_mem2_bt, \
64 (const uint8_t *)(r), (rlen))
66 #define CMDPRM_READ_REGION_1(sc, r, rlen) \
67 bus_space_read_region_1((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, \
68 (sc)->sc_cmd_param, (uint8_t *)(r), (rlen))
71 * This will clear previous command's
72 * execution status too
74 #define CMD_WRITE_4(sc, val) \
75 bus_space_write_4((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, \
77 #define CMD_READ_4(sc) \
78 bus_space_read_4((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (sc)->sc_cmd)
81 * acx command register layerout:
82 * upper 16bits are command execution status
83 * lower 16bits are command to be executed
85 #define ACX_CMD_STATUS_SHIFT 16
86 #define ACX_CMD_STATUS_OK 1
89 uint32_t radio_ofs
; /* radio firmware offset */
90 uint32_t radio_len
; /* radio firmware length */
94 uint8_t bssid
[IEEE80211_ADDR_LEN
];
95 uint16_t beacon_intvl
;
97 uint8_t ndata_txrate
; /* see ACX_NDATA_TXRATE_ */
98 uint8_t ndata_txopt
; /* see ACX_NDATA_TXOPT_ */
99 uint8_t mode
; /* see ACX_MODE_ */
106 * non-data frame tx rate
108 #define ACX_NDATA_TXRATE_1 10 /* 1Mbits/s */
109 #define ACX_NDATA_TXRATE_2 20 /* 2Mbits/s */
112 * non-data frame tx options
114 #define ACX_NDATA_TXOPT_PBCC 0x40
115 #define ACX_NDATA_TXOPT_OFDM 0x20
116 #define ACX_NDATA_TXOPT_SHORT_PREAMBLE 0x10
118 #define BSS_JOIN_BUFLEN \
119 (sizeof(struct bss_join_hdr) + IEEE80211_NWID_LEN)
120 #define BSS_JOIN_PARAM_SIZE(bj) \
121 (sizeof(struct bss_join_hdr) + (bj)->esslen)
124 acx_init_cmd_reg(struct acx_softc
*sc
)
126 sc
->sc_cmd
= CSR_READ_4(sc
, ACXREG_CMD_REG_OFFSET
);
127 sc
->sc_cmd_param
= sc
->sc_cmd
+ ACX_CMD_REG_SIZE
;
129 /* Clear command & status */
134 acx_join_bss(struct acx_softc
*sc
, uint8_t mode
, struct ieee80211_node
*ni
,
135 struct ieee80211_channel
*c
)
137 uint8_t bj_buf
[BSS_JOIN_BUFLEN
];
138 struct ieee80211com
*ic
= &sc
->sc_ic
;
139 struct bss_join_hdr
*bj
;
142 bzero(bj_buf
, sizeof(bj_buf
));
143 bj
= (struct bss_join_hdr
*)bj_buf
;
145 for (i
= 0; i
< IEEE80211_ADDR_LEN
; ++i
)
146 bj
->bssid
[i
] = ni
->ni_bssid
[IEEE80211_ADDR_LEN
- i
- 1];
148 bj
->beacon_intvl
= htole16(ni
->ni_intval
);
150 sc
->chip_set_bss_join_param(sc
, bj
->chip_spec
, ic
->ic_dtim_period
);
152 bj
->ndata_txrate
= ACX_NDATA_TXRATE_1
;
155 bj
->channel
= ieee80211_chan2ieee(ic
, c
);
156 bj
->esslen
= ni
->ni_esslen
;
157 bcopy(ni
->ni_essid
, bj
->essid
, ni
->ni_esslen
);
159 DPRINTF((&ic
->ic_if
, "join BSS/IBSS on channel %d\n", bj
->channel
));
160 return acx_exec_command(sc
, ACXCMD_JOIN_BSS
,
161 bj
, BSS_JOIN_PARAM_SIZE(bj
), NULL
, 0);
165 acx_enable_txchan(struct acx_softc
*sc
, uint8_t chan
)
167 return acx_exec_command(sc
, ACXCMD_ENABLE_TXCHAN
, &chan
, sizeof(chan
),
172 acx_enable_rxchan(struct acx_softc
*sc
, uint8_t chan
)
174 return acx_exec_command(sc
, ACXCMD_ENABLE_RXCHAN
, &chan
, sizeof(chan
),
179 acx_get_conf(struct acx_softc
*sc
, uint16_t conf_id
, void *conf
,
182 struct acx_conf
*confcom
;
184 if (conf_len
< sizeof(*confcom
)) {
185 if_printf(&sc
->sc_ic
.ic_if
, "%s configure data is too short\n",
191 confcom
->conf_id
= htole16(conf_id
);
192 confcom
->conf_data_len
= htole16(conf_len
- sizeof(*confcom
));
194 return acx_exec_command(sc
, ACXCMD_GET_CONF
, confcom
, sizeof(*confcom
),
199 acx_set_conf(struct acx_softc
*sc
, uint16_t conf_id
, void *conf
,
202 struct acx_conf
*confcom
;
204 if (conf_len
< sizeof(*confcom
)) {
205 if_printf(&sc
->sc_ic
.ic_if
, "%s configure data is too short\n",
211 confcom
->conf_id
= htole16(conf_id
);
212 confcom
->conf_data_len
= htole16(conf_len
- sizeof(*confcom
));
214 return acx_exec_command(sc
, ACXCMD_SET_CONF
, conf
, conf_len
, NULL
, 0);
218 acx_set_tmplt(struct acx_softc
*sc
, uint16_t cmd
, void *tmplt
,
223 if (tmplt_len
< sizeof(*size
)) {
224 if_printf(&sc
->sc_ic
.ic_if
, "%s template is too short\n",
230 *size
= htole16(tmplt_len
- sizeof(*size
));
232 return acx_exec_command(sc
, cmd
, tmplt
, tmplt_len
, NULL
, 0);
236 acx_init_radio(struct acx_softc
*sc
, uint32_t radio_ofs
, uint32_t radio_len
)
240 r
.radio_ofs
= htole32(radio_ofs
);
241 r
.radio_len
= htole32(radio_len
);
242 return acx_exec_command(sc
, ACXCMD_INIT_RADIO
, &r
, sizeof(r
), NULL
, 0);
246 acx_exec_command(struct acx_softc
*sc
, uint16_t cmd
, void *param
,
247 uint16_t param_len
, void *result
, uint16_t result_len
)
252 ASSERT_SERIALIZED(sc
->sc_ic
.ic_if
.if_serializer
);
254 if ((sc
->sc_flags
& ACX_FLAG_FW_LOADED
) == 0) {
255 if_printf(&sc
->sc_ic
.ic_if
, "cmd 0x%04x failed (base firmware "
262 if (param
!= NULL
&& param_len
!= 0) {
263 /* Set command param */
264 CMDPRM_WRITE_REGION_1(sc
, param
, param_len
);
268 CMD_WRITE_4(sc
, cmd
);
271 CSR_WRITE_2(sc
, ACXREG_INTR_TRIG
, ACXRV_TRIG_CMD_FINI
);
272 DELAY(50); /* XXX maybe 100 */
274 /* Wait for command to complete */
275 if (cmd
== ACXCMD_INIT_RADIO
) {
276 /* XXX radio initialization is extremely long */
277 tsleep(&cmd
, 0, "rdinit", (150 * hz
) / 1000); /* 150ms */
280 #define CMDWAIT_RETRY_MAX 1000
281 for (i
= 0; i
< CMDWAIT_RETRY_MAX
; ++i
) {
284 reg
= CSR_READ_2(sc
, ACXREG_INTR_STATUS
);
285 if (reg
& ACXRV_INTR_CMD_FINI
) {
286 CSR_WRITE_2(sc
, ACXREG_INTR_ACK
, ACXRV_INTR_CMD_FINI
);
291 if (i
== CMDWAIT_RETRY_MAX
) {
292 if_printf(&sc
->sc_ic
.ic_if
, "cmd %04x failed (timeout)\n", cmd
);
296 #undef CMDWAIT_RETRY_MAX
298 /* Get command exec status */
299 status
= (CMD_READ_4(sc
) >> ACX_CMD_STATUS_SHIFT
);
300 if (status
!= ACX_CMD_STATUS_OK
) {
301 if_printf(&sc
->sc_ic
.ic_if
, "cmd %04x failed\n", cmd
);
306 if (result
!= NULL
&& result_len
!= 0) {
307 /* Get command result */
308 CMDPRM_READ_REGION_1(sc
, result
, result_len
);