1 /* src/ihw.c - low level control 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 #include <linux/config.h>
40 #define WLAN_DBVAR prism2_debug
41 #include <linux/version.h>
43 #include <linux/module.h>
44 #include <linux/kernel.h>
46 #include <linux/sched.h>
47 #include <linux/types.h>
48 #include <linux/skbuff.h>
49 #include <linux/slab.h>
50 #include <linux/proc_fs.h>
51 #include <linux/if_arp.h>
52 #include <linux/rtnetlink.h>
53 #include <linux/wireless.h>
54 #include <linux/netdevice.h>
56 #include <linux/delay.h>
57 #include <asm/byteorder.h>
58 #include <asm/bitops.h>
59 #include <asm/uaccess.h>
61 #include <wlan_compat.h>
63 #include <linux/ioport.h>
64 #include <linux/pci.h>
67 #include <linux/dcache.h>
68 #include <linux/highmem.h>
69 #include <linux/sched.h>
70 #include <linux/skbuff.h>
71 #include <linux/etherdevice.h>
74 /*================================================================*/
75 /* Project Includes */
78 #include <p80211hdr.h>
79 #include <p80211mgmt.h>
80 #include <p80211conv.h>
81 #include <p80211msg.h>
82 #include <p80211ioctl.h>
84 #include <p80211netdev.h>
85 #include <p80211req.h>
86 #include <p80211types.h>
87 #include <acx100_helper.h>
88 #include <acx100_helper2.h>
91 #include <acx100mgmt.h>
93 /*****************************************************************************
95 * The Really Low Level Stuff (TM)
97 ****************************************************************************/
99 /*----------------------------------------------------------------
101 * rename to acx100_read_reg32
115 *----------------------------------------------------------------*/
117 /* hwReadRegister32()
120 UINT32
hwReadRegister32(wlandevice_t
* hw
, UINT offset
)
122 return readl(hw
->iobase
+ offset
);
124 /*----------------------------------------------------------------
126 * FIXME: rename to acx100_read_reg16
140 *----------------------------------------------------------------*/
142 /* hwReadRegister16()
143 * STATUS: should be ok.
145 UINT16
hwReadRegister16(wlandevice_t
* hw
, UINT offset
)
147 return readw(hw
->iobase
+ offset
);
150 /*----------------------------------------------------------------
152 * FIXME: rename to acx100_read_reg8
166 *----------------------------------------------------------------*/
171 UINT8
hwReadRegister8(wlandevice_t
* hw
, UINT offset
)
173 return readb(hw
->iobase
+ offset
);
176 /*----------------------------------------------------------------
178 * FIXME: rename to acx100_write_reg32
192 *----------------------------------------------------------------*/
194 /* hwWriteRegister32()
195 * STATUS: should be ok.
197 void hwWriteRegister32(wlandevice_t
* hw
, UINT offset
, UINT valb
)
199 writel(valb
, hw
->iobase
+ offset
);
202 /*----------------------------------------------------------------
204 * FIXME: rename to acx100_write_reg16
218 *----------------------------------------------------------------*/
220 /* hwWriteRegister16()
221 * STATUS: should be ok.
223 void hwWriteRegister16(wlandevice_t
* hw
, UINT offset
, UINT16 valb
)
225 writew(valb
, hw
->iobase
+ offset
);
228 /*----------------------------------------------------------------
230 * FIXME: rename to acx100_write_reg8
244 *----------------------------------------------------------------*/
246 /* hwWriteRegister8()
247 * STATUS: should be ok.
249 void hwWriteRegister8(wlandevice_t
* hw
, UINT offset
, UINT valb
)
251 writeb(valb
, hw
->iobase
+ offset
);
254 /*****************************************************************************
258 ****************************************************************************/
260 /*----------------------------------------------------------------
262 * FIXME: rename to acx100_get_cmd_state
276 *----------------------------------------------------------------*/
279 * STATUS: wow, lots of errors, but now it should be ok.
281 void get_cmd_state(wlandevice_t
* hw
)
283 hwWriteRegister16(hw
, ACX100_FW_4
, 0x0);
284 hwWriteRegister16(hw
, ACX100_FW_5
, 0x0);
285 hwWriteRegister16(hw
, ACX100_FW_2
, 0x0);
286 hwWriteRegister16(hw
, ACX100_FW_3
, 0x1);
287 hwWriteRegister16(hw
, ACX100_FW_0
,
288 hwReadRegister16(hw
, ACX100_CMD_MAILBOX_OFFS
));
289 hwWriteRegister16(hw
, ACX100_FW_1
, 0x0);
290 hw
->cmd_type
= hwReadRegister16(hw
, ACX100_DATA_LO
);
291 hw
->cmd_status
= hwReadRegister16(hw
, ACX100_DATA_HI
);
293 /*----------------------------------------------------------------
295 * FIXME: rename to acx100_write_cmd_type
309 *----------------------------------------------------------------*/
312 * STATUS: should really be ok.
314 void write_cmd_type(wlandevice_t
* hw
, UINT16 vala
)
316 hwWriteRegister16(hw
, ACX100_FW_4
, 0x0);
317 hwWriteRegister16(hw
, ACX100_FW_5
, 0x0);
318 hwWriteRegister16(hw
, ACX100_FW_2
, 0x0);
319 hwWriteRegister16(hw
, ACX100_FW_3
, 0x1);
320 hwWriteRegister16(hw
, ACX100_FW_0
,
321 hwReadRegister16(hw
, ACX100_CMD_MAILBOX_OFFS
));
322 hwWriteRegister16(hw
, ACX100_FW_1
, 0x0);
323 hwWriteRegister16(hw
, ACX100_DATA_LO
, vala
);
324 hwWriteRegister16(hw
, ACX100_DATA_HI
, 0x0);
327 /*----------------------------------------------------------------
329 * FIXME: rename to acx100_write_cmd_status
343 *----------------------------------------------------------------*/
345 /* write_cmd_status()
346 * STATUS: should really be ok.
348 void write_cmd_status(wlandevice_t
* act
, UINT vala
)
350 hwWriteRegister16(act
, ACX100_FW_4
, 0x0);
351 hwWriteRegister16(act
, ACX100_FW_5
, 0x0);
352 hwWriteRegister16(act
, ACX100_FW_2
, 0x0);
353 hwWriteRegister16(act
, ACX100_FW_3
, 0x1);
354 hwWriteRegister16(act
, ACX100_FW_0
,
355 hwReadRegister16(act
, ACX100_CMD_MAILBOX_OFFS
));
356 hwWriteRegister16(act
, ACX100_FW_1
, 0x0);
357 hwWriteRegister16(act
, ACX100_DATA_LO
, 0x0);
358 hwWriteRegister16(act
, ACX100_DATA_HI
, vala
);
361 /*----------------------------------------------------------------
362 * write_cmd_Parameters
363 * FIXME: rename to acx100_write_cmd_parameters
377 *----------------------------------------------------------------*/
379 /* write_cmd_Parameters()
380 * STATUS: should be ok.
382 int write_cmd_Parameters(wlandevice_t
* hw
, memmap_t
* cmd
, int len
)
384 memcpy((UINT
*) hw
->CommandParameters
, cmd
, len
);
388 /*----------------------------------------------------------------
389 * read_cmd_Parameters
390 * FIXME: rename to acx100_write_cmd_parameters
404 *----------------------------------------------------------------*/
406 /* read_cmd_Parameters()
407 * STATUS: should be ok.
409 int read_cmd_Parameters(wlandevice_t
* hw
, memmap_t
* cmd
, int len
)
411 memcpy(cmd
, (UINT
*) hw
->CommandParameters
, len
);
415 /*----------------------------------------------------------------
417 * FIXME: rename to acx100_issue_cmd
431 *----------------------------------------------------------------*/
434 * STATUS: FINISHED, UNVERIFIED.
436 int ctlIssueCommand(wlandevice_t
* hw
, UINT cmd
,
437 void *pcmdparam
, int paramlen
, UINT32 timeout
)
445 acxlog(L_CTL
, "%s cmd %X timeout %ld: UNVERIFIED.\n", __func__
,
448 /*** make sure we have at least *some* timeout value ***/
454 cmd_state can be one of the following:
459 0xe: "value out of range"
463 /*** wait for ACX100 to become idle for our command submission ***/
464 for (counter
= 2000; counter
> 0; counter
--) {
465 /* FIXME: auwtsh, busy waiting.
466 * Hmm, yeah, but this function is probably supposed to be
467 * finished ASAP, so it's probably not such a terribly good
468 * idea to schedule away instead of busy wait.
469 * Maybe let's just keep it as is. */
471 /* Test for IDLE state */
476 /*** The card doesn't get IDLE, we're in trouble ***/
478 /* uh oh, cmd status still set, now we're in trouble */
479 acxlog((L_BINDEBUG
| L_CTL
),
480 "Trying to issue a command to the ACX100 but the Command Register is not IDLE\n");
484 /*** now write the parameters of the command if needed ***/
485 if (pcmdparam
!= NULL
&& paramlen
!= 0) {
486 if (cmd
== ACX100_CMD_INTERROGATE
) {
487 /* it's an INTERROGATE command, so just pass the length
488 * of parameters to read, as data */
489 write_cmd_Parameters(hw
, pcmdparam
, 0x4);
491 write_cmd_Parameters(hw
, pcmdparam
, paramlen
);
495 /*** now write the actual command type ***/
497 write_cmd_type(hw
, cmd
);
499 /*** is this "execute command" operation? ***/
500 hwWriteRegister16(hw
, ACX100_REG_7C
,
501 hwReadRegister16(hw
, ACX100_REG_7C
) | 0x01);
503 /*** wait for IRQ to occur, then ACK it? ***/
504 if (timeout
> 120000) {
509 for (counter
= timeout
; counter
> 0; counter
--) {
510 /* it's a busy wait loop, but we're supposed to be
511 * fast here, so better don't schedule away here? */
513 hwReadRegister16(hw
, ACX100_STATUS
)) & 0x200) {
514 hwWriteRegister16(hw
, ACX100_IRQ_ACK
, 0x200);
520 /*** Save state for debugging ***/
522 cmd_status
= hw
->cmd_status
;
524 /*** Put the card in IDLE state ***/
526 write_cmd_status(hw
, 0);
528 if ((irqtype
| 0xfdff) == 0xfdff) {
530 "Polling for an IRQ failed with %X, cmd_status %d. Bailing.\n",
531 irqtype
, cmd_status
);
535 if (cmd_status
!= 1) {
536 switch (cmd_status
) {
538 acxlog((L_BINDEBUG
| L_CTL
),
539 "ctlIssueCommand failed: Idle[TIMEOUT] [%ld uSec]\n",
540 (timeout
- counter
) * 50);
544 acxlog((L_BINDEBUG
| L_CTL
),
545 "ctlIssueCommand failed: Unknown Command [%ld uSec]\n",
546 (timeout
- counter
) * 50);
550 acxlog((L_BINDEBUG
| L_CTL
),
551 "ctlIssueCommand failed: INvalid InfoEle [%ld uSec]\n",
552 (timeout
- counter
) * 50);
556 acxlog((L_BINDEBUG
| L_CTL
),
557 "ctlIssueCommand failed: Unknown(0x%x) [%ld uSec]\n",
558 cmd_status
, (timeout
- counter
) * 50);
559 /* cmd_status 0xe might be "value out of range": happens if you
560 * write a value < 1 or > 2 at ctlDot11CurrentTxPowerLevelWrite */
564 /*** read in result parameters if needed ***/
565 if (pcmdparam
!= NULL
&& paramlen
!= 0) {
566 if (cmd
== ACX100_CMD_INTERROGATE
) {
567 read_cmd_Parameters(hw
, pcmdparam
,
580 /*****************************************************************************
584 ****************************************************************************/
586 static short CtlLength
[0x14] = {
588 ACX100_RID_ACX_TIMER_LEN
,
589 ACX100_RID_POWER_MGMT_LEN
,
590 ACX100_RID_QUEUE_CONFIG_LEN
,
591 ACX100_RID_BLOCK_SIZE_LEN
,
592 ACX100_RID_MEMORY_CONFIG_OPTIONS_LEN
,
594 ACX100_RID_WEP_OPTIONS_LEN
,
595 ACX100_RID_MEMORY_MAP_LEN
, // ACX100_RID_SSID_LEN,
597 ACX100_RID_ASSOC_ID_LEN
,
600 ACX100_RID_FWREV_LEN
,
601 ACX100_RID_FCS_ERROR_COUNT_LEN
,
602 ACX100_RID_MEDIUM_USAGE_LEN
,
603 ACX100_RID_RXCONFIG_LEN
,
606 ACX100_RID_FIRMWARE_STATISTICS_LEN
609 static short CtlLengthDot11
[0x14] = {
611 ACX100_RID_DOT11_STATION_ID_LEN
,
613 ACX100_RID_DOT11_BEACON_PERIOD_LEN
,
614 ACX100_RID_DOT11_DTIM_PERIOD_LEN
,
615 ACX100_RID_DOT11_SHORT_RETRY_LIMIT_LEN
,
616 ACX100_RID_DOT11_LONG_RETRY_LIMIT_LEN
,
617 ACX100_RID_DOT11_WEP_DEFAULT_KEY_LEN
,
618 ACX100_RID_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN
,
620 ACX100_RID_DOT11_CURRENT_REG_DOMAIN_LEN
,
621 ACX100_RID_DOT11_CURRENT_ANTENNA_LEN
,
623 ACX100_RID_DOT11_TX_POWER_LEVEL_LEN
,
624 ACX100_RID_DOT11_CURRENT_CCA_MODE_LEN
,
625 ACX100_RID_DOT11_ED_THRESHOLD_LEN
,
626 ACX100_RID_DOT11_WEP_DEFAULT_KEY_SET_LEN
,
632 /*----------------------------------------------------------------
634 * FIXME: acx100_configure
648 *----------------------------------------------------------------*/
651 * STATUS: should be ok. FINISHED.
653 int ctlConfigure(wlandevice_t
* hw
, void * pdr
, short type
)
655 ((memmap_t
*)pdr
)->type
= type
;
657 ((memmap_t
*)pdr
)->length
= CtlLength
[type
];
658 return ctlIssueCommand(hw
, ACX100_CMD_CONFIGURE
, pdr
,
659 CtlLength
[type
] + 4, 5000);
661 ((memmap_t
*)pdr
)->length
= CtlLengthDot11
[type
-0x1000];
662 return ctlIssueCommand(hw
, ACX100_CMD_CONFIGURE
, pdr
,
663 CtlLengthDot11
[type
-0x1000] + 4, 5000);
667 /*----------------------------------------------------------------
669 * FIXME: rename to acx100_configure_length
683 *----------------------------------------------------------------*/
685 /* ctlConfigureLength()
687 int ctlConfigureLength(wlandevice_t
* hw
, void * pdr
, short type
, short length
)
689 ((memmap_t
*)pdr
)->type
= type
;
690 ((memmap_t
*)pdr
)->length
= length
;
691 return ctlIssueCommand(hw
, ACX100_CMD_CONFIGURE
, pdr
,
695 /*----------------------------------------------------------------
697 * FIXME: rename to acx100_interrogate
711 *----------------------------------------------------------------*/
714 * STATUS: should be ok. FINISHED.
716 int ctlInterrogate(wlandevice_t
* hw
, void * pdr
, short type
)
718 ((memmap_t
*)pdr
)->type
= type
;
720 ((memmap_t
*)pdr
)->length
= CtlLength
[type
];
721 return ctlIssueCommand(hw
, ACX100_CMD_INTERROGATE
, pdr
,
722 CtlLength
[type
] + 4, 5000);
724 ((memmap_t
*)pdr
)->length
= CtlLengthDot11
[type
-0x1000];
725 return ctlIssueCommand(hw
, ACX100_CMD_INTERROGATE
, pdr
,
726 CtlLengthDot11
[type
-0x1000] + 4, 5000);
731 /*****************************************************************************
735 ****************************************************************************/
737 /*----------------------------------------------------------------
739 * FIXME: rename to acx100_is_mac_address_zero
753 *----------------------------------------------------------------*/
755 /* IsMacAddressZero()
756 * STATUS: should be ok. FINISHED.
758 int IsMacAddressZero(mac_t
* mac
)
760 if ((mac
->vala
== 0) && (mac
->valb
== 0)) {
765 /*----------------------------------------------------------------
767 * FIXME: rename to acx100_clear_mac_address
781 *----------------------------------------------------------------*/
784 * STATUS: should be ok. FINISHED.
786 void ClearMacAddress(mac_t
* m
)
791 /*----------------------------------------------------------------
793 * FIXME: rename to acx100_is_mac_address_equal
807 *----------------------------------------------------------------*/
809 /* IsMacAddressEqual()
810 * STATUS: should be ok. FINISHED.
812 int IsMacAddressEqual(UINT8
* one
, UINT8
* two
)
814 if (memcmp(one
, two
, WLAN_ADDR_LEN
))
815 return 0; /* no match */
817 return 1; /* matched */
820 /*----------------------------------------------------------------
822 * FIXME: rename to acx100_copy_mac_address
836 *----------------------------------------------------------------*/
839 * STATUS: should be ok. FINISHED.
841 void CopyMacAddress(UINT8
* to
, UINT8
* from
)
843 memcpy(to
, from
, WLAN_ADDR_LEN
);
846 /*----------------------------------------------------------------
848 * FIXME: rename to acx100_is_mac_address_group
862 *----------------------------------------------------------------*/
864 /* IsMacAddressGroup()
865 * STATUS: should be ok. FINISHED.
867 UINT8
IsMacAddressGroup(mac_t
* mac
)
869 return mac
->vala
& 1;
871 /*----------------------------------------------------------------
872 * IsMacAddressDirected
873 * FIXME: rename to acx100_is_mac_address_directed
887 *----------------------------------------------------------------*/
889 /* IsMacAddressDirected()
890 * STATUS: should be ok. FINISHED.
892 UINT8
IsMacAddressDirected(mac_t
* mac
)
900 /*----------------------------------------------------------------
901 * SetMacAddressBroadcast
902 * FIXME: rename to acx100_set_mac_address_broadcast
916 *----------------------------------------------------------------*/
918 /* SetMacAddressBroadcast()
919 * STATUS: should be ok. FINISHED.
921 void SetMacAddressBroadcast(char *mac
)
923 memset(mac
, 0xff, WLAN_ADDR_LEN
);
926 /*----------------------------------------------------------------
927 * IsMacAddressBroadcast
928 * FIXME: rename to acx100_is_mac_address_broadcast
942 *----------------------------------------------------------------*/
944 /* IsMacAddressBroadcast()
945 * STATUS: should be ok. FINISHED.
947 int IsMacAddressBroadcast(mac_t
* mac
)
949 if ((mac
->vala
== 0xffffffff) && (mac
->valb
== 0xffff)) {
955 /*----------------------------------------------------------------
956 * IsMacAddressMulticast
957 * FIXME: rename to acx100_is_mac_address_multicast
971 *----------------------------------------------------------------*/
973 /* IsMacAddressMulticast()
974 * STATUS: should be ok. FINISHED.
976 int IsMacAddressMulticast(mac_t
* mac
)
979 if ((mac
->vala
== 0xffffffff) && (mac
->valb
== 0xffff))
987 /*----------------------------------------------------------------
989 * FIXME: rename to acx100_log_mac_address
1003 *----------------------------------------------------------------*/
1008 void LogMacAddress(int level
, UINT8
* mac
)
1010 acxlog(level
, "%02X.%02X.%02X.%02X.%02X.%02X",
1011 mac
[0], mac
[1], mac
[2], mac
[3], mac
[4], mac
[5]);
1014 /*----------------------------------------------------------------
1030 *----------------------------------------------------------------*/
1032 void acx100_power_led(wlandevice_t
*wlandev
, int enable
)
1035 hwWriteRegister16(wlandev
, 0x290, hwReadRegister16(wlandev
, 0x290) & ~0x0800);
1037 hwWriteRegister16(wlandev
, 0x290, hwReadRegister16(wlandev
, 0x290) | 0x0800);