1 /* src/acx100_helper.c - helper functions
3 * --------------------------------------------------------------------
5 * Copyright (C) 2003 ACX100 Open Source Project
7 * The contents of this file are subject to the Mozilla Public
8 * License Version 1.1 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * Alternatively, the contents of this file may be used under the
18 * terms of the GNU Public License version 2 (the "GPL"), in which
19 * case the provisions of the GPL are applicable instead of the
20 * above. If you wish to allow the use of your version of this file
21 * only under the terms of the GPL and not to allow others to use
22 * your version of this file under the MPL, indicate your decision
23 * by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL. If you do not delete
25 * the provisions above, a recipient may use your version of this
26 * file under either the MPL or the GPL.
28 * --------------------------------------------------------------------
30 * Inquiries regarding the ACX100 Open Source Project can be
33 * acx100-users@lists.sf.net
34 * http://acx100.sf.net
36 * --------------------------------------------------------------------
39 /*================================================================*/
42 #ifdef S_SPLINT_S /* some crap that splint needs to not crap out */
43 #define __signed__ signed
44 #define __u64 unsigned long long
45 #define loff_t unsigned long
46 #define sigval_t unsigned long
47 #define siginfo_t unsigned long
48 #define stack_t unsigned long
49 #define __s64 signed long long
51 #include <linux/config.h>
52 #include <linux/version.h>
54 #include <linux/kernel.h>
55 #include <linux/vmalloc.h>
57 #include <linux/sched.h>
58 #include <linux/types.h>
59 #include <linux/timer.h>
60 #include <linux/slab.h>
61 #include <linux/proc_fs.h>
62 #include <linux/if_arp.h>
63 #include <linux/skbuff.h>
64 #include <linux/netdevice.h>
65 #include <linux/etherdevice.h>
66 #include <linux/rtnetlink.h>
67 #include <linux/wireless.h>
68 #include <asm/uaccess.h>
72 #include <linux/dcache.h>
73 #include <linux/highmem.h>
76 /*================================================================*/
77 /* Project Includes */
79 #include <wlan_compat.h>
82 #include <p80211mgmt.h>
84 #include <acx100_helper.h>
85 #include <acx100_helper2.h>
91 extern char *firmware_dir
; /* declared in acx100.c, to keep together with other MODULE_PARMs */
93 const UINT8 reg_domain_ids
[] =
94 {(UINT8
)0x10, (UINT8
)0x20, (UINT8
)0x30, (UINT8
)0x31,
95 (UINT8
)0x32, (UINT8
)0x40, (UINT8
)0x41, (UINT8
)0x51};
96 /* stupid workaround for the fact that in C the size of an external array
97 * cannot be determined from within a second file */
98 const UINT8 reg_domain_ids_len
= (UINT8
)sizeof(reg_domain_ids
);
99 const UINT16 reg_domain_channel_masks
[] =
100 {0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc};
103 * Make sure to schedule away sometimes, in order to not hog the CPU too much.
104 * Remember to not do it in IRQ context, though!
106 void acx100_schedule(long timeout
)
109 current
->state
= TASK_UNINTERRUPTIBLE
;
110 (void)schedule_timeout(timeout
);
114 /*------------------------------------------------------------------------------
116 * Handle our /proc entry
119 * standard kernel read_proc interface
121 * number of bytes written to buf
127 * should be okay, non-critical
130 *----------------------------------------------------------------------------*/
131 int acx100_read_proc(char *buf
, char **start
, off_t offset
, int count
,
132 int *eof
, void *data
)
134 wlandevice_t
*priv
= (wlandevice_t
*)data
;
136 int length
= acx100_proc_output(buf
, priv
);
140 if (length
<= offset
+ count
)
142 *start
= buf
+ offset
;
152 int acx100_read_proc_diag(char *buf
, char **start
, off_t offset
, int count
,
153 int *eof
, void *data
)
155 wlandevice_t
*priv
= (wlandevice_t
*)data
;
157 int length
= acx100_proc_diag_output(buf
, priv
);
161 if (length
<= offset
+ count
)
163 *start
= buf
+ offset
;
173 int acx100_read_proc_eeprom(char *buf
, char **start
, off_t offset
, int count
,
174 int *eof
, void *data
)
176 wlandevice_t
*priv
= (wlandevice_t
*)data
;
178 int length
= acx100_proc_eeprom_output(buf
, priv
);
182 if (length
<= offset
+ count
)
184 *start
= buf
+ offset
;
194 int acx100_read_proc_phy(char *buf
, char **start
, off_t offset
, int count
,
195 int *eof
, void *data
)
197 wlandevice_t
*priv
= (wlandevice_t
*)data
;
199 int length
= acx100_proc_phy_output(buf
, priv
);
203 if (length
<= offset
+ count
)
205 *start
= buf
+ offset
;
215 /*------------------------------------------------------------------------------
217 * Generate content for our /proc entry
220 * buf is a pointer to write output to
221 * priv is the usual pointer to our private struct wlandevice
223 * number of bytes actually written to buf
229 * should be okay, non-critical
232 *----------------------------------------------------------------------------*/
233 int acx100_proc_output(char *buf
, wlandevice_t
*priv
)
239 p
+= sprintf(p
, "acx100 driver version:\t\t%s\n", WLAN_RELEASE_SUB
);
240 p
+= sprintf(p
, "Wireless extension version:\t%d\n", WIRELESS_EXT
);
241 p
+= sprintf(p
, "chip name:\t\t\t%s\n", priv
->chip_name
);
242 p
+= sprintf(p
, "radio type:\t\t\t0x%02x\n", priv
->radio_type
);
243 /* TODO: add radio type string from acx100_display_hardware_details */
244 p
+= sprintf(p
, "form factor:\t\t\t0x%02x\n", priv
->form_factor
);
245 /* TODO: add form factor string from acx100_display_hardware_details */
246 p
+= sprintf(p
, "EEPROM version:\t\t\t0x%02x\n", priv
->eeprom_version
);
247 p
+= sprintf(p
, "firmware version:\t\t%s (0x%08x)\n",
248 (char *)priv
->firmware_version
, priv
->firmware_id
);
249 p
+= sprintf(p
, "BSS table has %u entries:\n", priv
->bss_table_count
);
250 for (i
= 0; i
< priv
->bss_table_count
; i
++) {
251 struct bss_info
*bss
= &priv
->bss_table
[i
];
252 p
+= sprintf(p
, " BSS %u BSSID %02x:%02x:%02x:%02x:%02x:%02x ESSID %s channel %u WEP %s Cap 0x%x SIR %u SNR %u\n",
253 i
, bss
->bssid
[0], bss
->bssid
[1],
254 bss
->bssid
[2], bss
->bssid
[3], bss
->bssid
[4],
255 bss
->bssid
[5], (char *)bss
->essid
, bss
->channel
,
256 (0 != bss
->wep
) ? "yes" : "no", bss
->caps
,
259 p
+= sprintf(p
, "status:\t\t\t%u (%s)\n", priv
->status
, acx100_get_status_name(priv
->status
));
260 /* TODO: add more interesting stuff (essid, ...) here */
265 int acx100_proc_diag_output(char *buf
, wlandevice_t
*priv
)
269 TIWLAN_DC
*pDc
= &priv
->dc
;
270 struct rxhostdescriptor
*pDesc
;
273 fw_stats_t
*fw_stats
;
277 p
+= sprintf(p
, "*** Rx buf ***\n");
278 for (i
= 0; i
< pDc
->rx_pool_count
; i
++)
280 pDesc
= &pDc
->pRxHostDescQPool
[i
];
281 if ((0 != (pDesc
->Ctl
& ACX100_CTL_OWN
)) && (0 != (pDesc
->Status
& BIT31
)))
282 p
+= sprintf(p
, "%02u FULL\n", i
);
284 p
+= sprintf(p
, "%02u empty\n", i
);
286 p
+= sprintf(p
, "\n");
287 p
+= sprintf(p
, "*** Tx buf ***\n");
288 for (i
= 0; i
< pDc
->tx_pool_count
; i
++)
290 pTxDesc
= &pDc
->pTxDescQPool
[i
];
291 if ((UINT8
)DESC_CTL_DONE
== (pTxDesc
->Ctl
& (UINT8
)DESC_CTL_DONE
))
292 p
+= sprintf(p
, "%02u DONE\n", i
);
294 p
+= sprintf(p
, "%02u empty\n", i
);
296 p
+= sprintf(p
, "\n");
297 p
+= sprintf(p
, "*** network status ***\n");
298 p
+= sprintf(p
, "dev_state_mask: 0x%04x\n", priv
->dev_state_mask
);
299 p
+= sprintf(p
, "status: %u (%s), macmode_wanted: %u, macmode_joined: %u, channel: %u, reg_dom_id: 0x%02X, reg_dom_chanmask: 0x%04x, txrate_curr: %d, txrate_auto: %d, txrate_cfg: %d, txrate_fallback_retries: %d, txrate_fallbacks: %d/%d, txrate_stepups: %d/%d, bss_table_count: %d\n",
300 priv
->status
, acx100_get_status_name(priv
->status
),
301 priv
->macmode_wanted
, priv
->macmode_joined
, priv
->channel
,
302 priv
->reg_dom_id
, priv
->reg_dom_chanmask
,
303 priv
->txrate_curr
, priv
->txrate_auto
, priv
->txrate_cfg
,
304 priv
->txrate_fallback_retries
,
305 priv
->txrate_fallback_count
, priv
->txrate_fallback_threshold
,
306 priv
->txrate_stepup_count
, priv
->txrate_stepup_threshold
,
307 priv
->bss_table_count
);
308 p
+= sprintf(p
, "ESSID: \"%s\", essid_active: %d, essid_len: %d, essid_for_assoc: \"%s\", nick: \"%s\"\n",
309 priv
->essid
, priv
->essid_active
, (int)priv
->essid_len
,
310 priv
->essid_for_assoc
, priv
->nick
);
311 p
+= sprintf(p
, "monitor: %d, monitor_setting: %d\n",
312 priv
->monitor
, priv
->monitor_setting
);
314 p
+= sprintf(p
, "dev_addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
315 a
[0], a
[1], a
[2], a
[3], a
[4], a
[5]);
317 p
+= sprintf(p
, "address: %02x:%02x:%02x:%02x:%02x:%02x\n",
318 a
[0], a
[1], a
[2], a
[3], a
[4], a
[5]);
320 p
+= sprintf(p
, "bssid: %02x:%02x:%02x:%02x:%02x:%02x\n",
321 a
[0], a
[1], a
[2], a
[3], a
[4], a
[5]);
323 p
+= sprintf(p
, "ap_filter: %02x:%02x:%02x:%02x:%02x:%02x\n",
324 a
[0], a
[1], a
[2], a
[3], a
[4], a
[5]);
326 if ((fw_stats
= kmalloc(sizeof(fw_stats_t
), GFP_KERNEL
)) == NULL
) {
329 p
+= sprintf(p
, "\n");
330 acx100_interrogate(priv
, fw_stats
, ACX100_RID_FIRMWARE_STATISTICS
);
331 p
+= sprintf(p
, "*** Firmware ***\n");
332 p
+= sprintf(p
, "tx_desc_overfl %u, rx_OutOfMem %u, rx_hdr_overfl %u, rx_hdr_use_next %u\n",
333 le32_to_cpu(fw_stats
->tx_desc_of
), le32_to_cpu(fw_stats
->rx_oom
), le32_to_cpu(fw_stats
->rx_hdr_of
), le32_to_cpu(fw_stats
->rx_hdr_use_next
));
334 p
+= sprintf(p
, "rx_dropped_frame %u, rx_frame_ptr_err %u, rx_xfr_hint_trig %u, rx_dma_req %u\n",
335 le32_to_cpu(fw_stats
->rx_dropped_frame
), le32_to_cpu(fw_stats
->rx_frame_ptr_err
), le32_to_cpu(fw_stats
->rx_xfr_hint_trig
), le32_to_cpu(fw_stats
->rx_dma_req
));
336 p
+= sprintf(p
, "rx_dma_err %u, tx_dma_req %u, tx_dma_err %u, cmd_cplt %u, fiq %u\n",
337 le32_to_cpu(fw_stats
->rx_dma_err
), le32_to_cpu(fw_stats
->tx_dma_req
), le32_to_cpu(fw_stats
->tx_dma_err
), le32_to_cpu(fw_stats
->cmd_cplt
), le32_to_cpu(fw_stats
->fiq
));
338 p
+= sprintf(p
, "rx_hdrs %u, rx_cmplt %u, rx_mem_overfl %u, rx_rdys %u, irqs %u\n",
339 le32_to_cpu(fw_stats
->rx_hdrs
), le32_to_cpu(fw_stats
->rx_cmplt
), le32_to_cpu(fw_stats
->rx_mem_of
), le32_to_cpu(fw_stats
->rx_rdys
), le32_to_cpu(fw_stats
->irqs
));
340 p
+= sprintf(p
, "acx_trans_procs %u, decrypt_done %u, dma_0_done %u, dma_1_done %u\n",
341 le32_to_cpu(fw_stats
->acx_trans_procs
), le32_to_cpu(fw_stats
->decrypt_done
), le32_to_cpu(fw_stats
->dma_0_done
), le32_to_cpu(fw_stats
->dma_1_done
));
342 p
+= sprintf(p
, "tx_exch_complet %u, commands %u, acx_rx_procs %u\n",
343 le32_to_cpu(fw_stats
->tx_exch_complet
), le32_to_cpu(fw_stats
->commands
), le32_to_cpu(fw_stats
->acx_rx_procs
));
344 p
+= sprintf(p
, "hw_pm_mode_changes %u, host_acks %u, pci_pm %u, acm_wakeups %u\n",
345 le32_to_cpu(fw_stats
->hw_pm_mode_changes
), le32_to_cpu(fw_stats
->host_acks
), le32_to_cpu(fw_stats
->pci_pm
), le32_to_cpu(fw_stats
->acm_wakeups
));
346 p
+= sprintf(p
, "wep_key_count %u, wep_default_key_count %u, dot11_def_key_mib %u\n",
347 le32_to_cpu(fw_stats
->wep_key_count
), le32_to_cpu(fw_stats
->wep_default_key_count
), le32_to_cpu(fw_stats
->dot11_def_key_mib
));
348 p
+= sprintf(p
, "wep_key_not_found %u, wep_decrypt_fail %u\n",
349 le32_to_cpu(fw_stats
->wep_key_not_found
), le32_to_cpu(fw_stats
->wep_decrypt_fail
));
357 int acx100_proc_eeprom_output(char *buf
, wlandevice_t
*priv
)
365 for (i
= 0; i
< 0x400; i
++)
367 acx100_read_eeprom_offset(priv
, i
, &ch
);
368 p
+= sprintf(p
, "%c", ch
);
375 int acx100_proc_phy_output(char *buf
, wlandevice_t
*priv
)
384 if (RADIO_RFMD_11 != priv->radio_type) {
385 acxlog(L_STD, "Sorry, not yet adapted for radio types other than RFMD, please verify PHY size etc. first!\n");
390 /* The PHY area is only 0x80 bytes long; further pages after that
391 * only have some page number registers with altered value,
392 * all other registers remain the same. */
393 for (i
= 0; i
< 0x80; i
++)
395 acx100_read_phy_reg(priv
, i
, &ch
);
396 p
+= sprintf(p
, "%c", ch
);
403 /*----------------------------------------------------------------
408 * wlandevice: private device that contains card device
418 * resets onboard acx100 MAC
419 *----------------------------------------------------------------*/
421 /* acx100_reset_mac()
422 * Used to be HwReset()
423 * STATUS: should be ok.
425 void acx100_reset_mac(wlandevice_t
*priv
)
427 #if (WLAN_HOSTIF!=WLAN_USB)
433 #if (WLAN_HOSTIF!=WLAN_USB)
435 temp
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_ECPU_CTRL
]) | 0x1;
436 acx100_write_reg16(priv
, priv
->io
[IO_ACX_ECPU_CTRL
], temp
);
438 /* now do soft reset of eCPU */
439 temp
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_SOFT_RESET
]) | 0x1;
440 acxlog(L_BINSTD
, "%s: enable soft reset...\n", __func__
);
441 acx100_write_reg16(priv
, priv
->io
[IO_ACX_SOFT_RESET
], temp
);
443 /* used to be for loop 65536; do scheduled delay instead */
444 acx100_schedule(HZ
/ 100);
446 /* now reset bit again */
447 acxlog(L_BINSTD
, "%s: disable soft reset and go to init mode...\n", __func__
);
448 /* deassert eCPU reset */
449 acx100_write_reg16(priv
, priv
->io
[IO_ACX_SOFT_RESET
], temp
& ~0x1);
451 /* now start a burst read from initial flash EEPROM */
452 temp
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_EE_START
]) | 0x1;
453 acx100_write_reg16(priv
, priv
->io
[IO_ACX_EE_START
], temp
);
456 /* used to be for loop 65536; do scheduled delay instead */
457 acx100_schedule(HZ
/ 100);
462 /*----------------------------------------------------------------
467 * netdevice that contains the wlandevice priv variable
472 * device is hard reset
476 * FIXME: reverse return values
479 * This resets the acx100 device using low level hardware calls
480 * as well as uploads and verifies the firmware to the card
481 *----------------------------------------------------------------*/
483 int acx100_reset_dev(netdevice_t
*dev
)
486 #if (WLAN_HOSTIF!=WLAN_USB)
487 wlandevice_t
*priv
= (wlandevice_t
*)dev
->priv
;
493 /* we're doing a reset, so hardware is unavailable */
494 acxlog(L_INIT
, "reset hw_unavailable++\n");
495 priv
->hw_unavailable
++;
497 /* reset the device to make sure the eCPU is stopped
498 to upload the firmware correctly */
499 acx100_reset_mac(priv
);
501 /* TODO maybe seperate the two init parts into functions */
502 if (priv
->chip_type
== CHIPTYPE_ACX100
) {
504 if (!(vala
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_ECPU_CTRL
]) & 1)) {
505 acxlog(L_BINSTD
, "%s: eCPU already running (%xh)\n", __func__
, vala
);
509 if (0 != (acx100_read_reg16(priv
, priv
->io
[IO_ACX_SOR_CFG
]) & 2)) {
510 /* eCPU most likely means "embedded CPU" */
511 acxlog(L_BINSTD
, "%s: eCPU did not start after boot from flash\n", __func__
);
515 /* load the firmware */
516 if (0 == acx100_upload_fw(priv
)) {
517 acxlog(L_STD
, "%s: Failed to upload firmware to the ACX100\n", __func__
);
521 acx100_write_reg16(priv
, priv
->io
[IO_ACX_ECPU_CTRL
], vala
& ~0x1);
523 } else if (priv
->chip_type
== CHIPTYPE_ACX111
) {
524 if (!(vala
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_ECPU_CTRL
]) & 1)) {
525 acxlog(L_BINSTD
, "%s: eCPU already running (%xh)\n", __func__
, vala
);
529 /* check sense on reset flags */
530 if (0 != (acx100_read_reg16(priv
, priv
->io
[IO_ACX_SOR_CFG
]) & 0x10)) {
531 acxlog(L_BINSTD
, "%s: eCPU do not start after boot (SOR), is this fatal?\n", __func__
);
534 /* load the firmware */
535 if (0 == acx100_upload_fw(priv
)) {
536 acxlog(L_STD
, "%s: Failed to upload firmware to the ACX111\n", __func__
);
540 /* additional reset is needed after the firmware has been downloaded to the card */
541 acx100_reset_mac(priv
);
543 acxlog(L_BINSTD
, "%s: configure interrupt mask at %xh to: %Xh...\n", __func__
,
544 priv
->io
[IO_ACX_IRQ_MASK
], acx100_read_reg16(priv
, priv
->io
[IO_ACX_IRQ_MASK
]) ^ 0x4600);
545 acx100_write_reg16(priv
, priv
->io
[IO_ACX_IRQ_MASK
],
546 acx100_read_reg16(priv
, priv
->io
[IO_ACX_IRQ_MASK
]) ^ 0x4600);
548 acxlog(L_BINSTD
, "%s: boot up eCPU and wait for complete...\n", __func__
);
549 acx100_write_reg16(priv
, priv
->io
[IO_ACX_ECPU_CTRL
], 0x0);
552 /* wait for eCPU bootup */
553 while (!(vala
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_IRQ_STATUS_NON_DES
]) & 0x4000)) {
554 /* ok, let's insert scheduling here.
555 * This was an awfully CPU burning loop.
557 acx100_schedule(HZ
/ 10);
561 acxlog(L_BINSTD
, "Timeout waiting for the ACX100 to complete Initialization (ICOMP), %d\n", vala
);
566 #if (WLAN_HOSTIF!=WLAN_USB)
567 if (0 == acx100_verify_init(priv
)) {
569 "Timeout waiting for the ACX100 to complete Initialization\n");
574 acxlog(L_BINSTD
, "%s: Received signal that card is ready to be configured :) (the eCPU has woken up)\n", __func__
);
576 if (priv
->chip_type
== CHIPTYPE_ACX111
) {
577 acxlog(L_BINSTD
, "%s: Clean up cmd mailbox access area\n", __func__
);
578 acx100_write_cmd_status(priv
, 0);
579 acx100_get_cmd_state(priv
);
580 if(priv
->cmd_status
!= 0) {
581 acxlog(L_BINSTD
, "Error cleaning cmd mailbox area\n");
586 /* TODO what is this one doing ?? adapt for acx111 */
587 if ((0 == acx100_read_eeprom_area(priv
)) && (CHIPTYPE_ACX100
== priv
->chip_type
)) {
588 /* does "CIS" mean "Card Information Structure"?
589 * If so, then this would be a PCMCIA message...
591 acxlog(L_BINSTD
, "CIS error\n");
595 /* reset succeeded, so let's release the hardware lock */
596 acxlog(L_INIT
, "reset hw_unavailable--\n");
597 priv
->hw_unavailable
--;
606 /*----------------------------------------------------------------
609 * Checks if an file exists.
614 * 1 = File can be openend
615 * 0 = Error open file
625 *----------------------------------------------------------------*/
626 int acx100_check_file(const char *file
)
629 inf
= filp_open(file
, O_RDONLY
, 0);
630 if (0 != IS_ERR(inf
)) {
634 filp_close(inf
, NULL
);
639 /*----------------------------------------------------------------
655 *----------------------------------------------------------------*/
660 * Loads a firmware image in from a file.
662 * This seemed like a good idea at the time. I'm not so sure about it now.
663 * perhaps this should be a user mode helper that ioctls the module the firmware?
666 * 0 unable to load file
667 * pointer to firmware success
669 /*@null@*/ firmware_image_t
* acx_read_fw(const char *file
, UINT32
*size
)
671 firmware_image_t
*res
= NULL
;
679 orgfs
= get_fs(); /* store original fs */
682 /* Read in whole file then check the size */
683 page
= __get_free_page(GFP_KERNEL
);
685 acxlog(L_STD
, "Unable to allocate memory for firmware loading.\n");
689 buffer
= (char*)page
;
691 /* Note that file must be given as absolute path:
692 * a relative path works on first loading,
693 * but any subsequent firmware loading during card
694 * eject/insert will fail, most likely since the first
695 * module loading happens in user space (and thus
696 * filp_open can figure out the absolute path from a
697 * relative path) whereas the card reinsert processing
698 * probably happens in kernel space where you don't have
699 * a current directory to be able to figure out an
700 * absolute path from a relative path... */
701 inf
= filp_open(file
, O_RDONLY
, 0);
702 if (0 != IS_ERR(inf
)) {
705 switch(-PTR_ERR(inf
)) {
706 case 2: err
= "file not found - make sure this EXACT filename is in eXaCtLy this directory!";
709 err
= "unknown error";
712 acxlog(L_STD
, "ERROR %ld trying to open firmware image file '%s': %s\n", -PTR_ERR(inf
), file
, err
);
716 if ((NULL
== inf
->f_op
) || (NULL
== inf
->f_op
->read
)) {
717 acxlog(L_STD
, "ERROR: %s does not have a read method\n", file
);
724 retval
= inf
->f_op
->read(inf
, buffer
, PAGE_SIZE
, &inf
->f_pos
);
727 acxlog(L_STD
, "ERROR %d reading firmware image file '%s'.\n", -retval
, file
);
731 } else if (0 == retval
) {
733 acxlog(L_STD
, "ERROR: firmware image file '%s' is empty.\n", file
);
735 } else if (0 < retval
) {
736 /* allocate result buffer here if needed,
737 * since we don't want to waste resources/time
738 * (in case file opening/reading fails)
739 * by doing allocation in front of the loop instead. */
741 *size
= 8 + le32_to_cpu(*(UINT32
*)(4 + buffer
));
743 res
= vmalloc(*size
);
745 acxlog(L_STD
, "ERROR: Unable to allocate %u bytes for firmware module loading.\n", *size
);
749 acxlog(L_STD
, "Allocated %u bytes for firmware module loading.\n", *size
);
751 memcpy((UINT8
*)res
+ offset
, buffer
, retval
);
754 } while (0 < retval
);
757 retval
= filp_close(inf
, NULL
);
760 acxlog(L_STD
, "ERROR %d closing %s\n", -retval
, file
);
763 if ((NULL
!= res
) && (offset
!= le32_to_cpu(res
->size
) + 8)) {
764 acxlog(L_STD
,"Firmware is reporting a different size 0x%08x to read 0x%08x\n", le32_to_cpu(res
->size
) + 8, offset
);
774 /* checksum will be verified in write_fw, so don't bother here */
780 #define NO_AUTO_INCREMENT 1
782 /*----------------------------------------------------------------
784 * Used to be WriteACXImage
786 * Write the firmware image into the card.
789 * priv wlan device structure
790 * apfw_image firmware image.
793 * 0 firmware image corrupted
796 * STATUS: fixed some horrible bugs, should be ok now. FINISHED.
797 ----------------------------------------------------------------*/
799 int acx100_write_fw(wlandevice_t
*priv
, const firmware_image_t
*apfw_image
, UINT32 offset
)
801 #if (WLAN_HOSTIF!=WLAN_USB)
807 /* we skip the first four bytes which contain the control sum. */
808 const UINT8
*image
= (UINT8
*)apfw_image
+ 4;
810 /* start the image checksum by adding the image size value. */
812 for (i
= 0; i
<= 3; i
++, image
++)
816 counter
= 3; /* NONBINARY: this should be moved directly */
817 acc
= 0; /* in front of the loop. */
819 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_END_CTL
], cpu_to_le32(0)); /* be sure we are in little endian mode */
821 #if NO_AUTO_INCREMENT
822 acxlog(L_INIT
, "not using auto increment for firmware loading.\n");
823 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_CTL
], cpu_to_le32(0)); /* use basic mode */
825 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_CTL
], cpu_to_le32(1)); /* use autoincrement mode */
828 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_ADDR
], cpu_to_le32(offset
)); /* configure host indirect memory access address ?? */
830 /* the next four bytes contain the image size. */
831 /* image = apfw_image; */
832 while (len
< le32_to_cpu(apfw_image
->size
)) {
835 acc
|= byte
<< (counter
* 8);
842 /* we upload the image by blocks of four bytes */
844 /* this could probably also be done by doing
845 * 32bit write to register priv->io[IO_ACX_SLV_MEM_DATA]...
846 * But maybe there are cards with 16bit interface
848 #if NO_AUTO_INCREMENT
849 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_ADDR
], cpu_to_le32(offset
+ len
- 4));
852 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_DATA
], cpu_to_le32(acc
));
856 if (len
% 15000 == 0)
858 acx100_schedule(HZ
/ 50);
863 acxlog(L_STD
,"%s: Firmware written.\n", __func__
);
865 /* compare our checksum with the stored image checksum */
866 return (int)(sum
== le32_to_cpu(apfw_image
->chksum
));
872 /*----------------------------------------------------------------
874 * used to be ValidateACXImage
876 * Compare the firmware image given with
877 * the firmware image written into the card.
880 * priv wlan device structure
881 * apfw_image firmware image.
884 * 0 firmware image corrupted or not correctly written
888 ----------------------------------------------------------------*/
890 int acx100_validate_fw(wlandevice_t
*priv
, const firmware_image_t
*apfw_image
, UINT32 offset
)
893 #if (WLAN_HOSTIF!=WLAN_USB)
894 const UINT8
*image
= (UINT8
*)apfw_image
+ 4;
902 /* start the image checksum by adding the image size value. */
903 for (i
= 0; i
<= 3; i
++, image
++)
910 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_END_CTL
], cpu_to_le32(0));
912 #if NO_AUTO_INCREMENT
913 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_CTL
], cpu_to_le32(0));
915 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_CTL
], cpu_to_le32(1));
918 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_ADDR
], cpu_to_le32(offset
));
920 while (len
< le32_to_cpu(apfw_image
->size
)) {
921 acc1
|= *image
<< (counter
* 8);
923 /* acxlog(L_DEBUG, "acc1 %08lx *image %02x len %ld ctr %d\n", acc1, *image, len, counter); */
931 #if NO_AUTO_INCREMENT
932 acx100_write_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_ADDR
], cpu_to_le32(offset
+ len
- 4));
935 acc2
= le32_to_cpu(acx100_read_reg32(priv
, priv
->io
[IO_ACX_SLV_MEM_DATA
]));
938 acxlog(L_STD
, "FATAL: firmware upload: data parts at offset %d don't match!! (0x%08x vs. 0x%08x). Memory defective or timing issues, with DWL-xx0+?? Please report!\n", len
, acc1
, acc2
);
943 sum
+= ((acc2
& 0x000000ff));
944 sum
+= ((acc2
& 0x0000ff00) >> 8);
945 sum
+= ((acc2
& 0x00ff0000) >> 16);
946 sum
+= ((acc2
>> 24));
947 /* acxlog(L_DEBUG, "acc1 %08lx acc2 %08lx sum %08lx\n", acc1, acc2, sum); */
952 if (len
% 15000 == 0)
954 acx100_schedule(HZ
/ 50);
959 /* sum control verification */
961 if (sum
!= le32_to_cpu(apfw_image
->chksum
))
963 /* acxlog(L_DEBUG, "sum 0x%08lx chksum 0x%08x\n", sum, le32_to_cpu(apfw_image->chksum)); */
964 acxlog(L_STD
, "FATAL: firmware upload: checksums don't match!!\n");
972 /*----------------------------------------------------------------
977 * wlandevice: private device that contains card device
989 *----------------------------------------------------------------*/
991 char default_firmware_dir
[] = "/usr/share/acx";
992 int acx100_upload_fw(wlandevice_t
*priv
)
996 firmware_image_t
* apfw_image
;
1002 if (NULL
== firmware_dir
)
1004 firmware_dir
= default_firmware_dir
;
1005 acxlog(L_STD
, "Attention: no custom firmware directory specified (via module parameter firmware_dir), thus using our default firmware directory %s\n", firmware_dir
);
1008 filename
= kmalloc(PATH_MAX
, GFP_USER
);
1011 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
1012 sprintf(filename
,"%s/WLANGEN.BIN", firmware_dir
);
1013 } else if(priv
->chip_type
== CHIPTYPE_ACX111
) {
1014 sprintf(filename
,"%s/TIACX111.BIN", firmware_dir
);
1015 if (0 == acx100_check_file(filename
)) {
1016 acxlog(L_INIT
, "Firmware: '%s' not found. Trying alternative firmware.\n", filename
);
1017 sprintf(filename
,"%s/FwRad16.bin", firmware_dir
);
1022 acxlog(L_INIT
, "Trying to load firmware: '%s'\n", filename
);
1023 apfw_image
= acx_read_fw( filename
, &size
);
1024 if (NULL
== apfw_image
)
1026 acxlog(L_STD
, "acx_read_fw failed.\n");
1031 for (try = 0; try < 5; try++)
1033 res1
= acx100_write_fw(priv
, apfw_image
, 0);
1035 res2
= acx100_validate_fw(priv
, apfw_image
, 0);
1037 acxlog(L_DEBUG
| L_INIT
,
1038 "acx100_write_fw (firmware): %d, acx100_validate_fw: %d\n", res1
, res2
);
1039 if ((0 != res1
) && (0 != res2
))
1041 acxlog(L_STD
, "firmware upload attempt #%d FAILED, retrying...\n", try);
1042 acx100_schedule(HZ
); /* better wait for a while... */
1048 priv
->dev_state_mask
|= ACX_STATE_FW_LOADED
;
1049 FN_EXIT(1, (0 != res1
) && (0 != res2
));
1050 return (int)(((0 != res1
) && (0 != res2
)));
1053 /*----------------------------------------------------------------
1069 *----------------------------------------------------------------*/
1071 /* acx100_load_radio()
1073 * Used to load the appropriate radio module firmware
1076 int acx100_load_radio(wlandevice_t
*priv
)
1080 int res1
= 0, res2
= 0;
1081 firmware_image_t
*radio_image
=0;
1082 radioinit_t radioinit
;
1088 acx100_interrogate(priv
, &mm
, ACX100_RID_MEMORY_MAP
);
1089 offset
= le32_to_cpu(mm
.CodeEnd
);
1091 filename
= kmalloc(PATH_MAX
, GFP_USER
);
1093 acxlog(L_STD
, "ALERT: can't allocate filename\n");
1097 sprintf(filename
,"%s/RADIO%02x.BIN", firmware_dir
, priv
->radio_type
);
1098 acxlog(L_DEBUG
,"trying to read %s\n",filename
);
1099 radio_image
= acx_read_fw(filename
, &size
);
1102 * 0d = RADIO0d.BIN = Maxim chipset
1103 * 11 = RADIO11.BIN = RFMD chipset
1104 * 15 = RADIO15.BIN = UNKNOWN chipset
1107 if (NULL
== radio_image
)
1109 acxlog(L_STD
,"WARNING: no suitable radio module (%s) found to load. No problem in case of a combined firmware, FATAL when using a separated firmware (base firmware / radio image).\n",filename
);
1111 return 1; /* Doesn't need to be fatal, we might be using a combined image */
1114 acx100_issue_cmd(priv
, ACX100_CMD_SLEEP
, NULL
, 0, 5000);
1116 for (try = 0; try < 5; try++)
1118 res1
= acx100_write_fw(priv
, radio_image
, offset
);
1119 res2
= acx100_validate_fw(priv
, radio_image
, offset
);
1120 acxlog(L_DEBUG
| L_INIT
, "acx100_write_fw (radio): %d, acx100_validate_fw: %d\n", res1
, res2
);
1121 if ((0 != res1
) && (0 != res2
))
1123 acxlog(L_STD
, "radio firmware upload attempt #%d FAILED, retrying...\n", try);
1124 acx100_schedule(HZ
); /* better wait for a while... */
1127 acx100_issue_cmd(priv
, ACX100_CMD_WAKE
, NULL
, 0, 5000);
1128 radioinit
.offset
= cpu_to_le32(offset
);
1129 radioinit
.len
= radio_image
->size
; /* no endian conversion needed, remains in card CPU area */
1133 if ((0 == res1
) || (0 == res2
)) return 0;
1135 /* will take a moment so let's have a big timeout */
1136 acx100_issue_cmd(priv
, ACX100_CMD_RADIOINIT
, &radioinit
, sizeof(radioinit
), 120000);
1139 if (0 == acx100_interrogate(priv
, &mm
, ACX100_RID_MEMORY_MAP
))
1141 acxlog(L_STD
, "Error reading memory map\n");
1147 #if (WLAN_HOSTIF!=WLAN_USB)
1148 /*----------------------------------------------------------------
1149 * acx100_verify_init
1164 *----------------------------------------------------------------*/
1166 /* acx100_verify_init()
1167 * ACXWaitForInitComplete()
1168 * STATUS: should be ok.
1170 int acx100_verify_init(wlandevice_t
*priv
)
1177 for (timer
= 100; timer
> 0; timer
--) {
1179 if (0 != (acx100_read_reg16(priv
, priv
->io
[IO_ACX_IRQ_STATUS_NON_DES
]) & 0x4000)) {
1181 acx100_write_reg16(priv
, priv
->io
[IO_ACX_IRQ_ACK
], 0x4000);
1185 /* used to be for loop 65535; do scheduled delay instead */
1186 acx100_schedule(HZ
/ 50);
1194 /*----------------------------------------------------------------
1195 * acx100_init_mboxes
1210 *----------------------------------------------------------------*/
1212 /* acxInitializeMailboxes
1213 STATUS: should be ok.
1215 void acx100_init_mboxes(wlandevice_t
*priv
)
1218 #if (WLAN_HOSTIF!=WLAN_USB)
1219 UINT32 cmd_offs
, info_offs
;
1223 "==> Get the mailbox pointers from the scratch pad registers\n");
1225 cmd_offs
= le32_to_cpu(acx100_read_reg32(priv
, priv
->io
[IO_ACX_CMD_MAILBOX_OFFS
]));
1226 info_offs
= le32_to_cpu(acx100_read_reg32(priv
, priv
->io
[IO_ACX_INFO_MAILBOX_OFFS
]));
1228 acxlog(L_BINDEBUG
, "CmdMailboxOffset = %x\n", cmd_offs
);
1229 acxlog(L_BINDEBUG
, "InfoMailboxOffset = %x\n", info_offs
);
1231 "<== Get the mailbox pointers from the scratch pad registers\n");
1232 priv
->CommandParameters
= priv
->iobase2
+ cmd_offs
+ 0x4;
1233 priv
->InfoParameters
= priv
->iobase2
+ info_offs
+ 0x4;
1234 acxlog(L_BINDEBUG
, "CommandParameters = [ 0x%p ]\n",
1235 priv
->CommandParameters
);
1236 acxlog(L_BINDEBUG
, "InfoParameters = [ 0x%p ]\n",
1237 priv
->InfoParameters
);
1244 /*----------------------------------------------------------------
1260 *----------------------------------------------------------------*/
1262 /* acx100_init_wep()
1263 * STATUS: UNVERIFIED.
1264 * FIXME: this should probably be moved into the new card settings
1265 * management, but since we're also initializing the memory map layout here
1266 * depending on the WEP keys, we should take care...
1268 int acx100_init_wep(wlandevice_t
*priv
, acx100_memmap_t
*pt
)
1271 acx100_wep_options_t options
;
1272 dot11WEPDefaultKey_t wp
;
1273 dot11WEPDefaultKeyID_t dk
;
1274 acx100_wep_mgmt_t wep_mgmt
; /* size = 37 bytes */
1280 acxlog(L_STATE
, "%s: UNVERIFIED.\n", __func__
);
1282 if (acx100_interrogate(priv
, pt
, ACX100_RID_MEMORY_MAP
) == 0) {
1283 acxlog(L_STD
, "ctlMemoryMapRead failed!\n");
1287 acxlog(L_BINDEBUG
, "CodeEnd:%X\n", pt
->CodeEnd
);
1289 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
1291 pt
->WEPCacheStart
= cpu_to_le32(le32_to_cpu(pt
->CodeEnd
) + 0x4);
1292 pt
->WEPCacheEnd
= cpu_to_le32(le32_to_cpu(pt
->CodeEnd
) + 0x4);
1294 if (acx100_configure(priv
, pt
, ACX100_RID_MEMORY_MAP
) == 0) {
1295 acxlog(L_STD
, "%s: ctlMemoryMapWrite failed!\n", __func__
);
1301 /* FIXME: what kind of specific memmap struct is used here? */
1302 options
.NumKeys
= cpu_to_le16(0x000e);
1303 options
.WEPOption
= (UINT8
)0x00;
1305 acxlog(L_ASSOC
, "%s: writing WEP options.\n", __func__
);
1306 acx100_configure(priv
, &options
, ACX100_RID_WEP_OPTIONS
);
1307 key
= &wp
.defaultKeyNum
;
1308 for (i
= 0; i
<= 3; i
++) {
1309 if (priv
->wep_keys
[i
].size
!= 0) {
1310 wp
.Action
= (UINT8
)1;
1311 wp
.KeySize
= (UINT8
)priv
->wep_keys
[i
].size
;
1312 wp
.defaultKeyNum
= priv
->wep_keys
[i
].index
;
1313 memcpy(key
, &priv
->wep_keys
[i
].key
, priv
->wep_keys
[i
].size
);
1314 acxlog(L_ASSOC
, "%s: writing default WEP key.\n", __func__
);
1315 acx100_configure(priv
, &wp
, ACX100_RID_DOT11_WEP_DEFAULT_KEY_SET
);
1318 if (priv
->wep_keys
[priv
->wep_current_index
].size
!= 0) {
1319 acxlog(L_ASSOC
, "setting default WEP key number: %d.\n", priv
->wep_current_index
);
1320 dk
.KeyID
= priv
->wep_current_index
;
1321 acx100_configure(priv
, &dk
, ACX100_RID_DOT11_WEP_KEY
);
1323 /* FIXME!!! wep_key_struct is filled nowhere! */
1324 for (i
= 0; i
<= 9; i
++) {
1325 if (priv
->wep_key_struct
[i
].len
!= 0) {
1326 MAC_COPY(wep_mgmt
.MacAddr
, priv
->wep_key_struct
[i
].addr
);
1327 wep_mgmt
.KeySize
= cpu_to_le16(priv
->wep_key_struct
[i
].len
);
1328 memcpy(&wep_mgmt
.Key
, priv
->wep_key_struct
[i
].key
, le16_to_cpu(wep_mgmt
.KeySize
));
1329 wep_mgmt
.Action
= cpu_to_le16(1);
1330 acxlog(L_ASSOC
, "writing WEP key %d (len %d).\n", i
, le16_to_cpu(wep_mgmt
.KeySize
));
1331 /* FIXME: should we write sizeof or instead
1333 if (0 != acx100_issue_cmd(priv
, ACX100_CMD_WEP_MGMT
, &wep_mgmt
, sizeof(wep_mgmt
), 5000)) {
1334 priv
->wep_key_struct
[i
].index
= i
;
1339 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
1341 if (0 == acx100_interrogate(priv
, pt
, ACX100_RID_MEMORY_MAP
)) {
1342 acxlog(L_STD
, "ctlMemoryMapRead #2 failed!\n");
1345 pt
->PacketTemplateStart
= pt
->WEPCacheEnd
; /* no endianness conversion needed */
1347 if (0 == acx100_configure(priv
, pt
, ACX100_RID_MEMORY_MAP
)) {
1348 acxlog(L_STD
, "ctlMemoryMapWrite #2 failed!\n");
1357 int acx100_init_max_null_data_template(wlandevice_t
*priv
)
1359 struct acxp80211_nullframe b
;
1363 memset(&b
, 0, sizeof(struct acxp80211_nullframe
));
1364 b
.size
= cpu_to_le16(sizeof(struct acxp80211_nullframe
) - 2);
1365 result
= acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_NULL_DATA
, &b
, sizeof(struct acxp80211_nullframe
), 5000);
1370 /*----------------------------------------------------------------
1371 * acx100_init_max_beacon_template
1386 *----------------------------------------------------------------*/
1388 /* acx100_init_max_beacon_template()
1389 * InitMaxACXBeaconTemplate()
1390 * STATUS: should be ok.
1392 int acx100_init_max_beacon_template(wlandevice_t
*priv
)
1394 struct acxp80211_beacon_prb_resp_template b
;
1398 memset(&b
, 0, sizeof(struct acxp80211_beacon_prb_resp_template
));
1399 b
.size
= cpu_to_le16(sizeof(struct acxp80211_beacon_prb_resp
));
1400 result
= acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_BEACON
, &b
, sizeof(struct acxp80211_beacon_prb_resp_template
), 5000);
1406 /* acx100_init_max_tim_template()
1407 * InitMaxACXTIMTemplate()
1408 * STATUS: should be ok.
1410 int acx100_init_max_tim_template(wlandevice_t
*priv
)
1414 memset(&t
, 0, sizeof(struct tim
));
1415 t
.size
= cpu_to_le16(sizeof(struct tim
) - 0x2); /* subtract size of size field */
1416 return acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_TIM
, &t
, sizeof(struct tim
), 5000);
1419 /*----------------------------------------------------------------
1420 * acx100_init_max_probe_response_template
1435 *----------------------------------------------------------------*/
1437 /* acx100_init_max_probe_response_template()
1438 * InitMaxACXProbeResponseTemplate()
1439 * STATUS: should be ok.
1441 int acx100_init_max_probe_response_template(wlandevice_t
*priv
)
1443 struct acxp80211_beacon_prb_resp_template pr
;
1445 memset(&pr
, 0, sizeof(struct acxp80211_beacon_prb_resp_template
));
1446 pr
.size
= cpu_to_le16(sizeof(struct acxp80211_beacon_prb_resp
));
1448 return acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_PROBE_RESPONSE
, &pr
, sizeof(struct acxp80211_beacon_prb_resp_template
), 5000);
1451 /*----------------------------------------------------------------
1452 * acx100_init_max_probe_request_template
1467 *----------------------------------------------------------------*/
1469 /* acx100_init_max_probe_request_template()
1470 * InitMaxACXProbeRequestTemplate()
1471 * STATUS: should be ok.
1473 int acx100_init_max_probe_request_template(wlandevice_t
*priv
)
1478 memset(&pr
, 0, sizeof(struct probereq
));
1479 pr
.size
= cpu_to_le16(sizeof(struct probereq
) - 0x2); /* subtract size of size field */
1480 return acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_PROBE_REQUEST
, &pr
, sizeof(struct probereq
), 5000);
1483 /*----------------------------------------------------------------
1484 * acx100_set_tim_template
1499 *----------------------------------------------------------------*/
1501 /* acx100_set_tim_template()
1502 * SetACXTIMTemplate()
1503 * STATUS: should be ok.
1505 int acx100_set_tim_template(wlandevice_t
*priv
)
1511 t
.buf
[0x0] = (UINT8
)0x5;
1512 t
.buf
[0x1] = (UINT8
)0x4;
1513 t
.buf
[0x2] = (UINT8
)0x0;
1514 t
.buf
[0x3] = (UINT8
)0x0;
1515 t
.buf
[0x4] = (UINT8
)0x0;
1516 t
.buf
[0x5] = (UINT8
)0x0;
1517 t
.buf
[0x6] = (UINT8
)0x0;
1518 t
.buf
[0x7] = (UINT8
)0x0;
1519 t
.buf
[0x8] = (UINT8
)0x0;
1520 t
.buf
[0x9] = (UINT8
)0x0;
1521 t
.buf
[0xa] = (UINT8
)0x0;
1522 result
= acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_TIM
, &t
, sizeof(struct tim
), 5000);
1523 if (++DTIM_count
== priv
->dtim_interval
) {
1524 DTIM_count
= (UINT8
)0;
1530 /*----------------------------------------------------------------
1531 * acx100_set_generic_beacon_probe_response_frame
1546 *----------------------------------------------------------------*/
1548 /* SetACXGenericBeaconProbeResponseFrame()
1550 * For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!!
1553 * fishy status fixed
1555 int acx100_set_generic_beacon_probe_response_frame(wlandevice_t
*priv
,
1556 struct acxp80211_beacon_prb_resp
*bcn
)
1565 MAC_BCAST(bcn
->hdr
.a1
);
1566 MAC_COPY(bcn
->hdr
.a2
, priv
->dev_addr
);
1567 MAC_COPY(bcn
->hdr
.a3
, priv
->bssid
);
1570 /*** set entry 1: Timestamp field (8 octets) ***/
1571 /* FIXME: Strange usage of struct, is it ok ?
1572 * Answer: sort of. The current struct definition is for *one*
1573 * specific packet type only (and thus not for a Probe Response);
1574 * this needs to be redefined eventually */
1575 memset(bcn
->timestamp
, 0, 8);
1577 /*** set entry 2: Beacon Interval (2 octets) ***/
1578 bcn
->beacon_interval
= cpu_to_le16(priv
->beacon_interval
);
1580 /*** set entry 3: Capability information (2 octets) ***/
1581 acx100_update_capabilities(priv
);
1582 bcn
->caps
= cpu_to_le16(priv
->capabilities
);
1584 /* set initial frame_len to 36: A3 header (24) + 8 UINT8 + 2 UINT16 */
1585 frame_len
= WLAN_HDR_A3_LEN
+ 8 + 2 + 2;
1587 /*** set entry 4: SSID (2 + (0 to 32) octets) ***/
1588 acxlog(L_ASSOC
, "SSID = %s, len = %i\n", priv
->essid
, priv
->essid_len
);
1589 this = &bcn
->info
[0];
1590 this[0] = 0; /* "SSID Element ID" */
1591 this[1] = priv
->essid_len
; /* "Length" */
1592 memcpy(&this[2], priv
->essid
, priv
->essid_len
);
1593 frame_len
+= 2 + priv
->essid_len
;
1595 /*** set entry 5: Supported Rates (2 + (1 to 8) octets) ***/
1596 this = &bcn
->info
[2 + priv
->essid_len
];
1598 this[0] = 1; /* "Element ID" */
1599 this[1] = priv
->rate_spt_len
;
1600 if (priv
->rate_spt_len
> 2) {
1601 for (i
= 2; i
< priv
->rate_spt_len
; i
++) {
1602 priv
->rate_support1
[i
] &= ~0x80;
1605 memcpy(&this[2], priv
->rate_support1
, priv
->rate_spt_len
);
1606 frame_len
+= 2 + this[1]; /* length calculation is not split up like that, but it's much cleaner that way. */
1608 /*** set entry 6: DS Parameter Set (2 + 1 octets) ***/
1609 this = &this[2 + this[1]];
1610 this[0] = 3; /* "Element ID": "DS Parameter Set element" */
1611 this[1] = 1; /* "Length" */
1612 this[2] = priv
->channel
; /* "Current Channel" */
1613 frame_len
+= 2 + 1; /* ok, now add the remaining 3 bytes */
1615 FN_EXIT(1, frame_len
);
1620 /*----------------------------------------------------------------
1621 * acx100_set_beacon_template
1636 *----------------------------------------------------------------*/
1638 /* acx100_set_beacon_template()
1639 * SetACXBeaconTemplate()
1642 int acx100_set_beacon_template(wlandevice_t
*priv
)
1644 struct acxp80211_beacon_prb_resp_template bcn
;
1649 memset(&bcn
, 0, sizeof(struct acxp80211_beacon_prb_resp_template
));
1650 len
= acx100_set_generic_beacon_probe_response_frame(priv
, &bcn
.pkt
);
1651 bcn
.pkt
.hdr
.fc
= cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT
) | WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_BEACON
)); /* 0x80 */
1652 bcn
.size
= cpu_to_le16(len
);
1653 acxlog(L_BINDEBUG
, "Beacon length:%d\n", (UINT16
) len
);
1655 len
+= 2; /* add length of "size" field */
1656 result
= acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_BEACON
, &bcn
, len
, 5000);
1663 /*----------------------------------------------------------------
1664 * acx100_init_packet_templates
1679 *----------------------------------------------------------------*/
1681 /* acx100_init_packet_templates()
1683 * NOTE: order is very important here, to have a correct memory layout!
1684 * init templates: max Probe Request (station mode), max NULL data,
1685 * max Beacon, max TIM, max Probe Response.
1687 * acxInitPacketTemplates()
1688 * STATUS: almost ok, except for struct definitions.
1690 int acx100_init_packet_templates(wlandevice_t
*priv
, acx100_memmap_t
*mm
)
1692 int len
= 0; /* not important, only for logging */
1698 /* FIXME: creating the NULL data template breaks
1699 * communication right now, needs further testing.
1700 * Also, need to set the template once we're joining a network. */
1701 if (!acx100_init_max_null_data_template(priv
))
1703 len
+= sizeof(struct acxp80211_hdr
) + 2;
1706 if (0 == acx100_init_max_beacon_template(priv
))
1708 len
+= sizeof(struct acxp80211_beacon_prb_resp_template
);
1710 /* TODO: beautify code by moving init_tim down just before
1712 if (0 == acx100_init_max_tim_template(priv
))
1714 len
+= sizeof(struct tim
);
1716 if (0 == acx100_init_max_probe_response_template(priv
))
1718 len
+= sizeof(struct acxp80211_hdr
) + 2;
1720 if (0 == acx100_set_tim_template(priv
))
1723 /* the acx111 should set up its memory by itself (or I hope so..) */
1724 if (CHIPTYPE_ACX100
== priv
->chip_type
) {
1726 if (0 == acx100_interrogate(priv
, mm
, ACX100_RID_MEMORY_MAP
)) {
1727 acxlog(L_BINDEBUG
| L_INIT
, "interrogate failed\n");
1731 mm
->QueueStart
= cpu_to_le32(le32_to_cpu(mm
->PacketTemplateEnd
) + 4);
1732 if (0 == acx100_configure(priv
, mm
, ACX100_RID_MEMORY_MAP
)) {
1733 acxlog(L_BINDEBUG
| L_INIT
, "configure failed\n");
1742 acxlog(L_BINDEBUG
| L_INIT
, "cb =0x%X\n", len
);
1743 acxlog(L_BINDEBUG
| L_INIT
, "pACXMemoryMap->CodeStart= 0x%X\n",
1744 le32_to_cpu(mm
->CodeStart
));
1745 acxlog(L_BINDEBUG
| L_INIT
, "pACXMemoryMap->CodeEnd = 0x%X\n",
1746 le32_to_cpu(mm
->CodeEnd
));
1747 acxlog(L_BINDEBUG
| L_INIT
, "pACXMemoryMap->WEPCacheStart= 0x%X\n",
1748 le32_to_cpu(mm
->WEPCacheStart
));
1749 acxlog(L_BINDEBUG
| L_INIT
, "pACXMemoryMap->WEPCacheEnd = 0x%X\n",
1750 le32_to_cpu(mm
->WEPCacheEnd
));
1751 acxlog(L_BINDEBUG
| L_INIT
,
1752 "pACXMemoryMap->PacketTemplateStart= 0x%X\n",
1753 le32_to_cpu(mm
->PacketTemplateStart
));
1754 acxlog(L_BINDEBUG
| L_INIT
,
1755 "pACXMemoryMap->PacketTemplateEnd = 0x%X\n",
1756 le32_to_cpu(mm
->PacketTemplateEnd
));
1763 int acx111_init_packet_templates(wlandevice_t
*priv
, memmap_t
* mm
)
1769 acxlog(L_BINDEBUG
| L_INIT
, "%s: Init max packet templates\n", __func__
);
1771 if (!acx100_init_max_probe_request_template(priv
))
1774 if (!acx100_init_max_null_data_template(priv
))
1777 if (!acx100_init_max_beacon_template(priv
))
1780 if (!acx100_init_max_tim_template(priv
))
1783 if (!acx100_init_max_probe_response_template(priv
))
1786 /* the other templates will be set later (acx100_start)*/
1788 if (!acx100_set_tim_template(priv))
1795 acxlog(L_BINDEBUG
| L_INIT
, "%s: packet template configuration failed\n", __func__
);
1803 /* FIXME: this should be solved in a general way for all radio types
1804 * by decoding the radio firmware module,
1805 * since it probably has some standard structure describing how to
1806 * set the power level of the radio module which it controls.
1807 * Or maybe not, since the radio module probably has a function interface
1808 * instead which then manages Tx level programming :-\
1810 static inline int acx100_set_tx_level(wlandevice_t
*priv
, UINT8 level
)
1812 /* since it can be assumed that at least the Maxim radio has a
1813 * maximum power output of 20dBm and since it also can be
1814 * assumed that these values drive the DAC responsible for
1815 * setting the linear Tx level, I'd guess that these values
1816 * should be the corresponding linear values for a dBm value,
1817 * in other words: calculate the values from that formula:
1818 * Y [dBm] = 10 * log (X [mW])
1819 * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
1820 * and you're done...
1821 * Hopefully that's ok, but you never know if we're actually
1822 * right... (especially since Windows XP doesn't seem to show
1823 * actual Tx dBm values :-P) */
1824 #if (WLAN_HOSTIF!=WLAN_USB)
1825 UINT8 dbm2val_maxim
[21] = {
1826 (UINT8
)63, (UINT8
)63, (UINT8
)63, (UINT8
)62,
1827 (UINT8
)61, (UINT8
)61, (UINT8
)60, (UINT8
)60,
1828 (UINT8
)59, (UINT8
)58, (UINT8
)57, (UINT8
)55,
1829 (UINT8
)53, (UINT8
)50, (UINT8
)47, (UINT8
)43,
1830 (UINT8
)38, (UINT8
)31, (UINT8
)23, (UINT8
)13,
1833 UINT8 dbm2val_rfmd
[21] = {
1834 (UINT8
)0, (UINT8
)0, (UINT8
)0, (UINT8
)1,
1835 (UINT8
)2, (UINT8
)2, (UINT8
)3, (UINT8
)3,
1836 (UINT8
)4, (UINT8
)5, (UINT8
)6, (UINT8
)8,
1837 (UINT8
)10, (UINT8
)13, (UINT8
)16, (UINT8
)20,
1838 (UINT8
)25, (UINT8
)32, (UINT8
)41, (UINT8
)50,
1843 switch (priv
->radio_type
) {
1844 case RADIO_MAXIM_0D
:
1845 table
= &dbm2val_maxim
[0];
1848 table
= &dbm2val_rfmd
[0];
1851 acxlog(L_STD
, "FIXME: unknown/unsupported radio type, cannot modify Tx power level yet!\n");
1854 acxlog(L_STD
, "changing radio power level to %d dBm (0x%02x)\n", level
, table
[level
]);
1855 acx100_write_phy_reg(priv
, 0x11, table
[level
]);
1860 /*----------------------------------------------------------------
1876 *----------------------------------------------------------------*/
1879 * STATUS: should be ok, but struct not classified yet.
1881 void acx100_scan_chan(wlandevice_t
*priv
)
1884 memset(&s
, 0, sizeof(struct scan
));
1886 acxlog(L_INIT
, "Starting radio scan\n");
1888 if(priv
->chip_type
== CHIPTYPE_ACX111
) {
1889 acxlog(L_STD
, "ERROR: trying to invoke acx100_scan_chan, but wlandevice == acx111!\n");
1893 /* now that we're starting a new scan, reset the number of stations
1894 * found in range back to 0.
1895 * (not doing so would keep outdated stations in our list,
1896 * and if we decide to associate to "any" station, then we'll always
1897 * pick an outdated one) */
1898 priv
->bss_table_count
= 0;
1899 acx100_set_status(priv
, ISTATUS_1_SCANNING
);
1900 s
.count
= cpu_to_le16(priv
->scan_count
);
1901 s
.start_chan
= cpu_to_le16(1);
1902 s
.flags
= cpu_to_le16(0x8000);
1903 s
.max_rate
= 20; /* 2 Mbps */
1904 s
.options
= priv
->scan_mode
;
1906 s
.chan_duration
= cpu_to_le16(priv
->scan_duration
);
1907 s
.max_probe_delay
= cpu_to_le16(priv
->scan_probe_delay
);
1909 acx100_issue_cmd(priv
, ACX100_CMD_SCAN
, &s
, sizeof(struct scan
), 5000);
1914 void acx111_scan_chan(wlandevice_t
*priv
) {
1916 struct acx111_scan s
;
1917 memset(&s
, 0, sizeof(struct acx111_scan
));
1919 acxlog(L_INIT
, "Starting radio scan\n");
1922 s
.channel_list_select
= 0; /* scan every allowed channel */
1923 /*s.channel_list_select = 1;*/ /* scan given channels */
1926 /*s.rate = 0x0a;*/ /* 1 Mbs */
1927 s
.rate
= 0x14; /* 2 Mbs */
1928 /*s.rate = 0x0c;*/ /* 54 Mbs */
1929 /*s.options = ACX_SCAN_ACTIVE;*/
1930 s
.options
= ACX_SCAN_PASSIVE
;
1931 /*s.options = ACX_SCAN_PASSIVE | ACX_SCAN_BACKGROUND;*/ /* do an passive background scan */
1932 s
.chan_duration
= 50;
1933 s
.max_probe_delay
= 200;
1934 /*s.modulation = 0x40;*/ /* long preamble ? ofdm ? -> only for active scan*/
1936 /*s.channel_list[0] = 6;
1937 s.channel_list[1] = 4;*/
1939 acx111_scan_chan_p(priv
, &s
);
1943 /* AcxScanWithParam()
1944 * STATUS: should be ok.
1946 void acx100_scan_chan_p(wlandevice_t
*priv
, struct scan
*s
)
1949 acx100_set_status(priv
, ISTATUS_1_SCANNING
);
1951 acx100_issue_cmd(priv
, ACX100_CMD_SCAN
, s
, sizeof(struct scan
), 5000);
1955 /* AcxScanWithParam()
1956 * STATUS: should be ok.
1958 void acx111_scan_chan_p(wlandevice_t
*priv
, struct acx111_scan
*s
)
1961 acx100_set_status(priv
, ISTATUS_1_SCANNING
);
1962 acx100_issue_cmd(priv
, ACX100_CMD_SCAN
, s
, sizeof(struct acx111_scan
), 5000);
1967 void acx100_update_card_settings(wlandevice_t
*priv
, int init
, int get_all
, int set_all
)
1969 #ifdef BROKEN_LOCKING
1970 unsigned long flags
;
1976 #ifdef BROKEN_LOCKING
1978 /* cannot use acx100_lock() - hw_unavailable is set */
1979 local_irq_save(flags
);
1980 if (!spin_trylock(&priv
->lock
)) {
1981 printk(KERN_EMERG
"ARGH! Lock already taken in %s:%d\n", __FILE__
, __LINE__
);
1982 local_irq_restore(flags
);
1986 printk("Lock taken in %s\n", __func__
);
1989 if (acx100_lock(priv
, &flags
)) {
1996 if ((0 == init
) && (0 == (ACX_STATE_IFACE_UP
& priv
->dev_state_mask
))) {
1997 acxlog(L_DEBUG
, "iface not up, won't update card settings yet!\n");
2002 priv
->get_mask
|= GETSET_ALL
;
2004 priv
->set_mask
|= GETSET_ALL
;
2006 acxlog(L_INIT
, "get_mask 0x%08x, set_mask 0x%08x\n",
2007 priv
->get_mask
, priv
->set_mask
);
2009 /* send a disassoc request in case it's required */
2010 if (0 != (priv
->set_mask
& (GETSET_MODE
|GETSET_ESSID
|GETSET_CHANNEL
|GETSET_ALL
))) {
2011 if (ACX_MODE_3_MANAGED_AP
!= priv
->macmode_joined
) {
2012 if (ISTATUS_4_ASSOCIATED
== priv
->status
)
2014 acxlog(L_ASSOC
, "status was ASSOCIATED -> sending disassoc request.\n");
2015 acx100_transmit_disassoc(NULL
, priv
);
2017 acxlog(L_DEBUG
, "resetting bssid\n");
2018 MAC_FILL(priv
->bssid
, 0x0);
2019 acx100_set_status(priv
, ISTATUS_0_STARTED
);
2023 if (0 != priv
->get_mask
) {
2024 if (0 != (priv
->get_mask
& (GET_STATION_ID
|GETSET_ALL
))) {
2025 UINT8 stationID
[4 + ACX100_RID_DOT11_STATION_ID_LEN
];
2029 acx100_interrogate(priv
, &stationID
, ACX100_RID_DOT11_STATION_ID
);
2030 paddr
= &stationID
[4];
2031 for (i
= 0; i
< 6; i
++) {
2032 /* we copy the MAC address (reversed in
2033 * the card) to the netdevice's MAC
2034 * address, and on ifup it will be
2035 * copied into iwpriv->dev_addr */
2036 priv
->netdev
->dev_addr
[5 - i
] = paddr
[i
];
2038 priv
->get_mask
&= ~GET_STATION_ID
;
2041 if (0 != (priv
->get_mask
& (GETSET_SENSITIVITY
|GETSET_ALL
))) {
2042 if ((RADIO_RFMD_11
== priv
->radio_type
) || (RADIO_MAXIM_0D
== priv
->radio_type
)) {
2043 acx100_read_phy_reg(priv
, 0x30, &priv
->sensitivity
);
2045 acxlog(L_STD
, "ERROR: don't know how to get sensitivity for this radio type, please try to add that!\n");
2046 priv
->sensitivity
= 0;
2048 acxlog(L_INIT
, "Got sensitivity value %d\n", priv
->sensitivity
);
2050 priv
->get_mask
&= ~GETSET_SENSITIVITY
;
2053 if (0 != (priv
->get_mask
& (GETSET_ANTENNA
|GETSET_ALL
))) {
2054 UINT8 antenna
[4 + ACX100_RID_DOT11_CURRENT_ANTENNA_LEN
];
2056 memset(antenna
, 0, sizeof(antenna
));
2057 acx100_interrogate(priv
, antenna
, ACX100_RID_DOT11_CURRENT_ANTENNA
);
2058 priv
->antenna
= antenna
[4];
2059 acxlog(L_INIT
, "Got antenna value 0x%02X\n", priv
->antenna
);
2060 priv
->get_mask
&= ~GETSET_ANTENNA
;
2063 if (0 != (priv
->get_mask
& (GETSET_ED_THRESH
|GETSET_ALL
))) {
2064 UINT8 ed_threshold
[4 + ACX100_RID_DOT11_ED_THRESHOLD_LEN
];
2066 memset(ed_threshold
, 0, sizeof(ed_threshold
));
2067 acx100_interrogate(priv
, ed_threshold
, ACX100_RID_DOT11_ED_THRESHOLD
);
2068 priv
->ed_threshold
= ed_threshold
[4];
2069 acxlog(L_INIT
, "Got Energy Detect (ED) threshold %d\n", priv
->ed_threshold
);
2070 priv
->get_mask
&= ~GETSET_ED_THRESH
;
2073 if (0 != (priv
->get_mask
& (GETSET_CCA
|GETSET_ALL
))) {
2074 UINT8 cca
[4 + ACX100_RID_DOT11_CURRENT_CCA_MODE_LEN
];
2076 memset(cca
, 0, sizeof(priv
->cca
));
2077 acx100_interrogate(priv
, cca
, ACX100_RID_DOT11_CURRENT_CCA_MODE
);
2079 acxlog(L_INIT
, "Got Channel Clear Assessment (CCA) (CCA) (CCA) (CCA) (CCA) (CCA) (CCA) (CCA) (CCA) value %d\n", priv
->cca
);
2080 priv
->get_mask
&= ~GETSET_CCA
;
2083 if (0 != (priv
->get_mask
& (GETSET_REG_DOMAIN
|GETSET_ALL
))) {
2086 acx100_interrogate(priv
, &dom
, ACX100_RID_DOT11_CURRENT_REG_DOMAIN
);
2087 priv
->reg_dom_id
= dom
.m
.gp
.bytes
[0];
2088 /* FIXME: should also set chanmask somehow */
2089 acxlog(L_INIT
, "Got regulatory domain 0x%02X\n", priv
->reg_dom_id
);
2090 priv
->get_mask
&= ~GETSET_REG_DOMAIN
;
2094 if (0 != (priv
->set_mask
& (SET_TEMPLATES
|GETSET_ALL
))) {
2095 priv
->set_mask
&= ~SET_TEMPLATES
;
2096 if (ACX_MODE_2_MANAGED_STA
!= priv
->macmode_wanted
) {
2097 if (0 == acx100_set_beacon_template(priv
)) {
2099 "acx100_set_beacon_template failed.\n");
2101 if (0 == acx100_set_probe_response_template(priv
)) {
2103 "acx100_set_probe_response_template failed.\n");
2107 if (0 != (priv
->set_mask
& (SET_STA_LIST
|GETSET_ALL
))) {
2108 /* TODO insert a sweet if here */
2109 acx100_sta_list_init(priv
);
2110 priv
->set_mask
&= ~SET_STA_LIST
;
2113 if (0 != (priv
->set_mask
& (SET_RATE_FALLBACK
|GETSET_ALL
))) {
2114 UINT8 rate
[4 + ACX100_RID_RATE_FALLBACK_LEN
];
2116 /* configure to not do fallbacks when not in auto rate mode */
2117 rate
[4] = (0 != priv
->txrate_auto
) ? priv
->txrate_fallback_retries
: 0;
2118 acxlog(L_INIT
, "Updating Tx fallback to %d retries\n", rate
[4]);
2119 acx100_configure(priv
, &rate
, ACX100_RID_RATE_FALLBACK
);
2120 priv
->set_mask
&= ~SET_RATE_FALLBACK
;
2123 if (0 != (priv
->set_mask
& (GETSET_WEP
|GETSET_ALL
))) {
2125 acxlog(L_INIT
, "Updating WEP key settings\n");
2137 for (i
= 0; i
< NUM_WEPKEYS
; i
++) {
2138 if (priv
->wep_keys
[i
].size
!= 0) {
2140 acxlog(L_INIT
, "Setting WEP key: %d with size: %d\n", i
, priv
->wep_keys
[i
].size
);
2143 var_9ac
.val0x5
= priv
->wep_keys
[i
].size
;
2145 memcpy(var_9ac
.key
, priv
->wep_keys
[i
].key
,
2148 acx100_configure(priv
, &var_9ac
, ACX100_RID_DOT11_WEP_KEY
);
2151 /* TODO ACX111 CODE, not working yet, when activated no AP will be found :( */
2153 memset(data
, 0, 400),
2155 data
[0xD] = priv
->wep_keys
[i
].size
;
2159 memcpy(&data
[0x17], priv
->wep_keys
[i
].key
, priv
->wep_keys
[i
].size
);
2161 acx100_issue_cmd(priv
, ACX100_CMD_WEP_MGMT
, &data
[4], 0x17 + priv
->wep_keys
[i
].size
- 4, 5000);
2166 dkey
.m
.dkey
.num
= priv
->wep_current_index
;
2167 acxlog(L_INIT
, "Setting WEP key: %d as default.\n", dkey
.m
.dkey
.num
);
2168 acx100_configure(priv
, &dkey
, ACX100_RID_DOT11_WEP_DEFAULT_KEY_SET
);
2170 priv
->set_mask
&= ~GETSET_WEP
;
2173 if (0 != (priv
->set_mask
& (GETSET_TXPOWER
|GETSET_ALL
))) {
2174 acxlog(L_INIT
, "Updating transmit power: %d dBm\n",
2175 priv
->tx_level_dbm
);
2176 acx100_set_tx_level(priv
, priv
->tx_level_dbm
);
2177 priv
->set_mask
&= ~GETSET_TXPOWER
;
2180 if (0 != (priv
->set_mask
& (GETSET_SENSITIVITY
|GETSET_ALL
))) {
2181 acxlog(L_INIT
, "Updating sensitivity value: %d\n",
2183 if ((RADIO_RFMD_11
== priv
->radio_type
) || (RADIO_MAXIM_0D
== priv
->radio_type
)) {
2184 acx100_write_phy_reg(priv
, 0x30, priv
->sensitivity
);
2186 acxlog(L_STD
, "ERROR: don't know how to set sensitivity for this radio type, please try to add that!\n");
2188 priv
->set_mask
&= ~GETSET_SENSITIVITY
;
2191 if (0 != (priv
->set_mask
& (GETSET_ANTENNA
|GETSET_ALL
))) {
2193 UINT8 antenna
[4 + ACX100_RID_DOT11_CURRENT_ANTENNA_LEN
];
2195 memset(antenna
, 0, sizeof(antenna
));
2196 antenna
[4] = priv
->antenna
;
2197 acxlog(L_INIT
, "Updating antenna value: 0x%02X\n",
2199 acx100_configure(priv
, &antenna
, ACX100_RID_DOT11_CURRENT_ANTENNA
);
2200 priv
->set_mask
&= ~GETSET_ANTENNA
;
2203 if (0 != (priv
->set_mask
& (GETSET_ED_THRESH
|GETSET_ALL
))) {
2205 UINT8 ed_threshold
[4 + ACX100_RID_DOT11_ED_THRESHOLD_LEN
];
2207 memset(ed_threshold
, 0, sizeof(ed_threshold
));
2208 ed_threshold
[4] = priv
->ed_threshold
;
2209 acxlog(L_INIT
, "Updating Energy Detect (ED) threshold: %d\n",
2211 acx100_configure(priv
, &ed_threshold
, ACX100_RID_DOT11_ED_THRESHOLD
);
2212 priv
->set_mask
&= ~GETSET_ED_THRESH
;
2215 if (0 != (priv
->set_mask
& (GETSET_CCA
|GETSET_ALL
))) {
2217 UINT8 cca
[4 + ACX100_RID_DOT11_CURRENT_CCA_MODE_LEN
];
2219 memset(cca
, 0, sizeof(cca
));
2221 acxlog(L_INIT
, "Updating Channel Clear Assessment (CCA) value: 0x%02X\n", cca
[4]);
2222 acx100_configure(priv
, &cca
, ACX100_RID_DOT11_CURRENT_CCA_MODE
);
2223 priv
->set_mask
&= ~GETSET_CCA
;
2226 if (0 != (priv
->set_mask
& (GETSET_LED_POWER
|GETSET_ALL
))) {
2228 acxlog(L_INIT
, "Updating power LED status: %d\n", priv
->led_power
);
2229 acx100_power_led(priv
, priv
->led_power
);
2230 priv
->set_mask
&= ~GETSET_LED_POWER
;
2233 /* this seems to cause Tx lockup after some random time (Tx error 0x20),
2234 * so let's disable it for now until further investigation */
2235 #if POWER_SAVE_80211
2236 if (0 != (priv
->set_mask
& (GETSET_POWER_80211
|GETSET_ALL
))) {
2237 acx100_powermgmt_t pm
;
2239 /* change 802.11 power save mode settings */
2240 acxlog(L_INIT
, "Updating 802.11 power save mode settings: wakeup_cfg 0x%02x, listen interval %d, options 0x%02x, hangover period %d, enhanced_ps_transition_time %d\n", priv
->ps_wakeup_cfg
, priv
->ps_listen_interval
, priv
->ps_options
, priv
->ps_hangover_period
, priv
->ps_enhanced_transition_time
);
2241 acx100_interrogate(priv
, &pm
, ACX100_RID_POWER_MGMT
);
2242 acxlog(L_INIT
, "Previous PS mode settings: wakeup_cfg 0x%02x, listen interval %d, options 0x%02x, hangover period %d, enhanced_ps_transition_time %d\n", pm
.wakeup_cfg
, pm
.listen_interval
, pm
.options
, pm
.hangover_period
, pm
.enhanced_ps_transition_time
);
2243 pm
.wakeup_cfg
= priv
->ps_wakeup_cfg
;
2244 pm
.listen_interval
= priv
->ps_listen_interval
;
2245 pm
.options
= priv
->ps_options
;
2246 pm
.hangover_period
= priv
->ps_hangover_period
;
2247 pm
.enhanced_ps_transition_time
= cpu_to_le16(priv
->ps_enhanced_transition_time
);
2248 acx100_configure(priv
, &pm
, ACX100_RID_POWER_MGMT
);
2249 acx100_interrogate(priv
, &pm
, ACX100_RID_POWER_MGMT
);
2250 acxlog(L_INIT
, "wakeup_cfg: 0x%02x\n", pm
.wakeup_cfg
);
2251 acx100_schedule(HZ
/ 25);
2252 acx100_interrogate(priv
, &pm
, ACX100_RID_POWER_MGMT
);
2253 acxlog(L_INIT
, "power save mode change %s\n", (pm
.wakeup_cfg
& PS_CFG_PENDING
) ? "FAILED" : "was successful");
2254 /* FIXME: maybe verify via PS_CFG_PENDING bit here
2255 * that power save mode change was successful. */
2256 /* FIXME: we shouldn't trigger a scan immediately after
2257 * fiddling with power save mode (since the firmware is sending
2258 * a NULL frame then). Does this need locking?? */
2259 priv
->set_mask
&= ~GETSET_POWER_80211
;
2263 if (0 != (priv
->set_mask
& (GETSET_TX
|GETSET_ALL
))) {
2265 acxlog(L_INIT
, "Updating: %s Tx\n", priv
->tx_disabled
? "disable" : "enable");
2266 if ((UINT8
)0 != priv
->tx_disabled
)
2267 acx100_issue_cmd(priv
, ACX100_CMD_DISABLE_TX
, NULL
, 0x0 /* FIXME: this used to be 0x1, but since we don't transfer a parameter... */, 5000);
2269 acx100_issue_cmd(priv
, ACX100_CMD_ENABLE_TX
, &(priv
->channel
), 0x1, 5000);
2270 priv
->set_mask
&= ~GETSET_TX
;
2273 if (0 != (priv
->set_mask
& (GETSET_RX
|GETSET_ALL
))) {
2275 acxlog(L_INIT
, "Updating: enable Rx on channel: %d\n", priv
->channel
);
2276 acx100_issue_cmd(priv
, ACX100_CMD_ENABLE_RX
, &(priv
->channel
), 0x1, 5000);
2277 priv
->set_mask
&= ~GETSET_RX
;
2281 if (0 != (priv
->set_mask
& (GETSET_RETRY
|GETSET_ALL
))) {
2282 UINT8 short_retry
[4 + ACX100_RID_DOT11_SHORT_RETRY_LIMIT_LEN
];
2283 UINT8 long_retry
[4 + ACX100_RID_DOT11_LONG_RETRY_LIMIT_LEN
];
2285 acxlog(L_INIT
, "Updating short retry limit: %d, long retry limit: %d\n",
2286 priv
->short_retry
, priv
->long_retry
);
2287 short_retry
[0x4] = priv
->short_retry
;
2288 long_retry
[0x4] = priv
->long_retry
;
2289 acx100_configure(priv
, &short_retry
, ACX100_RID_DOT11_SHORT_RETRY_LIMIT
);
2290 acx100_configure(priv
, &long_retry
, ACX100_RID_DOT11_LONG_RETRY_LIMIT
);
2291 priv
->set_mask
&= ~GETSET_RETRY
;
2294 if (0 != (priv
->set_mask
& (SET_MSDU_LIFETIME
|GETSET_ALL
))) {
2295 UINT8 xmt_msdu_lifetime
[4 + ACX100_RID_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN
];
2297 acxlog(L_INIT
, "Updating xmt MSDU lifetime: %d\n",
2298 priv
->msdu_lifetime
);
2299 *(UINT32
*)&xmt_msdu_lifetime
[4] = cpu_to_le32((UINT32
)priv
->msdu_lifetime
);
2300 acx100_configure(priv
, &xmt_msdu_lifetime
, ACX100_RID_DOT11_MAX_XMIT_MSDU_LIFETIME
);
2301 priv
->set_mask
&= ~SET_MSDU_LIFETIME
;
2304 if (0 != (priv
->set_mask
& (GETSET_REG_DOMAIN
|GETSET_ALL
))) {
2309 acxlog(L_INIT
, "Updating regulatory domain: 0x%02X\n",
2311 for (i
= 0; i
< (UINT16
)sizeof(reg_domain_ids
); i
++)
2312 if (reg_domain_ids
[i
] == priv
->reg_dom_id
)
2315 if ((UINT16
)sizeof(reg_domain_ids
) == i
) {
2316 acxlog(L_STD
, "Invalid or unsupported regulatory domain 0x%02X specified, falling back to FCC (USA)! Please report if this sounds fishy!\n", priv
->reg_dom_id
);
2318 priv
->reg_dom_id
= reg_domain_ids
[i
];
2321 priv
->reg_dom_chanmask
= reg_domain_channel_masks
[i
];
2322 dom
.m
.gp
.bytes
[0] = priv
->reg_dom_id
;
2323 acx100_configure(priv
, &dom
, ACX100_RID_DOT11_CURRENT_REG_DOMAIN
);
2324 if (0 == (priv
->reg_dom_chanmask
& (1 << (priv
->channel
- 1) ) ))
2325 { /* hmm, need to adjust our channel setting to reside within our
2327 for (i
= 1; i
<= 14; i
++)
2328 if (0 != (priv
->reg_dom_chanmask
& (1 << (i
- 1)) ) ) {
2329 acxlog(L_STD
, "adjusting selected channel from %d to %d due to new regulatory domain.\n", priv
->channel
, i
);
2334 priv
->set_mask
&= ~GETSET_REG_DOMAIN
;
2337 if (0 != (priv
->set_mask
& (SET_RXCONFIG
|GETSET_ALL
))) {
2338 UINT8 rx_config
[4 + ACX100_RID_RXCONFIG_LEN
];
2339 switch (priv
->monitor
) {
2340 case 0: /* normal mode */
2341 priv
->rx_config_1
= (UINT16
)
2342 (RX_CFG1_PLUS_ADDIT_HDR
|
2343 RX_CFG1_ONLY_OWN_BEACONS
|
2344 RX_CFG1_FILTER_BSSID
|
2345 RX_CFG1_PROMISCUOUS
|
2346 RX_CFG1_RCV_ALL_FRAMES
/*|
2347 RX_CFG1_INCLUDE_ADDIT_HDR*/);
2349 priv
->rx_config_2
= (UINT16
)
2350 (RX_CFG2_RCV_ASSOC_REQ
|
2351 RX_CFG2_RCV_AUTH_FRAMES
|
2352 RX_CFG2_RCV_BEACON_FRAMES
|
2353 RX_CFG2_FILTER_ON_SOME_BIT
|
2354 RX_CFG2_RCV_CTRL_FRAMES
|
2355 RX_CFG2_RCV_DATA_FRAMES
|
2356 RX_CFG2_RCV_MGMT_FRAMES
|
2357 RX_CFG2_RCV_PROBE_REQ
|
2358 RX_CFG2_RCV_PROBE_RESP
|
2361 case 1: /* monitor mode - receive everything that's possible! */
2363 priv
->rx_config_1
= (UINT16
)
2364 (RX_CFG1_PLUS_ADDIT_HDR
|
2365 RX_CFG1_PROMISCUOUS
|
2366 RX_CFG1_RCV_ALL_FRAMES
|
2367 RX_CFG1_INCLUDE_FCS
/*|
2368 RX_CFG1_INCLUDE_ADDIT_HDR*/);
2370 priv
->rx_config_2
= (UINT16
)
2371 (RX_CFG2_RCV_ASSOC_REQ
|
2372 RX_CFG2_RCV_AUTH_FRAMES
|
2373 RX_CFG2_RCV_BEACON_FRAMES
|
2374 RX_CFG2_FILTER_ON_SOME_BIT
|
2375 RX_CFG2_RCV_CTRL_FRAMES
|
2376 RX_CFG2_RCV_DATA_FRAMES
|
2377 RX_CFG2_RCV_BROKEN_FRAMES
|
2378 RX_CFG2_RCV_MGMT_FRAMES
|
2379 RX_CFG2_RCV_PROBE_REQ
|
2380 RX_CFG2_RCV_PROBE_RESP
|
2381 RX_CFG2_RCV_ACK_FRAMES
|
2385 /* printk("setting RXconfig to %x:%x\n", priv->rx_config_1, priv->rx_config_2); */
2387 *(UINT16
*) &rx_config
[0x4] = cpu_to_le16(priv
->rx_config_1
);
2388 *(UINT16
*) &rx_config
[0x6] = cpu_to_le16(priv
->rx_config_2
);
2389 acx100_configure(priv
, &rx_config
, ACX100_RID_RXCONFIG
);
2390 priv
->set_mask
&= ~SET_RXCONFIG
;
2393 if (0 != (priv
->set_mask
& (GETSET_MODE
|GETSET_ALL
))) {
2394 if (ACX_MODE_3_MANAGED_AP
== priv
->macmode_wanted
) {
2395 priv
->macmode_joined
= priv
->macmode_wanted
; /* Master (AP) is just sitting there and waiting for others to connect, so the MAC mode we're currently "in" is AP, right? */
2396 MAC_COPY(priv
->bssid
, priv
->dev_addr
);
2397 acx100_set_status(priv
, ISTATUS_4_ASSOCIATED
);
2401 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
2402 acx100_scan_chan(priv
);
2403 } else if(priv
->chip_type
== CHIPTYPE_ACX111
) {
2404 acx111_scan_chan(priv
);
2409 priv
->set_mask
&= ~GETSET_MODE
;
2412 if (0 != (priv
->set_mask
& (GETSET_CHANNEL
|GETSET_ALL
))) {
2414 acxlog(L_INIT
, "Updating channel: %d\n",
2417 /* not needed in AP mode */
2418 if (ACX_MODE_3_MANAGED_AP
!= priv
->macmode_wanted
) {
2420 if (0 == scanning
) {
2423 /* stop any previous scan */
2424 acx100_issue_cmd(priv
, ACX100_CMD_STOP_SCAN
, NULL
, 0, 5000);
2425 #warning Is this used anymore?
2426 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
2429 s
.start_chan
= priv
->channel
;
2431 s
.max_rate
= 20; /* 2 Mbps */
2433 s
.chan_duration
= 50;
2434 s
.max_probe_delay
= 100;
2436 acx100_scan_chan_p(priv
, &s
);
2437 } else if(priv
->chip_type
== CHIPTYPE_ACX111
) {
2438 acx111_scan_chan(priv
);
2443 priv
->set_mask
&= ~GETSET_CHANNEL
;
2446 if (0 != (priv
->set_mask
& (GETSET_ESSID
|GETSET_ALL
))) {
2447 /* not needed in AP mode */
2448 if (ACX_MODE_3_MANAGED_AP
!= priv
->macmode_wanted
) {
2449 /* if we aren't scanning already, then start scanning now */
2452 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
2453 acx100_scan_chan(priv
);
2454 } else if(priv
->chip_type
== CHIPTYPE_ACX111
) {
2455 acx111_scan_chan(priv
);
2460 priv
->set_mask
&= ~GETSET_ESSID
;
2463 if (0 != (priv
->set_mask
& (SET_WEP_OPTIONS
|GETSET_ALL
))) {
2471 options
.valc
= cpu_to_le16(0x0e);
2472 options
.vald
= cpu_to_le16(priv
->monitor_setting
);
2474 acx100_configure(priv
, &options
, ACX100_RID_WEP_OPTIONS
);
2475 priv
->set_mask
&= ~SET_WEP_OPTIONS
;
2478 /* debug, rate, and nick don't need any handling */
2479 /* what about sniffing mode?? */
2481 priv
->get_mask
&= ~GETSET_ALL
;
2482 priv
->set_mask
&= ~GETSET_ALL
;
2484 acxlog(L_INIT
, "get_mask 0x%08x, set_mask 0x%08x - after update\n",
2485 priv
->get_mask
, priv
->set_mask
);
2487 #ifdef BROKEN_LOCKING
2488 acx100_unlock(priv
, &flags
);
2493 /*----------------------------------------------------------------
2494 * acx100_set_defaults
2509 *----------------------------------------------------------------*/
2514 int acx100_set_defaults(wlandevice_t
*priv
)
2520 /* query some settings from the card. */
2521 priv
->get_mask
= GETSET_ANTENNA
|GETSET_SENSITIVITY
|GET_STATION_ID
|GETSET_REG_DOMAIN
;
2522 acx100_update_card_settings(priv
, 1, 0, 0);
2524 /* set our global interrupt mask */
2525 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
2526 /* priv->irq_mask = 0xdbb5; not longer used anymore! */
2527 priv
->irq_mask
= 0xd9b5;
2528 } else if(priv
->chip_type
== CHIPTYPE_ACX111
) {
2529 priv
->irq_mask
= 0x98e5;
2532 priv
->led_power
= (UINT8
)1; /* LED is active on startup */
2534 /* copy the MAC address we just got from the card
2535 * into our MAC address used during current 802.11 session */
2536 MAC_COPY(priv
->dev_addr
, priv
->netdev
->dev_addr
);
2537 sprintf(priv
->essid
, "STA%02X%02X%02X",
2538 priv
->dev_addr
[3], priv
->dev_addr
[4], priv
->dev_addr
[5]);
2539 priv
->essid_len
= (UINT8
)9; /* make sure to adapt if changed above! */
2540 priv
->essid_active
= (UINT8
)1;
2542 /* we have a nick field to waste, so why not abuse it
2543 * to announce the driver version? ;-) */
2544 strncpy(priv
->nick
, "acx100 ", IW_ESSID_MAX_SIZE
);
2545 strncat(priv
->nick
, WLAN_RELEASE_SUB
, IW_ESSID_MAX_SIZE
);
2547 if ( priv
->chip_type
!= CHIPTYPE_ACX111
) {
2548 if (priv
->eeprom_version
< (UINT8
)5) {
2549 acx100_read_eeprom_offset(priv
, 0x16F, &priv
->reg_dom_id
);
2551 acx100_read_eeprom_offset(priv
, 0x171, &priv
->reg_dom_id
);
2554 /* Hope this is correct, only tested with domain 0x30 */
2555 acx100_read_eeprom_offset(priv
, 0x16F, &priv
->reg_dom_id
);
2559 priv
->scan_count
= 1; /* 0xffff would be better, but then we won't get a "scan complete" interrupt, so our current infrastructure will fail */
2560 priv
->scan_mode
= ACX_SCAN_PASSIVE
;
2561 priv
->scan_duration
= 100;
2562 priv
->scan_probe_delay
= 200;
2564 priv
->auth_alg
= WLAN_AUTH_ALG_OPENSYSTEM
;
2565 priv
->preamble_mode
= (UINT8
)2;
2566 priv
->preamble_flag
= (UINT8
)0;
2567 priv
->listen_interval
= 100;
2568 priv
->beacon_interval
= 100;
2569 priv
->macmode_wanted
= ACX_MODE_FF_AUTO
; /* associate to either Ad-Hoc or Managed */
2570 priv
->macmode_joined
= 0xaa; /* make sure we know that we didn't join anything */
2571 priv
->unknown0x2350
= 0;
2572 priv
->dtim_interval
= (UINT8
)2;
2574 priv
->msdu_lifetime
= 4096; /* used to be 2048, but FreeBSD driver changed it to 4096 to work properly in noisy wlans */
2575 priv
->set_mask
|= SET_MSDU_LIFETIME
;
2577 priv
->rts_threshold
= 2312; /* max. size: disable RTS mechanism */
2579 /* use standard default values for retry limits */
2580 priv
->short_retry
= 7; /* max. retries for (short) non-RTS packets */
2581 priv
->long_retry
= 4; /* max. retries for long (RTS) packets */
2582 priv
->set_mask
|= GETSET_RETRY
;
2584 priv
->txrate_auto
= (UINT8
)0; /* FIXME: disable it by default, implementation not very good yet. */
2585 priv
->txrate_auto_idx
= (UINT8
)1; /* 2Mbps */
2586 priv
->txrate_cfg
= (UINT8
)ACX_TXRATE_11
; /* Don't start with max. rate of 22Mbps, since very many APs only support up to 11Mbps */
2587 if (1 == priv
->txrate_auto
)
2588 priv
->txrate_curr
= (UINT8
)ACX_TXRATE_2
; /* 2Mbps, play it safe at the beginning */
2590 priv
->txrate_curr
= priv
->txrate_cfg
;
2592 /* # of retries to use when in auto rate mode.
2593 * Setting it higher will cause higher ping times due to retries. */
2594 priv
->txrate_fallback_retries
= (UINT8
)1;
2595 priv
->set_mask
|= SET_RATE_FALLBACK
;
2596 priv
->txrate_fallback_threshold
= (UINT8
)12;
2597 priv
->txrate_stepup_threshold
= (UINT8
)3;
2599 /* Supported Rates element - the rates here are given in units of
2600 * 500 kbit/s, plus 0x80 added. See 802.11-1999.pdf item 7.3.2.2 */
2601 priv
->rate_spt_len
= (UINT8
)5;
2602 priv
->rate_support1
[0] = (UINT8
)0x82; /* 1Mbps */
2603 priv
->rate_support1
[1] = (UINT8
)0x84; /* 2Mbps */
2604 priv
->rate_support1
[2] = (UINT8
)0x8b; /* 5.5Mbps */
2605 priv
->rate_support1
[3] = (UINT8
)0x96; /* 11Mbps */
2606 priv
->rate_support1
[4] = (UINT8
)0xac; /* 22Mbps */
2608 priv
->rate_support2
[0] = (UINT8
)0x82; /* 1Mbps */
2609 priv
->rate_support2
[1] = (UINT8
)0x84; /* 2Mbps */
2610 priv
->rate_support2
[2] = (UINT8
)0x8b; /* 5.5Mbps */
2611 priv
->rate_support2
[3] = (UINT8
)0x96; /* 11Mbps */
2612 priv
->rate_support2
[4] = (UINT8
)0xac; /* 22Mbps */
2614 priv
->capab_short
= (UINT8
)0;
2615 priv
->capab_pbcc
= (UINT8
)1;
2616 priv
->capab_agility
= (UINT8
)0;
2618 priv
->val0x2324
[0x1] = (UINT8
)0x1f; /* supported rates: 1, 2, 5.5, 11, 22 */
2619 priv
->val0x2324
[0x2] = (UINT8
)0x03;
2620 priv
->val0x2324
[0x3] = (UINT8
)0x0f; /* basic rates: 1, 2, 5.5, 11 */
2621 priv
->val0x2324
[0x4] = (UINT8
)0x0f;
2622 priv
->val0x2324
[0x5] = (UINT8
)0x0f;
2623 priv
->val0x2324
[0x6] = (UINT8
)0x1f;
2625 /* set some more defaults */
2626 priv
->tx_level_dbm
= (UINT8
)18; /* don't use max. level, since it might be dangerous (e.g. WRT54G people experience excessive Tx power damage!) */
2627 priv
->tx_level_auto
= (UINT8
)1;
2628 priv
->set_mask
|= GETSET_TXPOWER
;
2630 #if BETTER_DO_NOT_DO_IT
2631 /* should we overwrite the value we gained above with our own
2632 * potentially problematic value? I don't think so... */
2633 priv
->antenna
= 0x8f;
2635 priv
->set_mask
|= GETSET_ANTENNA
; /* better re-init the value from above */
2637 priv
->ed_threshold
= (UINT8
)0x70;
2638 priv
->set_mask
|= GETSET_ED_THRESH
;
2640 priv
->cca
= (UINT8
)0x0d;
2641 priv
->set_mask
|= GETSET_CCA
;
2643 priv
->set_mask
|= SET_RXCONFIG
;
2645 priv
->ps_wakeup_cfg
= (UINT8
)0;
2646 priv
->ps_listen_interval
= (UINT8
)0;
2647 priv
->ps_options
= (UINT8
)0;
2648 priv
->ps_hangover_period
= (UINT8
)0;
2649 priv
->ps_enhanced_transition_time
= 0;
2650 #if POWER_SAVE_80211
2651 priv
->set_mask
|= GETSET_POWER_80211
;
2654 MAC_BCAST(priv
->ap
);
2662 /*----------------------------------------------------------------
2663 * acx100_set_probe_response_template
2678 *----------------------------------------------------------------*/
2680 /* SetACXProbeResponseTemplate()
2683 int acx100_set_probe_response_template(wlandevice_t
*priv
)
2686 struct acxp80211_beacon_prb_resp_template pr
;
2691 memset(&pr
, 0, sizeof(struct acxp80211_beacon_prb_resp_template
));
2692 len
= acx100_set_generic_beacon_probe_response_frame(priv
, &pr
.pkt
);
2693 pr
.size
= cpu_to_le16(len
);
2694 pr
.pkt
.hdr
.fc
= cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT
) | WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBERESP
));
2697 acxlog(L_DATA
| L_XFER
, "SetProberTemp: cb = %d\n", len
);
2698 acxlog(L_DATA
, "src=%02X:%02X:%02X:%02X:%02X:%02X\n",
2699 pr
.pkt
.hdr
.a2
[0], pr
.pkt
.hdr
.a2
[1], pr
.pkt
.hdr
.a2
[2],
2700 pr
.pkt
.hdr
.a2
[3], pr
.pkt
.hdr
.a2
[4], pr
.pkt
.hdr
.a2
[5]);
2701 acxlog(L_DATA
, "BSSID=%02X:%02X:%02X:%02X:%02X:%02X\n",
2702 pr
.pkt
.hdr
.a3
[0], pr
.pkt
.hdr
.a3
[1], pr
.pkt
.hdr
.a3
[2],
2703 pr
.pkt
.hdr
.a3
[3], pr
.pkt
.hdr
.a3
[4], pr
.pkt
.hdr
.a3
[5]);
2705 "SetProberTemp: Info1=%02X %02X %02X %02X %02X %02X %02X %02X\n",
2706 pr2
[0], pr2
[1], pr2
[2], pr2
[3], pr2
[4], pr2
[5], pr2
[6],
2709 "SetProberTemp: Info2=%02X %02X %02X %02X %02X %02X %02X %02X\n",
2710 pr2
[0x8], pr2
[0x9], pr2
[0xa], pr2
[0xb], pr2
[0xc], pr2
[0xd],
2711 pr2
[0xe], pr2
[0xf]);
2713 "SetProberTemp: Info3=%02X %02X %02X %02X %02X %02X %02X %02X\n",
2714 pr2
[0x10], pr2
[0x11], pr2
[0x12], pr2
[0x13], pr2
[0x14],
2715 pr2
[0x15], pr2
[0x16], pr2
[0x17]);
2717 len
+= 2; /* add length of "size" field */
2718 result
= acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_PROBE_RESPONSE
, &pr
, len
, 5000);
2723 /*----------------------------------------------------------------
2724 * acx100_set_probe_request_template
2739 *----------------------------------------------------------------*/
2744 void acx100_set_probe_request_template(wlandevice_t
*priv
)
2746 struct acxp80211_packet pt
;
2747 struct acxp80211_hdr
*txf
;
2750 UINT8 bcast_addr
[0x6] = {0xff,0xff,0xff,0xff,0xff,0xff};
2754 /* pt.hdr.a4.a1[6] = 0xff; */
2756 pt
.hdr
.a4
.fc
= cpu_to_le16(0x40);
2757 pt
.hdr
.a4
.dur
= cpu_to_le16(0x0);
2758 MAC_BCAST(pt
.hdr
.a4
.a1
);
2759 MAC_COPY(pt
.hdr
.a4
.a2
, priv
->dev_addr
);
2760 MAC_COPY(pt
.hdr
.a4
.a3
, bcast_addr
);
2761 pt
.hdr
.a4
.seq
= cpu_to_le16(0x0);
2762 /* pt.hdr.b4.a1[0x0] = 0x0; */
2763 /* pt.hdr.a4.a4[0x1] = priv->next; */
2764 memset(txf
->val0x18
, 0, 8);
2766 /* set entry 2: Beacon Interval (2 octets) */
2767 txf
->beacon_interval
= cpu_to_le16(priv
->beacon_interval
);
2769 /* set entry 3: Capability information (2 octets) */
2770 acx100_update_capabilities(priv
);
2771 txf
->caps
= cpu_to_le16(priv
->capabilities
);
2773 /* set entry 4: SSID (2 + (0 to 32) octets) */
2774 acxlog(L_ASSOC
, "SSID = %s, len = %i\n", priv
->essid
, priv
->essid_len
);
2775 this = &txf
->info
[0];
2776 this[0] = 0; /* "SSID Element ID" */
2777 this[1] = priv
->essid_len
; /* "Length" */
2778 memcpy(&this[2], priv
->essid
, priv
->essid_len
);
2779 frame_len
+= 2 + priv
->essid_len
;
2781 /* set entry 5: Supported Rates (2 + (1 to 8) octets) */
2782 this = &txf
->info
[2 + priv
->essid_len
];
2784 this[0] = 1; /* "Element ID" */
2785 this[1] = priv
->rate_spt_len
;
2786 if (priv
->rate_spt_len
< 2) {
2787 for (i
= 0; i
< (int)priv
->rate_spt_len
; i
++) {
2788 priv
->rate_support1
[i
] &= ~0x80;
2791 memcpy(&this[2], priv
->rate_support1
, priv
->rate_spt_len
);
2792 frame_len
+= 2 + this[1]; /* length calculation is not split up like that, but it's much cleaner that way. */
2794 /* set entry 6: DS Parameter Set () */
2795 this = &this[2 + this[1]];
2796 this[0] = 3; /* "Element ID": "DS Parameter Set element" */
2797 this[1] = 1; /* "Length" */
2798 this[2] = priv
->channel
; /* "Current Channel" */
2799 frame_len
+= 3; /* ok, now add the remaining 3 bytes */
2801 acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_PROBE_REQUEST
, &pt
, frame_len
, 5000);
2805 void acx111_set_probe_request_template(wlandevice_t
*priv
)
2808 char bcast_addr
[0x6] = {0xff,0xff,0xff,0xff,0xff,0xff};
2809 UINT8
template[100], *this;
2814 memset(template, 0x00, sizeof(template));
2816 MAC_COPY(&template[0x04], bcast_addr
);
2817 MAC_COPY(&template[0x0a], priv
->dev_addr
);
2818 MAC_COPY(&template[0x10], bcast_addr
);
2820 this = &template[0x18];
2821 this[0] = 0; /* element id ssid */
2822 this[1] = priv
->essid_len
;
2823 memcpy(&this[2], priv
->essid
, priv
->essid_len
);
2824 frame_len
+= 2 + priv
->essid_len
;
2826 /* set entry 5: Supported Rates (2 + (1 to 8) octets) */
2827 this = &template[frame_len
];
2828 this[0] = 1; /* "Element ID" */
2829 this[1] = priv
->rate_spt_len
;
2830 if (priv
->rate_spt_len
< 2) {
2831 for (i
= 0; i
< priv
->rate_spt_len
; i
++) {
2832 priv
->rate_support1
[i
] &= ~0x80;
2835 memcpy(&this[2], priv
->rate_support1
, priv
->rate_spt_len
);
2836 frame_len
+= 2 + this[1]; /* length calculation is not split up like that, but it's much cleaner that way. */
2838 acx100_issue_cmd(priv
, ACX100_CMD_CONFIG_PROBE_REQUEST
, &template, frame_len
, 5000);
2843 /*----------------------------------------------------------------
2859 *----------------------------------------------------------------*/
2862 * STATUS: FINISHED, UNVERIFIED.
2864 void acx100_join_bssid(wlandevice_t
*priv
)
2869 acxlog(L_STATE
, "%s: UNVERIFIED.\n", __func__
);
2871 memset(&tmp
, 0, sizeof(tmp
));
2873 for (i
= 0; i
< ETH_ALEN
; i
++) {
2874 tmp
.bssid
[i
] = priv
->address
[5 - i
];
2877 tmp
.beacon_interval
= cpu_to_le16(priv
->beacon_interval
);
2878 tmp
.dtim_interval
= priv
->dtim_interval
;
2879 tmp
.rates_basic
= priv
->val0x2324
[3];
2881 tmp
.rates_supported
= priv
->val0x2324
[1];
2882 tmp
.txrate_val
= (UINT8
)ACX_TXRATE_2
; /* bitrate: 2Mbps */
2883 tmp
.preamble_type
= priv
->capab_short
;
2884 tmp
.macmode
= priv
->macmode_chosen
; /* should be called BSS_Type? */
2885 tmp
.channel
= priv
->channel
;
2886 tmp
.essid_len
= priv
->essid_len
;
2887 /* The firmware hopefully doesn't stupidly rely
2888 * on having a trailing \0 copied, right?
2889 * (the code memcpy'd essid_len + 1 before, which is WRONG!) */
2890 memcpy(tmp
.essid
, priv
->essid
, tmp
.essid_len
);
2892 acx100_issue_cmd(priv
, ACX100_CMD_JOIN
, &tmp
, tmp
.essid_len
+ 0x11, 5000);
2893 acxlog(L_ASSOC
| L_BINDEBUG
, "<%s> BSS_Type = %d\n", __func__
, tmp
.macmode
);
2894 acxlog(L_ASSOC
| L_BINDEBUG
,
2895 "<%s> JoinBSSID MAC:%02X %02X %02X %02X %02X %02X\n", __func__
,
2896 tmp
.bssid
[5], tmp
.bssid
[4], tmp
.bssid
[3],
2897 tmp
.bssid
[2], tmp
.bssid
[1], tmp
.bssid
[0]);
2899 for (i
= 0; i
< ETH_ALEN
; i
++) {
2900 priv
->bssid
[5 - i
] = tmp
.bssid
[i
];
2902 priv
->macmode_joined
= tmp
.macmode
;
2903 acx100_update_capabilities(priv
);
2907 /*----------------------------------------------------------------
2923 *----------------------------------------------------------------*/
2928 int acx100_init_mac(netdevice_t
*dev
, UINT16 init
)
2931 acx100_memmap_t pkt
;
2932 wlandevice_t
*priv
= (wlandevice_t
*) dev
->priv
;
2934 acxlog(L_DEBUG
,"sizeof(memmap)=%d bytes\n",sizeof(pkt
));
2938 acxlog(L_BINDEBUG
, "******************************************\n");
2939 acxlog(L_BINDEBUG
| L_INIT
, "************ acx100_initmac_1 ************\n");
2940 acxlog(L_BINDEBUG
, "******************************************\n");
2941 #if (WLAN_HOSTIF!=WLAN_USB)
2942 priv
->memblocksize
= 0x100;
2944 priv
->memblocksize
= 0x80;
2947 acx100_init_mboxes(priv
);
2948 #if (WLAN_HOSTIF!=WLAN_USB)
2949 /* try to load radio for both ACX100 and ACX111, since both
2950 * chips have at least some firmware versions making use of an
2951 * external radio module */
2952 acx100_load_radio(priv
);
2955 if(priv
->chip_type
== CHIPTYPE_ACX100
) {
2956 if (0 == acx100_init_wep(priv
, &pkt
)) goto done
;
2957 acxlog(L_DEBUG
,"between init_wep and init_packet_templates\n");
2958 if (!acx100_init_packet_templates(priv
,&pkt
)) goto done
;
2960 if (acx100_create_dma_regions(priv
)) {
2961 acxlog(L_STD
, "acx100_create_dma_regions failed.\n");
2965 } else if(priv
->chip_type
== CHIPTYPE_ACX111
) {
2966 /* here the order is different
2967 1. init packet templates
2968 2. create station context and create dma regions
2969 3. init wep default keys
2971 if (0 == acx111_init_packet_templates(priv
,&pkt
)) goto done
;
2973 if (0 != acx111_create_dma_regions(priv
)) {
2974 acxlog(L_STD
, "acx111_create_dma_regions failed.\n");
2978 if (0 == acx100_init_wep(priv
, &pkt
)) goto done
;
2980 acxlog(L_DEBUG
,"unknown chip type\n");
2985 if (0 == acx100_set_defaults(priv
)) {
2986 acxlog(L_STD
, "acx100_set_defaults failed.\n");
2991 MAC_COPY(dev
->dev_addr
, priv
->dev_addr
);
2994 /* FIXME: most likely that's not needed here,
2995 * since it's done in acx100_start() */
2996 priv
->set_mask
|= SET_STA_LIST
;
2997 priv
->set_mask
|= SET_TEMPLATES
;
2998 acx100_update_card_settings(priv
, 1, 0, 0);
3003 /*priv->val0x240c = 0x1; */
3005 if (ACX_MODE_2_MANAGED_STA
!= priv
->macmode_wanted
) {
3006 if (acx100_set_beacon_template(priv
) == 0) {
3008 "acx100_set_beacon_template failed.\n");
3011 if (acx100_set_probe_response_template(priv
) == 0) {
3013 "acx100_set_probe_response_template failed.\n");
3021 /* acx100_enable_irq(priv); */
3022 /* acx100_start(priv); */
3027 /*----------------------------------------------------------------
3043 *----------------------------------------------------------------*/
3046 * STATUS: should be ok.
3048 void acx100_start(wlandevice_t
*priv
)
3050 unsigned long flags
;
3051 int dont_lock_up
= 0;
3055 if (0 != spin_is_locked(&priv
->lock
)) {
3056 printk(KERN_EMERG
"Preventing lock-up!");
3060 if (0 == dont_lock_up
)
3061 if (acx100_lock(priv
, &flags
))
3063 acxlog(L_STD
, "ERROR: lock failed!\n");
3068 * Ok, now we do everything that can possibly be done with ioctl
3069 * calls to make sure that when it was called before the card
3070 * was up we get the changes asked for
3073 priv
->set_mask
|= SET_TEMPLATES
|SET_STA_LIST
|GETSET_WEP
|GETSET_TXPOWER
|GETSET_ANTENNA
|GETSET_ED_THRESH
|GETSET_CCA
|GETSET_REG_DOMAIN
|GETSET_MODE
|GETSET_CHANNEL
|GETSET_TX
|GETSET_RX
;
3074 acxlog(L_INIT
, "initial settings update on iface activation.\n");
3075 acx100_update_card_settings(priv
, 1, 0, 0);
3078 /* FIXME: that's completely useless, isn't it? */
3080 acxlog(L_INIT
, "Setting mode to %ld\n", priv
->mode
);
3081 acx100_join_bssid(priv
);
3084 if (0 == dont_lock_up
)
3085 acx100_unlock(priv
, &flags
);
3089 /*------------------------------------------------------------------------------
3092 * Sets the 802.11 state management timer's timeout.
3095 * @priv: per-device struct containing the management timer
3096 * @timeout: timeout in us
3104 * STATUS: FINISHED, but struct undefined.
3108 *----------------------------------------------------------------------------*/
3109 void acx100_set_timer(wlandevice_t
*priv
, UINT32 timeout
)
3111 #if (WLAN_HOSTIF!=WLAN_USB)
3117 acxlog(L_BINDEBUG
| L_IRQ
, "<acx100_set_timer> Elapse = %d\n", timeout
);
3118 if (0 == (priv
->dev_state_mask
& ACX_STATE_IFACE_UP
)) {
3119 acxlog(L_STD
, "ERROR: attempt to set the timer before the card interface is up! Please report with a debug=0xffff log!!\n");
3123 /* newer firmware versions abandoned timer configuration
3124 * FIXME: any other versions between 1.8.3 (working) and
3125 * 1.9.3.e (removed)? */
3126 #if (WLAN_HOSTIF!=WLAN_USB)
3127 if (priv
->firmware_numver
< 0x0109030e &&
3128 priv
->chip_type
!= CHIPTYPE_ACX111
)
3130 /* first two 16-bit words reserved for type and length */
3131 tmp
[1] = cpu_to_le32(timeout
);
3133 acx100_configure(priv
, &tmp
, ACX100_RID_ACX_TIMER
);
3137 /* first check if the timer was already initialized, THEN modify it */
3138 if (priv
->mgmt_timer
.function
)
3140 mod_timer(&(priv
->mgmt_timer
), jiffies
+ (timeout
* HZ
/ 1000000));
3147 /* AcxUpdateCapabilities()
3148 * STATUS: FINISHED. Warning: spelling error, original name was
3149 * AcxUpdateCapabilies.
3151 void acx100_update_capabilities(wlandevice_t
*priv
)
3154 priv
->capabilities
= 0;
3155 if (ACX_MODE_3_MANAGED_AP
== priv
->macmode_wanted
) {
3156 priv
->capabilities
= WLAN_SET_MGMT_CAP_INFO_ESS(1); /* 1 */
3158 priv
->capabilities
|= WLAN_SET_MGMT_CAP_INFO_IBSS(1); /* 2 */
3160 if (priv
->wep_restricted
!= 0) {
3161 priv
->capabilities
|= WLAN_SET_MGMT_CAP_INFO_PRIVACY(1); /* 0x10 */
3163 if (priv
->capab_short
!= 0) {
3164 priv
->capabilities
|= WLAN_SET_MGMT_CAP_INFO_SHORT(1); /* 0x20 */
3166 if (priv
->capab_pbcc
!= 0) {
3167 priv
->capabilities
|= WLAN_SET_MGMT_CAP_INFO_PBCC(1); /* 0x40 */
3169 if (priv
->capab_agility
!= 0) {
3170 priv
->capabilities
|= WLAN_SET_MGMT_CAP_INFO_AGILITY(1); /* 0x80 */
3174 /*----------------------------------------------------------------
3175 * acx100_read_eeprom_offset
3177 * Function called to read an octet in the EEPROM.
3179 * This function is used by acx100_probe_pci to check if the
3180 * connected card is a legal one or not.
3183 * priv ptr to wlandevice structure
3184 * addr address to read in the EEPROM
3185 * charbuf ptr to a char. This is where the read octet
3198 * NOT ADAPTED FOR ACX111 !!
3200 * Comment: This function was in V3 driver only.
3201 * It should be found what mean the different values written
3203 * It should be checked if it would be possible to use a
3204 * acx100_read_reg8() instead of a acx100_read_reg16() as the
3205 * read value should be an octet. (ygauteron, 29.05.2003)
3206 ----------------------------------------------------------------*/
3207 UINT16
acx100_read_eeprom_offset(wlandevice_t
*priv
,
3208 UINT16 addr
, UINT8
*charbuf
)
3211 #if (WLAN_HOSTIF!=WLAN_USB)
3216 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_CFG
], cpu_to_le32(0));
3217 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_ADDR
], cpu_to_le32(addr
));
3218 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_CTL
], cpu_to_le32(2));
3220 while (0 != acx100_read_reg16(priv
, priv
->io
[IO_ACX_EEPROM_CTL
]))
3222 /* scheduling away instead of CPU burning loop
3223 * doesn't seem to work here at all:
3224 * awful delay, sometimes also failure.
3225 * Doesn't matter anyway (only small delay). */
3226 if (++count
> 0xffff) {
3228 acxlog(L_BINSTD
, "%s: timeout waiting for read eeprom cmd\n", __func__
);
3233 /* yg: Why reading a 16-bits register for a 8-bits value ? */
3234 *charbuf
= (unsigned char) acx100_read_reg16(priv
, priv
->io
[IO_ACX_EEPROM_DATA
]);
3235 acxlog(L_DEBUG
, "EEPROM read 0x%04x --> 0x%02x\n", addr
, *charbuf
);
3244 /* acx100_read_eeprom_area
3247 UINT16
acx100_read_eeprom_area(wlandevice_t
*priv
)
3249 #if (WLAN_HOSTIF!=WLAN_USB)
3253 for (offs
= 0x8c; offs
< 0xb9; offs
++) {
3254 acx100_read_eeprom_offset(priv
, offs
, &tmp
[offs
- 0x8c]);
3260 UINT16
acx100_write_eeprom_offset(wlandevice_t
*priv
, UINT16 addr
, UINT16 len
, UINT8
*charbuf
)
3263 #if (WLAN_HOSTIF!=WLAN_USB)
3267 UINT8
*data_verify
= NULL
;
3272 acxlog(L_STD
, "WARNING: I would write to EEPROM now. Since I really DON'T want to do it unless you know what you're doing, I will abort that now.\n");
3275 /* first we need to enable the OE (EEPROM Output Enable) GPIO line
3276 * to be able to write to the EEPROM */
3277 gpio_orig
= acx100_read_reg16(priv
, priv
->io
[IO_ACX_GPIO_OE
]);
3278 acx100_write_reg16(priv
, priv
->io
[IO_ACX_GPIO_OE
], gpio_orig
& ~1);
3280 /* ok, now start writing the data out */
3281 for (i
= 0; i
< len
; i
++) {
3283 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_CFG
], cpu_to_le32(0));
3284 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_ADDR
], cpu_to_le32(addr
+ i
));
3285 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_DATA
], cpu_to_le32(*(charbuf
+ i
)));
3286 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_CTL
], cpu_to_le32(1));
3288 while (0 != acx100_read_reg16(priv
, priv
->io
[IO_ACX_EEPROM_CTL
]))
3290 /* scheduling away instead of CPU burning loop
3291 * doesn't seem to work here at all:
3292 * awful delay, sometimes also failure.
3293 * Doesn't matter anyway (only small delay). */
3294 if (++count
> 0xffff) {
3295 acxlog(L_BINSTD
, "%s: WARNING, DANGER!!!! Timeout waiting for write eeprom cmd\n", __func__
);
3302 /* disable EEPROM writing */
3303 acx100_write_reg16(priv
, priv
->io
[IO_ACX_GPIO_OE
], gpio_orig
);
3305 /* now start a verification run */
3306 if ((NULL
== (data_verify
= kmalloc(len
, GFP_KERNEL
)))) {
3311 for (i
= 0; i
< len
; i
++) {
3313 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_CFG
], cpu_to_le32(0));
3314 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_ADDR
], cpu_to_le32(addr
+ i
));
3315 acx100_write_reg32(priv
, priv
->io
[IO_ACX_EEPROM_CTL
], cpu_to_le32(2));
3317 while (0 != acx100_read_reg16(priv
, priv
->io
[IO_ACX_EEPROM_CTL
]))
3319 /* scheduling away instead of CPU burning loop
3320 * doesn't seem to work here at all:
3321 * awful delay, sometimes also failure.
3322 * Doesn't matter anyway (only small delay). */
3323 if (++count
> 0xffff) {
3324 acxlog(L_BINSTD
, "%s: timeout waiting for read eeprom cmd\n", __func__
);
3330 *(data_verify
+ i
) = (UINT8
)acx100_read_reg16(priv
, priv
->io
[IO_ACX_EEPROM_DATA
]);
3333 if (0 == memcmp(charbuf
, data_verify
, len
))
3334 result
= 1; /* read data matches, success */
3337 if (NULL
!= data_verify
)
3345 UINT16
acx100_read_phy_reg(wlandevice_t
*priv
, UINT16 reg
, UINT8
*charbuf
)
3348 #if (WLAN_HOSTIF!=WLAN_USB)
3353 acx100_write_reg32(priv
, priv
->io
[IO_ACX_PHY_ADDR
], cpu_to_le32(reg
));
3354 acx100_write_reg32(priv
, priv
->io
[IO_ACX_PHY_CTL
], cpu_to_le32(2));
3356 while (0 != acx100_read_reg16(priv
, priv
->io
[IO_ACX_PHY_CTL
]))
3358 /* scheduling away instead of CPU burning loop
3359 * doesn't seem to work here at all:
3360 * awful delay, sometimes also failure.
3361 * Doesn't matter anyway (only small delay). */
3362 if (++count
> 0xffff) {
3364 acxlog(L_BINSTD
, "%s: timeout waiting for read eeprom cmd\n", __func__
);
3369 /* yg: Why reading a 16-bits register for a 8-bits value ? */
3370 *charbuf
= (UINT8
)acx100_read_reg16(priv
, priv
->io
[IO_ACX_PHY_DATA
]);
3372 mem_read_write_t mem
;
3374 mem
.addr
= cpu_to_le16(reg
);
3375 mem
.type
= cpu_to_le16(0x82);
3376 mem
.len
= cpu_to_le32(1);
3377 acx100_issue_cmd(priv
, ACX100_CMD_MEM_READ
, &mem
, 0x8 + mem
.len
, 200000);
3378 *charbuf
= (UINT8
)mem
.data
[0];
3380 acxlog(L_DEBUG
, "radio PHY read 0x%02x from 0x%04x\n", *charbuf
, reg
);
3382 goto done
; /* silence compiler warning */
3388 UINT16
acx100_write_phy_reg(wlandevice_t
*priv
, UINT16 reg
, UINT8 value
)
3390 #if (WLAN_HOSTIF!=WLAN_USB)
3393 acx100_write_reg32(priv
, priv
->io
[IO_ACX_PHY_ADDR
], cpu_to_le32(reg
));
3394 /* FIXME: we don't use 32bit access here since mprusko said that
3395 * it results in distorted sensitivity on his card (huh!?!?
3396 * doesn't happen with my setup...)
3397 * Maybe we actually need a delay similar to the one in the read
3398 * function, due to some radio chipsets being too slow...
3399 * FIXME: which radio is in the problematic card? My working one
3401 acx100_write_reg16(priv
, priv
->io
[IO_ACX_PHY_DATA
], cpu_to_le16(value
));
3402 acx100_write_reg16(priv
, priv
->io
[IO_ACX_PHY_DATA
] + 2, 0);
3403 acx100_write_reg32(priv
, priv
->io
[IO_ACX_PHY_CTL
], cpu_to_le32(1));
3405 mem_read_write_t mem
;
3407 mem
.addr
= cpu_to_le16(reg
);
3408 mem
.type
= cpu_to_le16(0x82);
3409 mem
.len
= cpu_to_le32(1);
3410 mem
.data
[0] = value
;
3411 acx100_issue_cmd(priv
, ACX100_CMD_MEM_WRITE
, &mem
, 0x8 + mem
.len
, 200000);
3413 acxlog(L_DEBUG
, "radio PHY write 0x%02x to 0x%04x\n", value
, reg
);