add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
menuconfig RT2X00
tristate "Ralink driver support"
depends on MAC80211 && WLAN_80211
---help---
This will enable the support for the Ralink drivers,
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
These drivers make use of the mac80211 stack.
When building one of the individual drivers, the rt2x00 library
will also be created. That library (when the driver is built as
a module) will be called rt2x00lib.
Additionally PCI and USB libraries will also be build depending
on the types of drivers being selected, these libraries will be
called rt2x00pci and rt2x00usb.
if RT2X00
config RT2400PCI
tristate "Ralink rt2400 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
This adds support for rt2400 wireless chipset family.
Supported chips: RT2460.
When compiled as a module, this driver will be called rt2400pci.
config RT2500PCI
tristate "Ralink rt2500 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
This adds support for rt2500 wireless chipset family.
Supported chips: RT2560.
When compiled as a module, this driver will be called rt2500pci.
config RT61PCI
tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_PCI
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_ITU_T
select EEPROM_93CX6
---help---
This adds support for rt2501 wireless chipset family.
Supported chips: RT2561, RT2561S & RT2661.
When compiled as a module, this driver will be called rt61pci.
config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
select RT2X00_LIB_USB
select RT2X00_LIB_CRYPTO
---help---
This adds support for rt2500 wireless chipset family.
Supported chips: RT2571 & RT2572.
When compiled as a module, this driver will be called rt2500usb.
config RT73USB
tristate "Ralink rt2501/rt73 (USB) support"
depends on USB
select RT2X00_LIB_USB
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_ITU_T
---help---
This adds support for rt2501 wireless chipset family.
Supported chips: RT2571W, RT2573 & RT2671.
When compiled as a module, this driver will be called rt73usb.
config RT2800USB
tristate "Ralink rt2800 (USB) support"
depends on USB && EXPERIMENTAL
select RT2X00_LIB_USB
select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
---help---
This adds experimental support for rt2800 wireless chipset family.
Supported chips: RT2770, RT2870 & RT3070.
When compiled as a module, this driver will be called "rt2800usb.ko".
config RT2X00_LIB_PCI
tristate
select RT2X00_LIB
config RT2X00_LIB_USB
tristate
select RT2X00_LIB
config RT2X00_LIB
tristate
config RT2X00_LIB_HT
boolean
config RT2X00_LIB_FIRMWARE
boolean
select FW_LOADER
config RT2X00_LIB_CRYPTO
boolean
config RT2X00_LIB_LEDS
boolean
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00"
depends on RT2X00_LIB=y && LEDS_CLASS=m
config RT2X00_LIB_DEBUGFS
bool "Ralink debugfs support"
depends on RT2X00_LIB && MAC80211_DEBUGFS
---help---
Enable creation of debugfs files for the rt2x00 drivers.
These debugfs files support both reading and writing of the
most important register types of the rt2x00 hardware.
config RT2X00_DEBUG
bool "Ralink debug output"
depends on RT2X00_LIB
---help---
Enable debugging output for all rt2x00 modules
endif

View File

@@ -0,0 +1,20 @@
rt2x00lib-y += rt2x00dev.o
rt2x00lib-y += rt2x00mac.o
rt2x00lib-y += rt2x00config.o
rt2x00lib-y += rt2x00queue.o
rt2x00lib-y += rt2x00link.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
obj-$(CONFIG_RT2400PCI) += rt2400pci.o
obj-$(CONFIG_RT2500PCI) += rt2500pci.o
obj-$(CONFIG_RT61PCI) += rt61pci.o
obj-$(CONFIG_RT2500USB) += rt2500usb.o
obj-$(CONFIG_RT73USB) += rt73usb.o
obj-$(CONFIG_RT2800USB) += rt2800usb.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,952 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2400pci
Abstract: Data structures and registers for the rt2400pci module.
Supported chipsets: RT2460.
*/
#ifndef RT2400PCI_H
#define RT2400PCI_H
/*
* RF chip defines.
*/
#define RF2420 0x0000
#define RF2421 0x0001
/*
* Signal information.
* Defaul offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 100
/*
* Register layout information.
*/
#define CSR_REG_BASE 0x0000
#define CSR_REG_SIZE 0x014c
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x0100
#define BBP_BASE 0x0000
#define BBP_SIZE 0x0020
#define RF_BASE 0x0004
#define RF_SIZE 0x000c
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* CSR0: ASIC revision number.
*/
#define CSR0 0x0000
/*
* CSR1: System control register.
* SOFT_RESET: Software reset, 1: reset, 0: normal.
* BBP_RESET: Hardware reset, 1: reset, 0, release.
* HOST_READY: Host ready after initialization.
*/
#define CSR1 0x0004
#define CSR1_SOFT_RESET FIELD32(0x00000001)
#define CSR1_BBP_RESET FIELD32(0x00000002)
#define CSR1_HOST_READY FIELD32(0x00000004)
/*
* CSR2: System admin status register (invalid).
*/
#define CSR2 0x0008
/*
* CSR3: STA MAC address register 0.
*/
#define CSR3 0x000c
#define CSR3_BYTE0 FIELD32(0x000000ff)
#define CSR3_BYTE1 FIELD32(0x0000ff00)
#define CSR3_BYTE2 FIELD32(0x00ff0000)
#define CSR3_BYTE3 FIELD32(0xff000000)
/*
* CSR4: STA MAC address register 1.
*/
#define CSR4 0x0010
#define CSR4_BYTE4 FIELD32(0x000000ff)
#define CSR4_BYTE5 FIELD32(0x0000ff00)
/*
* CSR5: BSSID register 0.
*/
#define CSR5 0x0014
#define CSR5_BYTE0 FIELD32(0x000000ff)
#define CSR5_BYTE1 FIELD32(0x0000ff00)
#define CSR5_BYTE2 FIELD32(0x00ff0000)
#define CSR5_BYTE3 FIELD32(0xff000000)
/*
* CSR6: BSSID register 1.
*/
#define CSR6 0x0018
#define CSR6_BYTE4 FIELD32(0x000000ff)
#define CSR6_BYTE5 FIELD32(0x0000ff00)
/*
* CSR7: Interrupt source register.
* Write 1 to clear interrupt.
* TBCN_EXPIRE: Beacon timer expired interrupt.
* TWAKE_EXPIRE: Wakeup timer expired interrupt.
* TATIMW_EXPIRE: Timer of atim window expired interrupt.
* TXDONE_TXRING: Tx ring transmit done interrupt.
* TXDONE_ATIMRING: Atim ring transmit done interrupt.
* TXDONE_PRIORING: Priority ring transmit done interrupt.
* RXDONE: Receive done interrupt.
*/
#define CSR7 0x001c
#define CSR7_TBCN_EXPIRE FIELD32(0x00000001)
#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002)
#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004)
#define CSR7_TXDONE_TXRING FIELD32(0x00000008)
#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010)
#define CSR7_TXDONE_PRIORING FIELD32(0x00000020)
#define CSR7_RXDONE FIELD32(0x00000040)
/*
* CSR8: Interrupt mask register.
* Write 1 to mask interrupt.
* TBCN_EXPIRE: Beacon timer expired interrupt.
* TWAKE_EXPIRE: Wakeup timer expired interrupt.
* TATIMW_EXPIRE: Timer of atim window expired interrupt.
* TXDONE_TXRING: Tx ring transmit done interrupt.
* TXDONE_ATIMRING: Atim ring transmit done interrupt.
* TXDONE_PRIORING: Priority ring transmit done interrupt.
* RXDONE: Receive done interrupt.
*/
#define CSR8 0x0020
#define CSR8_TBCN_EXPIRE FIELD32(0x00000001)
#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002)
#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004)
#define CSR8_TXDONE_TXRING FIELD32(0x00000008)
#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010)
#define CSR8_TXDONE_PRIORING FIELD32(0x00000020)
#define CSR8_RXDONE FIELD32(0x00000040)
/*
* CSR9: Maximum frame length register.
* MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
*/
#define CSR9 0x0024
#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80)
/*
* CSR11: Back-off control register.
* CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
* CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
* SLOT_TIME: Slot time, default is 20us for 802.11b.
* LONG_RETRY: Long retry count.
* SHORT_RETRY: Short retry count.
*/
#define CSR11 0x002c
#define CSR11_CWMIN FIELD32(0x0000000f)
#define CSR11_CWMAX FIELD32(0x000000f0)
#define CSR11_SLOT_TIME FIELD32(0x00001f00)
#define CSR11_LONG_RETRY FIELD32(0x00ff0000)
#define CSR11_SHORT_RETRY FIELD32(0xff000000)
/*
* CSR12: Synchronization configuration register 0.
* All units in 1/16 TU.
* BEACON_INTERVAL: Beacon interval, default is 100 TU.
* CFPMAX_DURATION: Cfp maximum duration, default is 100 TU.
*/
#define CSR12 0x0030
#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff)
#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000)
/*
* CSR13: Synchronization configuration register 1.
* All units in 1/16 TU.
* ATIMW_DURATION: Atim window duration.
* CFP_PERIOD: Cfp period, default is 0 TU.
*/
#define CSR13 0x0034
#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff)
#define CSR13_CFP_PERIOD FIELD32(0x00ff0000)
/*
* CSR14: Synchronization control register.
* TSF_COUNT: Enable tsf auto counting.
* TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
* TBCN: Enable tbcn with reload value.
* TCFP: Enable tcfp & cfp / cp switching.
* TATIMW: Enable tatimw & atim window switching.
* BEACON_GEN: Enable beacon generator.
* CFP_COUNT_PRELOAD: Cfp count preload value.
* TBCM_PRELOAD: Tbcn preload value in units of 64us.
*/
#define CSR14 0x0038
#define CSR14_TSF_COUNT FIELD32(0x00000001)
#define CSR14_TSF_SYNC FIELD32(0x00000006)
#define CSR14_TBCN FIELD32(0x00000008)
#define CSR14_TCFP FIELD32(0x00000010)
#define CSR14_TATIMW FIELD32(0x00000020)
#define CSR14_BEACON_GEN FIELD32(0x00000040)
#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00)
#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000)
/*
* CSR15: Synchronization status register.
* CFP: ASIC is in contention-free period.
* ATIMW: ASIC is in ATIM window.
* BEACON_SENT: Beacon is send.
*/
#define CSR15 0x003c
#define CSR15_CFP FIELD32(0x00000001)
#define CSR15_ATIMW FIELD32(0x00000002)
#define CSR15_BEACON_SENT FIELD32(0x00000004)
/*
* CSR16: TSF timer register 0.
*/
#define CSR16 0x0040
#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff)
/*
* CSR17: TSF timer register 1.
*/
#define CSR17 0x0044
#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff)
/*
* CSR18: IFS timer register 0.
* SIFS: Sifs, default is 10 us.
* PIFS: Pifs, default is 30 us.
*/
#define CSR18 0x0048
#define CSR18_SIFS FIELD32(0x0000ffff)
#define CSR18_PIFS FIELD32(0xffff0000)
/*
* CSR19: IFS timer register 1.
* DIFS: Difs, default is 50 us.
* EIFS: Eifs, default is 364 us.
*/
#define CSR19 0x004c
#define CSR19_DIFS FIELD32(0x0000ffff)
#define CSR19_EIFS FIELD32(0xffff0000)
/*
* CSR20: Wakeup timer register.
* DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
* TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
* AUTOWAKE: Enable auto wakeup / sleep mechanism.
*/
#define CSR20 0x0050
#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff)
#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000)
#define CSR20_AUTOWAKE FIELD32(0x01000000)
/*
* CSR21: EEPROM control register.
* RELOAD: Write 1 to reload eeprom content.
* TYPE_93C46: 1: 93c46, 0:93c66.
*/
#define CSR21 0x0054
#define CSR21_RELOAD FIELD32(0x00000001)
#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002)
#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004)
#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008)
#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010)
#define CSR21_TYPE_93C46 FIELD32(0x00000020)
/*
* CSR22: CFP control register.
* CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
* RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
*/
#define CSR22 0x0058
#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff)
#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000)
/*
* Transmit related CSRs.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* TXCSR0: TX Control Register.
* KICK_TX: Kick tx ring.
* KICK_ATIM: Kick atim ring.
* KICK_PRIO: Kick priority ring.
* ABORT: Abort all transmit related ring operation.
*/
#define TXCSR0 0x0060
#define TXCSR0_KICK_TX FIELD32(0x00000001)
#define TXCSR0_KICK_ATIM FIELD32(0x00000002)
#define TXCSR0_KICK_PRIO FIELD32(0x00000004)
#define TXCSR0_ABORT FIELD32(0x00000008)
/*
* TXCSR1: TX Configuration Register.
* ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
* ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
* TSF_OFFSET: Insert tsf offset.
* AUTORESPONDER: Enable auto responder which include ack & cts.
*/
#define TXCSR1 0x0064
#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff)
#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00)
#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000)
#define TXCSR1_AUTORESPONDER FIELD32(0x01000000)
/*
* TXCSR2: Tx descriptor configuration register.
* TXD_SIZE: Tx descriptor size, default is 48.
* NUM_TXD: Number of tx entries in ring.
* NUM_ATIM: Number of atim entries in ring.
* NUM_PRIO: Number of priority entries in ring.
*/
#define TXCSR2 0x0068
#define TXCSR2_TXD_SIZE FIELD32(0x000000ff)
#define TXCSR2_NUM_TXD FIELD32(0x0000ff00)
#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000)
#define TXCSR2_NUM_PRIO FIELD32(0xff000000)
/*
* TXCSR3: TX Ring Base address register.
*/
#define TXCSR3 0x006c
#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR4: TX Atim Ring Base address register.
*/
#define TXCSR4 0x0070
#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR5: TX Prio Ring Base address register.
*/
#define TXCSR5 0x0074
#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR6: Beacon Base address register.
*/
#define TXCSR6 0x0078
#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR7: Auto responder control register.
* AR_POWERMANAGEMENT: Auto responder power management bit.
*/
#define TXCSR7 0x007c
#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001)
/*
* Receive related CSRs.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* RXCSR0: RX Control Register.
* DISABLE_RX: Disable rx engine.
* DROP_CRC: Drop crc error.
* DROP_PHYSICAL: Drop physical error.
* DROP_CONTROL: Drop control frame.
* DROP_NOT_TO_ME: Drop not to me unicast frame.
* DROP_TODS: Drop frame tods bit is true.
* DROP_VERSION_ERROR: Drop version error frame.
* PASS_CRC: Pass all packets with crc attached.
*/
#define RXCSR0 0x0080
#define RXCSR0_DISABLE_RX FIELD32(0x00000001)
#define RXCSR0_DROP_CRC FIELD32(0x00000002)
#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004)
#define RXCSR0_DROP_CONTROL FIELD32(0x00000008)
#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010)
#define RXCSR0_DROP_TODS FIELD32(0x00000020)
#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040)
#define RXCSR0_PASS_CRC FIELD32(0x00000080)
/*
* RXCSR1: RX descriptor configuration register.
* RXD_SIZE: Rx descriptor size, default is 32b.
* NUM_RXD: Number of rx entries in ring.
*/
#define RXCSR1 0x0084
#define RXCSR1_RXD_SIZE FIELD32(0x000000ff)
#define RXCSR1_NUM_RXD FIELD32(0x0000ff00)
/*
* RXCSR2: RX Ring base address register.
*/
#define RXCSR2 0x0088
#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff)
/*
* RXCSR3: BBP ID register for Rx operation.
* BBP_ID#: BBP register # id.
* BBP_ID#_VALID: BBP register # id is valid or not.
*/
#define RXCSR3 0x0090
#define RXCSR3_BBP_ID0 FIELD32(0x0000007f)
#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080)
#define RXCSR3_BBP_ID1 FIELD32(0x00007f00)
#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000)
#define RXCSR3_BBP_ID2 FIELD32(0x007f0000)
#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000)
#define RXCSR3_BBP_ID3 FIELD32(0x7f000000)
#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000)
/*
* RXCSR4: BBP ID register for Rx operation.
* BBP_ID#: BBP register # id.
* BBP_ID#_VALID: BBP register # id is valid or not.
*/
#define RXCSR4 0x0094
#define RXCSR4_BBP_ID4 FIELD32(0x0000007f)
#define RXCSR4_BBP_ID4_VALID FIELD32(0x00000080)
#define RXCSR4_BBP_ID5 FIELD32(0x00007f00)
#define RXCSR4_BBP_ID5_VALID FIELD32(0x00008000)
/*
* ARCSR0: Auto Responder PLCP config register 0.
* ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
* ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
*/
#define ARCSR0 0x0098
#define ARCSR0_AR_BBP_DATA0 FIELD32(0x000000ff)
#define ARCSR0_AR_BBP_ID0 FIELD32(0x0000ff00)
#define ARCSR0_AR_BBP_DATA1 FIELD32(0x00ff0000)
#define ARCSR0_AR_BBP_ID1 FIELD32(0xff000000)
/*
* ARCSR1: Auto Responder PLCP config register 1.
* ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
* ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
*/
#define ARCSR1 0x009c
#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff)
#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00)
#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000)
#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000)
/*
* Miscellaneous Registers.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* PCICSR: PCI control register.
* BIG_ENDIAN: 1: big endian, 0: little endian.
* RX_TRESHOLD: Rx threshold in dw to start pci access
* 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
* TX_TRESHOLD: Tx threshold in dw to start pci access
* 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
* BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
* ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
*/
#define PCICSR 0x008c
#define PCICSR_BIG_ENDIAN FIELD32(0x00000001)
#define PCICSR_RX_TRESHOLD FIELD32(0x00000006)
#define PCICSR_TX_TRESHOLD FIELD32(0x00000018)
#define PCICSR_BURST_LENTH FIELD32(0x00000060)
#define PCICSR_ENABLE_CLK FIELD32(0x00000080)
/*
* CNT0: FCS error count.
* FCS_ERROR: FCS error count, cleared when read.
*/
#define CNT0 0x00a0
#define CNT0_FCS_ERROR FIELD32(0x0000ffff)
/*
* Statistic Register.
* CNT1: PLCP error count.
* CNT2: Long error count.
* CNT3: CCA false alarm count.
* CNT4: Rx FIFO overflow count.
* CNT5: Tx FIFO underrun count.
*/
#define TIMECSR2 0x00a8
#define CNT1 0x00ac
#define CNT2 0x00b0
#define TIMECSR3 0x00b4
#define CNT3 0x00b8
#define CNT4 0x00bc
#define CNT5 0x00c0
/*
* Baseband Control Register.
*/
/*
* PWRCSR0: Power mode configuration register.
*/
#define PWRCSR0 0x00c4
/*
* Power state transition time registers.
*/
#define PSCSR0 0x00c8
#define PSCSR1 0x00cc
#define PSCSR2 0x00d0
#define PSCSR3 0x00d4
/*
* PWRCSR1: Manual power control / status register.
* Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
* SET_STATE: Set state. Write 1 to trigger, self cleared.
* BBP_DESIRE_STATE: BBP desired state.
* RF_DESIRE_STATE: RF desired state.
* BBP_CURR_STATE: BBP current state.
* RF_CURR_STATE: RF current state.
* PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
*/
#define PWRCSR1 0x00d8
#define PWRCSR1_SET_STATE FIELD32(0x00000001)
#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006)
#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018)
#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060)
#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180)
#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200)
/*
* TIMECSR: Timer control register.
* US_COUNT: 1 us timer count in units of clock cycles.
* US_64_COUNT: 64 us timer count in units of 1 us timer.
* BEACON_EXPECT: Beacon expect window.
*/
#define TIMECSR 0x00dc
#define TIMECSR_US_COUNT FIELD32(0x000000ff)
#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00)
#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000)
/*
* MACCSR0: MAC configuration register 0.
*/
#define MACCSR0 0x00e0
/*
* MACCSR1: MAC configuration register 1.
* KICK_RX: Kick one-shot rx in one-shot rx mode.
* ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
* BBPRX_RESET_MODE: Ralink bbp rx reset mode.
* AUTO_TXBBP: Auto tx logic access bbp control register.
* AUTO_RXBBP: Auto rx logic access bbp control register.
* LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
* INTERSIL_IF: Intersil if calibration pin.
*/
#define MACCSR1 0x00e4
#define MACCSR1_KICK_RX FIELD32(0x00000001)
#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002)
#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004)
#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008)
#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010)
#define MACCSR1_LOOPBACK FIELD32(0x00000060)
#define MACCSR1_INTERSIL_IF FIELD32(0x00000080)
/*
* RALINKCSR: Ralink Rx auto-reset BBCR.
* AR_BBP_DATA#: Auto reset BBP register # data.
* AR_BBP_ID#: Auto reset BBP register # id.
*/
#define RALINKCSR 0x00e8
#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff)
#define RALINKCSR_AR_BBP_ID0 FIELD32(0x0000ff00)
#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000)
#define RALINKCSR_AR_BBP_ID1 FIELD32(0xff000000)
/*
* BCNCSR: Beacon interval control register.
* CHANGE: Write one to change beacon interval.
* DELTATIME: The delta time value.
* NUM_BEACON: Number of beacon according to mode.
* MODE: Please refer to asic specs.
* PLUS: Plus or minus delta time value.
*/
#define BCNCSR 0x00ec
#define BCNCSR_CHANGE FIELD32(0x00000001)
#define BCNCSR_DELTATIME FIELD32(0x0000001e)
#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0)
#define BCNCSR_MODE FIELD32(0x00006000)
#define BCNCSR_PLUS FIELD32(0x00008000)
/*
* BBP / RF / IF Control Register.
*/
/*
* BBPCSR: BBP serial control register.
* VALUE: Register value to program into BBP.
* REGNUM: Selected BBP register.
* BUSY: 1: asic is busy execute BBP programming.
* WRITE_CONTROL: 1: write BBP, 0: read BBP.
*/
#define BBPCSR 0x00f0
#define BBPCSR_VALUE FIELD32(0x000000ff)
#define BBPCSR_REGNUM FIELD32(0x00007f00)
#define BBPCSR_BUSY FIELD32(0x00008000)
#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000)
/*
* RFCSR: RF serial control register.
* VALUE: Register value + id to program into rf/if.
* NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
* IF_SELECT: Chip to program: 0: rf, 1: if.
* PLL_LD: Rf pll_ld status.
* BUSY: 1: asic is busy execute rf programming.
*/
#define RFCSR 0x00f4
#define RFCSR_VALUE FIELD32(0x00ffffff)
#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000)
#define RFCSR_IF_SELECT FIELD32(0x20000000)
#define RFCSR_PLL_LD FIELD32(0x40000000)
#define RFCSR_BUSY FIELD32(0x80000000)
/*
* LEDCSR: LED control register.
* ON_PERIOD: On period, default 70ms.
* OFF_PERIOD: Off period, default 30ms.
* LINK: 0: linkoff, 1: linkup.
* ACTIVITY: 0: idle, 1: active.
*/
#define LEDCSR 0x00f8
#define LEDCSR_ON_PERIOD FIELD32(0x000000ff)
#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00)
#define LEDCSR_LINK FIELD32(0x00010000)
#define LEDCSR_ACTIVITY FIELD32(0x00020000)
/*
* ASIC pointer information.
* RXPTR: Current RX ring address.
* TXPTR: Current Tx ring address.
* PRIPTR: Current Priority ring address.
* ATIMPTR: Current ATIM ring address.
*/
#define RXPTR 0x0100
#define TXPTR 0x0104
#define PRIPTR 0x0108
#define ATIMPTR 0x010c
/*
* GPIO and others.
*/
/*
* GPIOCSR: GPIO control register.
*/
#define GPIOCSR 0x0120
#define GPIOCSR_BIT0 FIELD32(0x00000001)
#define GPIOCSR_BIT1 FIELD32(0x00000002)
#define GPIOCSR_BIT2 FIELD32(0x00000004)
#define GPIOCSR_BIT3 FIELD32(0x00000008)
#define GPIOCSR_BIT4 FIELD32(0x00000010)
#define GPIOCSR_BIT5 FIELD32(0x00000020)
#define GPIOCSR_BIT6 FIELD32(0x00000040)
#define GPIOCSR_BIT7 FIELD32(0x00000080)
/*
* BBPPCSR: BBP Pin control register.
*/
#define BBPPCSR 0x0124
/*
* BCNCSR1: Tx BEACON offset time control register.
* PRELOAD: Beacon timer offset in units of usec.
*/
#define BCNCSR1 0x0130
#define BCNCSR1_PRELOAD FIELD32(0x0000ffff)
/*
* MACCSR2: TX_PE to RX_PE turn-around time control register
* DELAY: RX_PE low width, in units of pci clock cycle.
*/
#define MACCSR2 0x0134
#define MACCSR2_DELAY FIELD32(0x000000ff)
/*
* ARCSR2: 1 Mbps ACK/CTS PLCP.
*/
#define ARCSR2 0x013c
#define ARCSR2_SIGNAL FIELD32(0x000000ff)
#define ARCSR2_SERVICE FIELD32(0x0000ff00)
#define ARCSR2_LENGTH_LOW FIELD32(0x00ff0000)
#define ARCSR2_LENGTH FIELD32(0xffff0000)
/*
* ARCSR3: 2 Mbps ACK/CTS PLCP.
*/
#define ARCSR3 0x0140
#define ARCSR3_SIGNAL FIELD32(0x000000ff)
#define ARCSR3_SERVICE FIELD32(0x0000ff00)
#define ARCSR3_LENGTH FIELD32(0xffff0000)
/*
* ARCSR4: 5.5 Mbps ACK/CTS PLCP.
*/
#define ARCSR4 0x0144
#define ARCSR4_SIGNAL FIELD32(0x000000ff)
#define ARCSR4_SERVICE FIELD32(0x0000ff00)
#define ARCSR4_LENGTH FIELD32(0xffff0000)
/*
* ARCSR5: 11 Mbps ACK/CTS PLCP.
*/
#define ARCSR5 0x0148
#define ARCSR5_SIGNAL FIELD32(0x000000ff)
#define ARCSR5_SERVICE FIELD32(0x0000ff00)
#define ARCSR5_LENGTH FIELD32(0xffff0000)
/*
* BBP registers.
* The wordsize of the BBP is 8 bits.
*/
/*
* R1: TX antenna control
*/
#define BBP_R1_TX_ANTENNA FIELD8(0x03)
/*
* R4: RX antenna control
*/
#define BBP_R4_RX_ANTENNA FIELD8(0x06)
/*
* RF registers
*/
/*
* RF 1
*/
#define RF1_TUNER FIELD32(0x00020000)
/*
* RF 3
*/
#define RF3_TUNER FIELD32(0x00000100)
#define RF3_TXPOWER FIELD32(0x00003e00)
/*
* EEPROM content.
* The wordsize of the EEPROM is 16 bits.
*/
/*
* HW MAC address.
*/
#define EEPROM_MAC_ADDR_0 0x0002
#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
#define EEPROM_MAC_ADDR1 0x0003
#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
#define EEPROM_MAC_ADDR_2 0x0004
#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
/*
* EEPROM antenna.
* ANTENNA_NUM: Number of antenna's.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RF_TYPE: Rf_type of this adapter.
* LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
* RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning.
* HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
*/
#define EEPROM_ANTENNA 0x0b
#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0040)
#define EEPROM_ANTENNA_LED_MODE FIELD16(0x0180)
#define EEPROM_ANTENNA_RX_AGCVGC_TUNING FIELD16(0x0200)
#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
/*
* EEPROM BBP.
*/
#define EEPROM_BBP_START 0x0c
#define EEPROM_BBP_SIZE 7
#define EEPROM_BBP_VALUE FIELD16(0x00ff)
#define EEPROM_BBP_REG_ID FIELD16(0xff00)
/*
* EEPROM TXPOWER
*/
#define EEPROM_TXPOWER_START 0x13
#define EEPROM_TXPOWER_SIZE 7
#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
#define EEPROM_TXPOWER_2 FIELD16(0xff00)
/*
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 8 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 8 * sizeof(__le32) )
/*
* TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
*/
/*
* Word0
*/
#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
#define TXD_W0_VALID FIELD32(0x00000002)
#define TXD_W0_RESULT FIELD32(0x0000001c)
#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0)
#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
#define TXD_W0_ACK FIELD32(0x00000200)
#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
#define TXD_W0_RTS FIELD32(0x00000800)
#define TXD_W0_IFS FIELD32(0x00006000)
#define TXD_W0_RETRY_MODE FIELD32(0x00008000)
#define TXD_W0_AGC FIELD32(0x00ff0000)
#define TXD_W0_R2 FIELD32(0xff000000)
/*
* Word1
*/
#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
/*
* Word2
*/
#define TXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
#define TXD_W2_DATABYTE_COUNT FIELD32(0xffff0000)
/*
* Word3 & 4: PLCP information
* The PLCP values should be treated as if they were BBP values.
*/
#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff)
#define TXD_W3_PLCP_SIGNAL_REGNUM FIELD32(0x00007f00)
#define TXD_W3_PLCP_SIGNAL_BUSY FIELD32(0x00008000)
#define TXD_W3_PLCP_SERVICE FIELD32(0x00ff0000)
#define TXD_W3_PLCP_SERVICE_REGNUM FIELD32(0x7f000000)
#define TXD_W3_PLCP_SERVICE_BUSY FIELD32(0x80000000)
#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x000000ff)
#define TXD_W3_PLCP_LENGTH_LOW_REGNUM FIELD32(0x00007f00)
#define TXD_W3_PLCP_LENGTH_LOW_BUSY FIELD32(0x00008000)
#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0x00ff0000)
#define TXD_W3_PLCP_LENGTH_HIGH_REGNUM FIELD32(0x7f000000)
#define TXD_W3_PLCP_LENGTH_HIGH_BUSY FIELD32(0x80000000)
/*
* Word5
*/
#define TXD_W5_BBCR4 FIELD32(0x0000ffff)
#define TXD_W5_AGC_REG FIELD32(0x007f0000)
#define TXD_W5_AGC_REG_VALID FIELD32(0x00800000)
#define TXD_W5_XXX_REG FIELD32(0x7f000000)
#define TXD_W5_XXX_REG_VALID FIELD32(0x80000000)
/*
* Word6
*/
#define TXD_W6_SK_BUFF FIELD32(0xffffffff)
/*
* Word7
*/
#define TXD_W7_RESERVED FIELD32(0xffffffff)
/*
* RX descriptor format for RX Ring.
*/
/*
* Word0
*/
#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
#define RXD_W0_MULTICAST FIELD32(0x00000004)
#define RXD_W0_BROADCAST FIELD32(0x00000008)
#define RXD_W0_MY_BSS FIELD32(0x00000010)
#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
#define RXD_W0_DATABYTE_COUNT FIELD32(0xffff0000)
/*
* Word1
*/
#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
/*
* Word2
*/
#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
#define RXD_W2_BBR0 FIELD32(0x00ff0000)
#define RXD_W2_SIGNAL FIELD32(0xff000000)
/*
* Word3
*/
#define RXD_W3_RSSI FIELD32(0x000000ff)
#define RXD_W3_BBR3 FIELD32(0x0000ff00)
#define RXD_W3_BBR4 FIELD32(0x00ff0000)
#define RXD_W3_BBR5 FIELD32(0xff000000)
/*
* Word4
*/
#define RXD_W4_RX_END_TIME FIELD32(0xffffffff)
/*
* Word5 & 6 & 7: Reserved
*/
#define RXD_W5_RESERVED FIELD32(0xffffffff)
#define RXD_W6_RESERVED FIELD32(0xffffffff)
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
* Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
* value means that the txpower must be lowered. This is
* important when converting the value coming from the
* mac80211 stack to the rt2400 acceptable value.
*/
#define MIN_TXPOWER 31
#define MAX_TXPOWER 62
#define DEFAULT_TXPOWER 39
#define __CLAMP_TX(__txpower) \
clamp_t(char, (__txpower), MIN_TXPOWER, MAX_TXPOWER)
#define TXPOWER_FROM_DEV(__txpower) \
((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER)
#define TXPOWER_TO_DEV(__txpower) \
MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER)
#endif /* RT2400PCI_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,847 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2500usb
Abstract: Data structures and registers for the rt2500usb module.
Supported chipsets: RT2570.
*/
#ifndef RT2500USB_H
#define RT2500USB_H
/*
* RF chip defines.
*/
#define RF2522 0x0000
#define RF2523 0x0001
#define RF2524 0x0002
#define RF2525 0x0003
#define RF2525E 0x0005
#define RF5222 0x0010
/*
* RT2570 version
*/
#define RT2570_VERSION_B 2
#define RT2570_VERSION_C 3
#define RT2570_VERSION_D 4
/*
* Signal information.
* Defaul offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 120
/*
* Register layout information.
*/
#define CSR_REG_BASE 0x0400
#define CSR_REG_SIZE 0x0100
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x006a
#define BBP_BASE 0x0000
#define BBP_SIZE 0x0060
#define RF_BASE 0x0004
#define RF_SIZE 0x0010
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* MAC_CSR0: ASIC revision number.
*/
#define MAC_CSR0 0x0400
/*
* MAC_CSR1: System control.
* SOFT_RESET: Software reset, 1: reset, 0: normal.
* BBP_RESET: Hardware reset, 1: reset, 0, release.
* HOST_READY: Host ready after initialization.
*/
#define MAC_CSR1 0x0402
#define MAC_CSR1_SOFT_RESET FIELD16(0x00000001)
#define MAC_CSR1_BBP_RESET FIELD16(0x00000002)
#define MAC_CSR1_HOST_READY FIELD16(0x00000004)
/*
* MAC_CSR2: STA MAC register 0.
*/
#define MAC_CSR2 0x0404
#define MAC_CSR2_BYTE0 FIELD16(0x00ff)
#define MAC_CSR2_BYTE1 FIELD16(0xff00)
/*
* MAC_CSR3: STA MAC register 1.
*/
#define MAC_CSR3 0x0406
#define MAC_CSR3_BYTE2 FIELD16(0x00ff)
#define MAC_CSR3_BYTE3 FIELD16(0xff00)
/*
* MAC_CSR4: STA MAC register 2.
*/
#define MAC_CSR4 0X0408
#define MAC_CSR4_BYTE4 FIELD16(0x00ff)
#define MAC_CSR4_BYTE5 FIELD16(0xff00)
/*
* MAC_CSR5: BSSID register 0.
*/
#define MAC_CSR5 0x040a
#define MAC_CSR5_BYTE0 FIELD16(0x00ff)
#define MAC_CSR5_BYTE1 FIELD16(0xff00)
/*
* MAC_CSR6: BSSID register 1.
*/
#define MAC_CSR6 0x040c
#define MAC_CSR6_BYTE2 FIELD16(0x00ff)
#define MAC_CSR6_BYTE3 FIELD16(0xff00)
/*
* MAC_CSR7: BSSID register 2.
*/
#define MAC_CSR7 0x040e
#define MAC_CSR7_BYTE4 FIELD16(0x00ff)
#define MAC_CSR7_BYTE5 FIELD16(0xff00)
/*
* MAC_CSR8: Max frame length.
*/
#define MAC_CSR8 0x0410
#define MAC_CSR8_MAX_FRAME_UNIT FIELD16(0x0fff)
/*
* Misc MAC_CSR registers.
* MAC_CSR9: Timer control.
* MAC_CSR10: Slot time.
* MAC_CSR11: SIFS.
* MAC_CSR12: EIFS.
* MAC_CSR13: Power mode0.
* MAC_CSR14: Power mode1.
* MAC_CSR15: Power saving transition0
* MAC_CSR16: Power saving transition1
*/
#define MAC_CSR9 0x0412
#define MAC_CSR10 0x0414
#define MAC_CSR11 0x0416
#define MAC_CSR12 0x0418
#define MAC_CSR13 0x041a
#define MAC_CSR14 0x041c
#define MAC_CSR15 0x041e
#define MAC_CSR16 0x0420
/*
* MAC_CSR17: Manual power control / status register.
* Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
* SET_STATE: Set state. Write 1 to trigger, self cleared.
* BBP_DESIRE_STATE: BBP desired state.
* RF_DESIRE_STATE: RF desired state.
* BBP_CURRENT_STATE: BBP current state.
* RF_CURRENT_STATE: RF current state.
* PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
*/
#define MAC_CSR17 0x0422
#define MAC_CSR17_SET_STATE FIELD16(0x0001)
#define MAC_CSR17_BBP_DESIRE_STATE FIELD16(0x0006)
#define MAC_CSR17_RF_DESIRE_STATE FIELD16(0x0018)
#define MAC_CSR17_BBP_CURR_STATE FIELD16(0x0060)
#define MAC_CSR17_RF_CURR_STATE FIELD16(0x0180)
#define MAC_CSR17_PUT_TO_SLEEP FIELD16(0x0200)
/*
* MAC_CSR18: Wakeup timer register.
* DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU.
* BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup.
* AUTO_WAKE: Enable auto wakeup / sleep mechanism.
*/
#define MAC_CSR18 0x0424
#define MAC_CSR18_DELAY_AFTER_BEACON FIELD16(0x00ff)
#define MAC_CSR18_BEACONS_BEFORE_WAKEUP FIELD16(0x7f00)
#define MAC_CSR18_AUTO_WAKE FIELD16(0x8000)
/*
* MAC_CSR19: GPIO control register.
*/
#define MAC_CSR19 0x0426
#define MAC_CSR19_BIT0 FIELD32(0x0001)
#define MAC_CSR19_BIT1 FIELD32(0x0002)
#define MAC_CSR19_BIT2 FIELD32(0x0004)
#define MAC_CSR19_BIT3 FIELD32(0x0008)
#define MAC_CSR19_BIT4 FIELD32(0x0010)
#define MAC_CSR19_BIT5 FIELD32(0x0020)
#define MAC_CSR19_BIT6 FIELD32(0x0040)
#define MAC_CSR19_BIT7 FIELD32(0x0080)
/*
* MAC_CSR20: LED control register.
* ACTIVITY: 0: idle, 1: active.
* LINK: 0: linkoff, 1: linkup.
* ACTIVITY_POLARITY: 0: active low, 1: active high.
*/
#define MAC_CSR20 0x0428
#define MAC_CSR20_ACTIVITY FIELD16(0x0001)
#define MAC_CSR20_LINK FIELD16(0x0002)
#define MAC_CSR20_ACTIVITY_POLARITY FIELD16(0x0004)
/*
* MAC_CSR21: LED control register.
* ON_PERIOD: On period, default 70ms.
* OFF_PERIOD: Off period, default 30ms.
*/
#define MAC_CSR21 0x042a
#define MAC_CSR21_ON_PERIOD FIELD16(0x00ff)
#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00)
/*
* MAC_CSR22: Collision window control register.
*/
#define MAC_CSR22 0x042c
/*
* Transmit related CSRs.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* TXRX_CSR0: Security control register.
*/
#define TXRX_CSR0 0x0440
#define TXRX_CSR0_ALGORITHM FIELD16(0x0007)
#define TXRX_CSR0_IV_OFFSET FIELD16(0x01f8)
#define TXRX_CSR0_KEY_ID FIELD16(0x1e00)
/*
* TXRX_CSR1: TX configuration.
* ACK_TIMEOUT: ACK Timeout in unit of 1-us.
* TSF_OFFSET: TSF offset in MAC header.
* AUTO_SEQUENCE: Let ASIC control frame sequence number.
*/
#define TXRX_CSR1 0x0442
#define TXRX_CSR1_ACK_TIMEOUT FIELD16(0x00ff)
#define TXRX_CSR1_TSF_OFFSET FIELD16(0x7f00)
#define TXRX_CSR1_AUTO_SEQUENCE FIELD16(0x8000)
/*
* TXRX_CSR2: RX control.
* DISABLE_RX: Disable rx engine.
* DROP_CRC: Drop crc error.
* DROP_PHYSICAL: Drop physical error.
* DROP_CONTROL: Drop control frame.
* DROP_NOT_TO_ME: Drop not to me unicast frame.
* DROP_TODS: Drop frame tods bit is true.
* DROP_VERSION_ERROR: Drop version error frame.
* DROP_MCAST: Drop multicast frames.
* DROP_BCAST: Drop broadcast frames.
*/
#define TXRX_CSR2 0x0444
#define TXRX_CSR2_DISABLE_RX FIELD16(0x0001)
#define TXRX_CSR2_DROP_CRC FIELD16(0x0002)
#define TXRX_CSR2_DROP_PHYSICAL FIELD16(0x0004)
#define TXRX_CSR2_DROP_CONTROL FIELD16(0x0008)
#define TXRX_CSR2_DROP_NOT_TO_ME FIELD16(0x0010)
#define TXRX_CSR2_DROP_TODS FIELD16(0x0020)
#define TXRX_CSR2_DROP_VERSION_ERROR FIELD16(0x0040)
#define TXRX_CSR2_DROP_MULTICAST FIELD16(0x0200)
#define TXRX_CSR2_DROP_BROADCAST FIELD16(0x0400)
/*
* RX BBP ID registers
* TXRX_CSR3: CCK RX BBP ID.
* TXRX_CSR4: OFDM RX BBP ID.
*/
#define TXRX_CSR3 0x0446
#define TXRX_CSR4 0x0448
/*
* TXRX_CSR5: CCK TX BBP ID0.
*/
#define TXRX_CSR5 0x044a
#define TXRX_CSR5_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR5_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR5_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR5_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR6: CCK TX BBP ID1.
*/
#define TXRX_CSR6 0x044c
#define TXRX_CSR6_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR6_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR6_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR6_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR7: OFDM TX BBP ID0.
*/
#define TXRX_CSR7 0x044e
#define TXRX_CSR7_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR7_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR7_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR8: OFDM TX BBP ID1.
*/
#define TXRX_CSR8 0x0450
#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR8_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR8_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR8_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR9: TX ACK time-out.
*/
#define TXRX_CSR9 0x0452
/*
* TXRX_CSR10: Auto responder control.
*/
#define TXRX_CSR10 0x0454
#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004)
/*
* TXRX_CSR11: Auto responder basic rate.
*/
#define TXRX_CSR11 0x0456
/*
* ACK/CTS time registers.
*/
#define TXRX_CSR12 0x0458
#define TXRX_CSR13 0x045a
#define TXRX_CSR14 0x045c
#define TXRX_CSR15 0x045e
#define TXRX_CSR16 0x0460
#define TXRX_CSR17 0x0462
/*
* TXRX_CSR18: Synchronization control register.
*/
#define TXRX_CSR18 0x0464
#define TXRX_CSR18_OFFSET FIELD16(0x000f)
#define TXRX_CSR18_INTERVAL FIELD16(0xfff0)
/*
* TXRX_CSR19: Synchronization control register.
* TSF_COUNT: Enable TSF auto counting.
* TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
* TBCN: Enable Tbcn with reload value.
* BEACON_GEN: Enable beacon generator.
*/
#define TXRX_CSR19 0x0466
#define TXRX_CSR19_TSF_COUNT FIELD16(0x0001)
#define TXRX_CSR19_TSF_SYNC FIELD16(0x0006)
#define TXRX_CSR19_TBCN FIELD16(0x0008)
#define TXRX_CSR19_BEACON_GEN FIELD16(0x0010)
/*
* TXRX_CSR20: Tx BEACON offset time control register.
* OFFSET: In units of usec.
* BCN_EXPECT_WINDOW: Default: 2^CWmin
*/
#define TXRX_CSR20 0x0468
#define TXRX_CSR20_OFFSET FIELD16(0x1fff)
#define TXRX_CSR20_BCN_EXPECT_WINDOW FIELD16(0xe000)
/*
* TXRX_CSR21
*/
#define TXRX_CSR21 0x046a
/*
* Encryption related CSRs.
*
*/
/*
* SEC_CSR0: Shared key 0, word 0
* SEC_CSR1: Shared key 0, word 1
* SEC_CSR2: Shared key 0, word 2
* SEC_CSR3: Shared key 0, word 3
* SEC_CSR4: Shared key 0, word 4
* SEC_CSR5: Shared key 0, word 5
* SEC_CSR6: Shared key 0, word 6
* SEC_CSR7: Shared key 0, word 7
*/
#define SEC_CSR0 0x0480
#define SEC_CSR1 0x0482
#define SEC_CSR2 0x0484
#define SEC_CSR3 0x0486
#define SEC_CSR4 0x0488
#define SEC_CSR5 0x048a
#define SEC_CSR6 0x048c
#define SEC_CSR7 0x048e
/*
* SEC_CSR8: Shared key 1, word 0
* SEC_CSR9: Shared key 1, word 1
* SEC_CSR10: Shared key 1, word 2
* SEC_CSR11: Shared key 1, word 3
* SEC_CSR12: Shared key 1, word 4
* SEC_CSR13: Shared key 1, word 5
* SEC_CSR14: Shared key 1, word 6
* SEC_CSR15: Shared key 1, word 7
*/
#define SEC_CSR8 0x0490
#define SEC_CSR9 0x0492
#define SEC_CSR10 0x0494
#define SEC_CSR11 0x0496
#define SEC_CSR12 0x0498
#define SEC_CSR13 0x049a
#define SEC_CSR14 0x049c
#define SEC_CSR15 0x049e
/*
* SEC_CSR16: Shared key 2, word 0
* SEC_CSR17: Shared key 2, word 1
* SEC_CSR18: Shared key 2, word 2
* SEC_CSR19: Shared key 2, word 3
* SEC_CSR20: Shared key 2, word 4
* SEC_CSR21: Shared key 2, word 5
* SEC_CSR22: Shared key 2, word 6
* SEC_CSR23: Shared key 2, word 7
*/
#define SEC_CSR16 0x04a0
#define SEC_CSR17 0x04a2
#define SEC_CSR18 0X04A4
#define SEC_CSR19 0x04a6
#define SEC_CSR20 0x04a8
#define SEC_CSR21 0x04aa
#define SEC_CSR22 0x04ac
#define SEC_CSR23 0x04ae
/*
* SEC_CSR24: Shared key 3, word 0
* SEC_CSR25: Shared key 3, word 1
* SEC_CSR26: Shared key 3, word 2
* SEC_CSR27: Shared key 3, word 3
* SEC_CSR28: Shared key 3, word 4
* SEC_CSR29: Shared key 3, word 5
* SEC_CSR30: Shared key 3, word 6
* SEC_CSR31: Shared key 3, word 7
*/
#define SEC_CSR24 0x04b0
#define SEC_CSR25 0x04b2
#define SEC_CSR26 0x04b4
#define SEC_CSR27 0x04b6
#define SEC_CSR28 0x04b8
#define SEC_CSR29 0x04ba
#define SEC_CSR30 0x04bc
#define SEC_CSR31 0x04be
#define KEY_ENTRY(__idx) \
( SEC_CSR0 + ((__idx) * 16) )
/*
* PHY control registers.
*/
/*
* PHY_CSR0: RF switching timing control.
*/
#define PHY_CSR0 0x04c0
/*
* PHY_CSR1: TX PA configuration.
*/
#define PHY_CSR1 0x04c2
/*
* MAC configuration registers.
*/
/*
* PHY_CSR2: TX MAC configuration.
* NOTE: Both register fields are complete dummy,
* documentation and legacy drivers are unclear un
* what this register means or what fields exists.
*/
#define PHY_CSR2 0x04c4
#define PHY_CSR2_LNA FIELD16(0x0002)
#define PHY_CSR2_LNA_MODE FIELD16(0x3000)
/*
* PHY_CSR3: RX MAC configuration.
*/
#define PHY_CSR3 0x04c6
/*
* PHY_CSR4: Interface configuration.
*/
#define PHY_CSR4 0x04c8
#define PHY_CSR4_LOW_RF_LE FIELD16(0x0001)
/*
* BBP pre-TX registers.
* PHY_CSR5: BBP pre-TX CCK.
*/
#define PHY_CSR5 0x04ca
#define PHY_CSR5_CCK FIELD16(0x0003)
#define PHY_CSR5_CCK_FLIP FIELD16(0x0004)
/*
* BBP pre-TX registers.
* PHY_CSR6: BBP pre-TX OFDM.
*/
#define PHY_CSR6 0x04cc
#define PHY_CSR6_OFDM FIELD16(0x0003)
#define PHY_CSR6_OFDM_FLIP FIELD16(0x0004)
/*
* PHY_CSR7: BBP access register 0.
* BBP_DATA: BBP data.
* BBP_REG_ID: BBP register ID.
* BBP_READ_CONTROL: 0: write, 1: read.
*/
#define PHY_CSR7 0x04ce
#define PHY_CSR7_DATA FIELD16(0x00ff)
#define PHY_CSR7_REG_ID FIELD16(0x7f00)
#define PHY_CSR7_READ_CONTROL FIELD16(0x8000)
/*
* PHY_CSR8: BBP access register 1.
* BBP_BUSY: ASIC is busy execute BBP programming.
*/
#define PHY_CSR8 0x04d0
#define PHY_CSR8_BUSY FIELD16(0x0001)
/*
* PHY_CSR9: RF access register.
* RF_VALUE: Register value + id to program into rf/if.
*/
#define PHY_CSR9 0x04d2
#define PHY_CSR9_RF_VALUE FIELD16(0xffff)
/*
* PHY_CSR10: RF access register.
* RF_VALUE: Register value + id to program into rf/if.
* RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
* RF_IF_SELECT: Chip to program: 0: rf, 1: if.
* RF_PLL_LD: Rf pll_ld status.
* RF_BUSY: 1: asic is busy execute rf programming.
*/
#define PHY_CSR10 0x04d4
#define PHY_CSR10_RF_VALUE FIELD16(0x00ff)
#define PHY_CSR10_RF_NUMBER_OF_BITS FIELD16(0x1f00)
#define PHY_CSR10_RF_IF_SELECT FIELD16(0x2000)
#define PHY_CSR10_RF_PLL_LD FIELD16(0x4000)
#define PHY_CSR10_RF_BUSY FIELD16(0x8000)
/*
* STA_CSR0: FCS error count.
* FCS_ERROR: FCS error count, cleared when read.
*/
#define STA_CSR0 0x04e0
#define STA_CSR0_FCS_ERROR FIELD16(0xffff)
/*
* STA_CSR1: PLCP error count.
*/
#define STA_CSR1 0x04e2
/*
* STA_CSR2: LONG error count.
*/
#define STA_CSR2 0x04e4
/*
* STA_CSR3: CCA false alarm.
* FALSE_CCA_ERROR: False CCA error count, cleared when read.
*/
#define STA_CSR3 0x04e6
#define STA_CSR3_FALSE_CCA_ERROR FIELD16(0xffff)
/*
* STA_CSR4: RX FIFO overflow.
*/
#define STA_CSR4 0x04e8
/*
* STA_CSR5: Beacon sent counter.
*/
#define STA_CSR5 0x04ea
/*
* Statistics registers
*/
#define STA_CSR6 0x04ec
#define STA_CSR7 0x04ee
#define STA_CSR8 0x04f0
#define STA_CSR9 0x04f2
#define STA_CSR10 0x04f4
/*
* BBP registers.
* The wordsize of the BBP is 8 bits.
*/
/*
* R2: TX antenna control
*/
#define BBP_R2_TX_ANTENNA FIELD8(0x03)
#define BBP_R2_TX_IQ_FLIP FIELD8(0x04)
/*
* R14: RX antenna control
*/
#define BBP_R14_RX_ANTENNA FIELD8(0x03)
#define BBP_R14_RX_IQ_FLIP FIELD8(0x04)
/*
* RF registers.
*/
/*
* RF 1
*/
#define RF1_TUNER FIELD32(0x00020000)
/*
* RF 3
*/
#define RF3_TUNER FIELD32(0x00000100)
#define RF3_TXPOWER FIELD32(0x00003e00)
/*
* EEPROM contents.
*/
/*
* HW MAC address.
*/
#define EEPROM_MAC_ADDR_0 0x0002
#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
#define EEPROM_MAC_ADDR1 0x0003
#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
#define EEPROM_MAC_ADDR_2 0x0004
#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
/*
* EEPROM antenna.
* ANTENNA_NUM: Number of antenna's.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd.
* DYN_TXAGC: Dynamic TX AGC control.
* HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
* RF_TYPE: Rf_type of this adapter.
*/
#define EEPROM_ANTENNA 0x000b
#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0)
#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
/*
* EEPROM NIC config.
* CARDBUS_ACCEL: 0: enable, 1: disable.
* DYN_BBP_TUNE: 0: enable, 1: disable.
* CCK_TX_POWER: CCK TX power compensation.
*/
#define EEPROM_NIC 0x000c
#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001)
#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002)
#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c)
/*
* EEPROM geography.
* GEO: Default geography setting for device.
*/
#define EEPROM_GEOGRAPHY 0x000d
#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00)
/*
* EEPROM BBP.
*/
#define EEPROM_BBP_START 0x000e
#define EEPROM_BBP_SIZE 16
#define EEPROM_BBP_VALUE FIELD16(0x00ff)
#define EEPROM_BBP_REG_ID FIELD16(0xff00)
/*
* EEPROM TXPOWER
*/
#define EEPROM_TXPOWER_START 0x001e
#define EEPROM_TXPOWER_SIZE 7
#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
#define EEPROM_TXPOWER_2 FIELD16(0xff00)
/*
* EEPROM Tuning threshold
*/
#define EEPROM_BBPTUNE 0x0030
#define EEPROM_BBPTUNE_THRESHOLD FIELD16(0x00ff)
/*
* EEPROM BBP R24 Tuning.
*/
#define EEPROM_BBPTUNE_R24 0x0031
#define EEPROM_BBPTUNE_R24_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R24_HIGH FIELD16(0xff00)
/*
* EEPROM BBP R25 Tuning.
*/
#define EEPROM_BBPTUNE_R25 0x0032
#define EEPROM_BBPTUNE_R25_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R25_HIGH FIELD16(0xff00)
/*
* EEPROM BBP R24 Tuning.
*/
#define EEPROM_BBPTUNE_R61 0x0033
#define EEPROM_BBPTUNE_R61_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R61_HIGH FIELD16(0xff00)
/*
* EEPROM BBP VGC Tuning.
*/
#define EEPROM_BBPTUNE_VGC 0x0034
#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff)
#define EEPROM_BBPTUNE_VGCLOWER FIELD16(0xff00)
/*
* EEPROM BBP R17 Tuning.
*/
#define EEPROM_BBPTUNE_R17 0x0035
#define EEPROM_BBPTUNE_R17_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R17_HIGH FIELD16(0xff00)
/*
* RSSI <-> dBm offset calibration
*/
#define EEPROM_CALIBRATE_OFFSET 0x0036
#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff)
/*
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 5 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 4 * sizeof(__le32) )
/*
* TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
*/
/*
* Word0
*/
#define TXD_W0_PACKET_ID FIELD32(0x0000000f)
#define TXD_W0_RETRY_LIMIT FIELD32(0x000000f0)
#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
#define TXD_W0_ACK FIELD32(0x00000200)
#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
#define TXD_W0_OFDM FIELD32(0x00000800)
#define TXD_W0_NEW_SEQ FIELD32(0x00001000)
#define TXD_W0_IFS FIELD32(0x00006000)
#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
#define TXD_W0_CIPHER FIELD32(0x20000000)
#define TXD_W0_KEY_ID FIELD32(0xc0000000)
/*
* Word1
*/
#define TXD_W1_IV_OFFSET FIELD32(0x0000003f)
#define TXD_W1_AIFS FIELD32(0x000000c0)
#define TXD_W1_CWMIN FIELD32(0x00000f00)
#define TXD_W1_CWMAX FIELD32(0x0000f000)
/*
* Word2: PLCP information
*/
#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
/*
* Word3
*/
#define TXD_W3_IV FIELD32(0xffffffff)
/*
* Word4
*/
#define TXD_W4_EIV FIELD32(0xffffffff)
/*
* RX descriptor format for RX Ring.
*/
/*
* Word0
*/
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
#define RXD_W0_MULTICAST FIELD32(0x00000004)
#define RXD_W0_BROADCAST FIELD32(0x00000008)
#define RXD_W0_MY_BSS FIELD32(0x00000010)
#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
#define RXD_W0_OFDM FIELD32(0x00000040)
#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
#define RXD_W0_CIPHER FIELD32(0x00000100)
#define RXD_W0_CIPHER_ERROR FIELD32(0x00000200)
#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
/*
* Word1
*/
#define RXD_W1_RSSI FIELD32(0x000000ff)
#define RXD_W1_SIGNAL FIELD32(0x0000ff00)
/*
* Word2
*/
#define RXD_W2_IV FIELD32(0xffffffff)
/*
* Word3
*/
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
* Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
#define MAX_TXPOWER 31
#define DEFAULT_TXPOWER 24
#define TXPOWER_FROM_DEV(__txpower) \
(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
#define TXPOWER_TO_DEV(__txpower) \
clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)
#endif /* RT2500USB_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,212 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 generic configuration routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
enum nl80211_iftype type,
const u8 *mac, const u8 *bssid)
{
struct rt2x00intf_conf conf;
unsigned int flags = 0;
conf.type = type;
switch (type) {
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_WDS:
conf.sync = TSF_SYNC_BEACON;
break;
case NL80211_IFTYPE_STATION:
conf.sync = TSF_SYNC_INFRA;
break;
default:
conf.sync = TSF_SYNC_NONE;
break;
}
/*
* Note that when NULL is passed as address we will send
* 00:00:00:00:00 to the device to clear the address.
* This will prevent the device being confused when it wants
* to ACK frames or consideres itself associated.
*/
memset(&conf.mac, 0, sizeof(conf.mac));
if (mac)
memcpy(&conf.mac, mac, ETH_ALEN);
memset(&conf.bssid, 0, sizeof(conf.bssid));
if (bssid)
memcpy(&conf.bssid, bssid, ETH_ALEN);
flags |= CONFIG_UPDATE_TYPE;
if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
flags |= CONFIG_UPDATE_MAC;
if (bssid || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
flags |= CONFIG_UPDATE_BSSID;
rt2x00dev->ops->lib->config_intf(rt2x00dev, intf, &conf, flags);
}
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *bss_conf)
{
struct rt2x00lib_erp erp;
memset(&erp, 0, sizeof(erp));
erp.short_preamble = bss_conf->use_short_preamble;
erp.cts_protection = bss_conf->use_cts_prot;
erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
erp.sifs = SIFS;
erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
erp.basic_rates = bss_conf->basic_rates;
erp.beacon_int = bss_conf->beacon_int;
/* Update global beacon interval time, this is needed for PS support */
rt2x00dev->beacon_int = bss_conf->beacon_int;
rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
}
static inline
enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
enum antenna default_ant)
{
if (current_ant != ANTENNA_SW_DIVERSITY)
return current_ant;
return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B;
}
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup config)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup *def = &rt2x00dev->default_ant;
struct antenna_setup *active = &rt2x00dev->link.ant.active;
/*
* Failsafe: Make sure we are not sending the
* ANTENNA_SW_DIVERSITY state to the driver.
* If that happens, fallback to hardware defaults,
* or our own default.
* If diversity handling is active for a particular antenna,
* we shouldn't overwrite that antenna.
* The calls to rt2x00lib_config_antenna_check()
* might have caused that we restore back to the already
* active setting. If that has happened we can quit.
*/
if (!(ant->flags & ANTENNA_RX_DIVERSITY))
config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
else
config.rx = active->rx;
if (!(ant->flags & ANTENNA_TX_DIVERSITY))
config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx);
else
config.tx = active->tx;
if (config.rx == active->rx && config.tx == active->tx)
return;
/*
* Antenna setup changes require the RX to be disabled,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
/*
* Write new antenna setup to device and reset the link tuner.
* The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup.
*/
rt2x00dev->ops->lib->config_ant(rt2x00dev, &config);
rt2x00link_reset_tuner(rt2x00dev, true);
memcpy(active, &config, sizeof(config));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
}
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
unsigned int ieee80211_flags)
{
struct rt2x00lib_conf libconf;
memset(&libconf, 0, sizeof(libconf));
libconf.conf = conf;
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
if (conf_is_ht40(conf))
__set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
else
__clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
memcpy(&libconf.rf,
&rt2x00dev->spec.channels[conf->channel->hw_value],
sizeof(libconf.rf));
memcpy(&libconf.channel,
&rt2x00dev->spec.channels_info[conf->channel->hw_value],
sizeof(libconf.channel));
}
/*
* Start configuration.
*/
rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
/*
* Some configuration changes affect the link quality
* which means we need to reset the link tuner.
*/
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2x00link_reset_tuner(rt2x00dev, false);
rt2x00dev->curr_band = conf->channel->band;
rt2x00dev->tx_power = conf->power_level;
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
rt2x00dev->rx_status.band = conf->channel->band;
rt2x00dev->rx_status.freq = conf->channel->center_freq;
}

View File

@@ -0,0 +1,258 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 crypto specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
{
switch (key->alg) {
case ALG_WEP:
if (key->keylen == WLAN_KEY_LEN_WEP40)
return CIPHER_WEP64;
else
return CIPHER_WEP128;
case ALG_TKIP:
return CIPHER_TKIP;
case ALG_CCMP:
return CIPHER_AES;
default:
return CIPHER_NONE;
}
}
void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
__set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
txdesc->key_idx = hw_key->hw_key_idx;
txdesc->iv_offset = txdesc->header_length;
txdesc->iv_len = hw_key->iv_len;
if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
__set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
__set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
}
unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
return overhead;
/*
* Extend frame length to include IV/EIV/ICV/MMIC,
* note that these lengths should only be added when
* mac80211 does not generate it.
*/
overhead += key->icv_len;
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
overhead += key->iv_len;
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
if (key->alg == ALG_TKIP)
overhead += 8;
}
return overhead;
}
void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (unlikely(!txdesc->iv_len))
return;
/* Copy IV/EIV data */
memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
}
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (unlikely(!txdesc->iv_len))
return;
/* Copy IV/EIV data */
memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
/* Move ieee80211 header */
memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset);
/* Pull buffer to correct size */
skb_pull(skb, txdesc->iv_len);
/* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;
}
void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
const unsigned int iv_len =
((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
if (!(skbdesc->flags & SKBDESC_IV_STRIPPED))
return;
skb_push(skb, iv_len);
/* Move ieee80211 header */
memmove(skb->data, skb->data + iv_len, header_length);
/* Copy IV/EIV data */
memcpy(skb->data + header_length, skbdesc->iv, iv_len);
/* IV/EIV data has returned into the frame */
skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
}
void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc)
{
unsigned int payload_len = rxdesc->size - header_length;
unsigned int align = ALIGN_SIZE(skb, header_length);
unsigned int iv_len;
unsigned int icv_len;
unsigned int transfer = 0;
/*
* WEP64/WEP128: Provides IV & ICV
* TKIP: Provides IV/EIV & ICV
* AES: Provies IV/EIV & ICV
*/
switch (rxdesc->cipher) {
case CIPHER_WEP64:
case CIPHER_WEP128:
iv_len = 4;
icv_len = 4;
break;
case CIPHER_TKIP:
iv_len = 8;
icv_len = 4;
break;
case CIPHER_AES:
iv_len = 8;
icv_len = 8;
break;
default:
/* Unsupport type */
return;
}
/*
* Make room for new data. There are 2 possibilities
* either the alignment is already present between
* the 802.11 header and payload. In that case we
* we have to move the header less then the iv_len
* since we can use the already available l2pad bytes
* for the iv data.
* When the alignment must be added manually we must
* move the header more then iv_len since we must
* make room for the payload move as well.
*/
if (rxdesc->dev_flags & RXDONE_L2PAD) {
skb_push(skb, iv_len - align);
skb_put(skb, icv_len);
/* Move ieee80211 header */
memmove(skb->data + transfer,
skb->data + transfer + (iv_len - align),
header_length);
transfer += header_length;
} else {
skb_push(skb, iv_len + align);
if (align < icv_len)
skb_put(skb, icv_len - align);
else if (align > icv_len)
skb_trim(skb, rxdesc->size + iv_len + icv_len);
/* Move ieee80211 header */
memmove(skb->data + transfer,
skb->data + transfer + iv_len + align,
header_length);
transfer += header_length;
}
/* Copy IV/EIV data */
memcpy(skb->data + transfer, rxdesc->iv, iv_len);
transfer += iv_len;
/*
* Move payload for alignment purposes. Note that
* this is only needed when no l2 padding is present.
*/
if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
memmove(skb->data + transfer,
skb->data + transfer + align,
payload_len);
}
/*
* NOTE: Always count the payload as transfered,
* even when alignment was set to zero. This is required
* for determining the correct offset for the ICV data.
*/
transfer += payload_len;
/*
* Copy ICV data
* AES appends 8 bytes, we can't fill the upper
* 4 bytes, but mac80211 doesn't care about what
* we provide here anyway and strips it immediately.
*/
memcpy(skb->data + transfer, &rxdesc->icv, 4);
transfer += icv_len;
/* IV/EIV/ICV has been inserted into frame */
rxdesc->size = transfer;
rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
}

View File

@@ -0,0 +1,739 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 debugfs specific routines.
*/
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
#include "rt2x00dump.h"
#define MAX_LINE_LENGTH 64
struct rt2x00debug_crypto {
unsigned long success;
unsigned long icv_error;
unsigned long mic_error;
unsigned long key_error;
};
struct rt2x00debug_intf {
/*
* Pointer to driver structure where
* this debugfs entry belongs to.
*/
struct rt2x00_dev *rt2x00dev;
/*
* Reference to the rt2x00debug structure
* which can be used to communicate with
* the registers.
*/
const struct rt2x00debug *debug;
/*
* Debugfs entries for:
* - driver folder
* - driver file
* - chipset file
* - device flags file
* - register folder
* - csr offset/value files
* - eeprom offset/value files
* - bbp offset/value files
* - rf offset/value files
* - queue folder
* - frame dump file
* - queue stats file
* - crypto stats file
*/
struct dentry *driver_folder;
struct dentry *driver_entry;
struct dentry *chipset_entry;
struct dentry *dev_flags;
struct dentry *register_folder;
struct dentry *csr_off_entry;
struct dentry *csr_val_entry;
struct dentry *eeprom_off_entry;
struct dentry *eeprom_val_entry;
struct dentry *bbp_off_entry;
struct dentry *bbp_val_entry;
struct dentry *rf_off_entry;
struct dentry *rf_val_entry;
struct dentry *queue_folder;
struct dentry *queue_frame_dump_entry;
struct dentry *queue_stats_entry;
struct dentry *crypto_stats_entry;
/*
* The frame dump file only allows a single reader,
* so we need to store the current state here.
*/
unsigned long frame_dump_flags;
#define FRAME_DUMP_FILE_OPEN 1
/*
* We queue each frame before dumping it to the user,
* per read command we will pass a single skb structure
* so we should be prepared to queue multiple sk buffers
* before sending it to userspace.
*/
struct sk_buff_head frame_dump_skbqueue;
wait_queue_head_t frame_dump_waitqueue;
/*
* HW crypto statistics.
* All statistics are stored seperately per cipher type.
*/
struct rt2x00debug_crypto crypto_stats[CIPHER_MAX];
/*
* Driver and chipset files will use a data buffer
* that has been created in advance. This will simplify
* the code since we can use the debugfs functions.
*/
struct debugfs_blob_wrapper driver_blob;
struct debugfs_blob_wrapper chipset_blob;
/*
* Requested offset for each register type.
*/
unsigned int offset_csr;
unsigned int offset_eeprom;
unsigned int offset_bbp;
unsigned int offset_rf;
};
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
enum cipher cipher = rxdesc->cipher;
enum rx_crypto status = rxdesc->cipher_status;
if (cipher == CIPHER_TKIP_NO_MIC)
cipher = CIPHER_TKIP;
if (cipher == CIPHER_NONE || cipher >= CIPHER_MAX)
return;
/* Remove CIPHER_NONE index */
cipher--;
intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS);
intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV);
intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC);
intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY);
}
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct sk_buff *skb)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
struct skb_frame_desc *desc = get_skb_frame_desc(skb);
struct sk_buff *skbcopy;
struct rt2x00dump_hdr *dump_hdr;
struct timeval timestamp;
do_gettimeofday(&timestamp);
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
return;
if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n");
return;
}
skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + skb->len,
GFP_ATOMIC);
if (!skbcopy) {
DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
return;
}
dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr));
dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
dump_hdr->desc_length = cpu_to_le32(desc->desc_len);
dump_hdr->data_length = cpu_to_le32(skb->len);
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(type);
dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx;
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len);
memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len);
skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
wake_up_interruptible(&intf->frame_dump_waitqueue);
/*
* Verify that the file has not been closed while we were working.
*/
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
skb_queue_purge(&intf->frame_dump_skbqueue);
}
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
file->private_data = inode->i_private;
if (!try_module_get(intf->debug->owner))
return -EBUSY;
return 0;
}
static int rt2x00debug_file_release(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = file->private_data;
module_put(intf->debug->owner);
return 0;
}
static int rt2x00debug_open_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
int retval;
retval = rt2x00debug_file_open(inode, file);
if (retval)
return retval;
if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) {
rt2x00debug_file_release(inode, file);
return -EBUSY;
}
return 0;
}
static int rt2x00debug_release_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
skb_queue_purge(&intf->frame_dump_skbqueue);
clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags);
return rt2x00debug_file_release(inode, file);
}
static ssize_t rt2x00debug_read_queue_dump(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct sk_buff *skb;
size_t status;
int retval;
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
retval =
wait_event_interruptible(intf->frame_dump_waitqueue,
(skb =
skb_dequeue(&intf->frame_dump_skbqueue)));
if (retval)
return retval;
status = min((size_t)skb->len, length);
if (copy_to_user(buf, skb->data, status)) {
status = -EFAULT;
goto exit;
}
*offset += status;
exit:
kfree_skb(skb);
return status;
}
static unsigned int rt2x00debug_poll_queue_dump(struct file *file,
poll_table *wait)
{
struct rt2x00debug_intf *intf = file->private_data;
poll_wait(file, &intf->frame_dump_waitqueue, wait);
if (!skb_queue_empty(&intf->frame_dump_skbqueue))
return POLLOUT | POLLWRNORM;
return 0;
}
static const struct file_operations rt2x00debug_fop_queue_dump = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_queue_dump,
.poll = rt2x00debug_poll_queue_dump,
.open = rt2x00debug_open_queue_dump,
.release = rt2x00debug_release_queue_dump,
};
static ssize_t rt2x00debug_read_queue_stats(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct data_queue *queue;
unsigned long irqflags;
unsigned int lines = 1 + intf->rt2x00dev->data_queues;
size_t size;
char *data;
char *temp;
if (*offset)
return 0;
data = kzalloc(lines * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return -ENOMEM;
temp = data +
sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n");
queue_for_each(intf->rt2x00dev, queue) {
spin_lock_irqsave(&queue->lock, irqflags);
temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
queue->index[Q_INDEX_DONE],
queue->index[Q_INDEX_CRYPTO]);
spin_unlock_irqrestore(&queue->lock, irqflags);
}
size = strlen(data);
size = min(size, length);
if (copy_to_user(buf, data, size)) {
kfree(data);
return -EFAULT;
}
kfree(data);
*offset += size;
return size;
}
static const struct file_operations rt2x00debug_fop_queue_stats = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_queue_stats,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
};
#ifdef CONFIG_RT2X00_LIB_CRYPTO
static ssize_t rt2x00debug_read_crypto_stats(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
char *name[] = { "WEP64", "WEP128", "TKIP", "AES" };
char *data;
char *temp;
size_t size;
unsigned int i;
if (*offset)
return 0;
data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return -ENOMEM;
temp = data;
temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n");
for (i = 0; i < CIPHER_MAX; i++) {
temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i],
intf->crypto_stats[i].success,
intf->crypto_stats[i].icv_error,
intf->crypto_stats[i].mic_error,
intf->crypto_stats[i].key_error);
}
size = strlen(data);
size = min(size, length);
if (copy_to_user(buf, data, size)) {
kfree(data);
return -EFAULT;
}
kfree(data);
*offset += size;
return size;
}
static const struct file_operations rt2x00debug_fop_crypto_stats = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_crypto_stats,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
};
#endif
#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
static ssize_t rt2x00debug_read_##__name(struct file *file, \
char __user *buf, \
size_t length, \
loff_t *offset) \
{ \
struct rt2x00debug_intf *intf = file->private_data; \
const struct rt2x00debug *debug = intf->debug; \
char line[16]; \
size_t size; \
unsigned int index = intf->offset_##__name; \
__type value; \
\
if (*offset) \
return 0; \
\
if (index >= debug->__name.word_count) \
return -EINVAL; \
\
index += (debug->__name.word_base / \
debug->__name.word_size); \
\
if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \
index *= debug->__name.word_size; \
\
debug->__name.read(intf->rt2x00dev, index, &value); \
\
size = sprintf(line, __format, value); \
\
if (copy_to_user(buf, line, size)) \
return -EFAULT; \
\
*offset += size; \
return size; \
}
#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
static ssize_t rt2x00debug_write_##__name(struct file *file, \
const char __user *buf,\
size_t length, \
loff_t *offset) \
{ \
struct rt2x00debug_intf *intf = file->private_data; \
const struct rt2x00debug *debug = intf->debug; \
char line[16]; \
size_t size; \
unsigned int index = intf->offset_##__name; \
__type value; \
\
if (*offset) \
return 0; \
\
if (index >= debug->__name.word_count) \
return -EINVAL; \
\
if (copy_from_user(line, buf, length)) \
return -EFAULT; \
\
size = strlen(line); \
value = simple_strtoul(line, NULL, 0); \
\
index += (debug->__name.word_base / \
debug->__name.word_size); \
\
if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \
index *= debug->__name.word_size; \
\
debug->__name.write(intf->rt2x00dev, index, value); \
\
*offset += size; \
return size; \
}
#define RT2X00DEBUGFS_OPS(__name, __format, __type) \
RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \
RT2X00DEBUGFS_OPS_WRITE(__name, __type); \
\
static const struct file_operations rt2x00debug_fop_##__name = {\
.owner = THIS_MODULE, \
.read = rt2x00debug_read_##__name, \
.write = rt2x00debug_write_##__name, \
.open = rt2x00debug_file_open, \
.release = rt2x00debug_file_release, \
};
RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
static ssize_t rt2x00debug_read_dev_flags(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
char line[16];
size_t size;
if (*offset)
return 0;
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
if (copy_to_user(buf, line, size))
return -EFAULT;
*offset += size;
return size;
}
static const struct file_operations rt2x00debug_fop_dev_flags = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_dev_flags,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
};
static struct dentry *rt2x00debug_create_file_driver(const char *name,
struct rt2x00debug_intf
*intf,
struct debugfs_blob_wrapper
*blob)
{
char *data;
data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return NULL;
blob->data = data;
data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);
data += sprintf(data, "version:\t%s\n", DRV_VERSION);
data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__);
blob->size = strlen(blob->data);
return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
}
static struct dentry *rt2x00debug_create_file_chipset(const char *name,
struct rt2x00debug_intf
*intf,
struct
debugfs_blob_wrapper
*blob)
{
const struct rt2x00debug *debug = intf->debug;
char *data;
data = kzalloc(8 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return NULL;
blob->data = data;
data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);
data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf);
data += sprintf(data, "revision:\t%08x\n", intf->rt2x00dev->chip.rev);
data += sprintf(data, "\n");
data += sprintf(data, "register\tbase\twords\twordsize\n");
data += sprintf(data, "csr\t%d\t%d\t%d\n",
debug->csr.word_base,
debug->csr.word_count,
debug->csr.word_size);
data += sprintf(data, "eeprom\t%d\t%d\t%d\n",
debug->eeprom.word_base,
debug->eeprom.word_count,
debug->eeprom.word_size);
data += sprintf(data, "bbp\t%d\t%d\t%d\n",
debug->bbp.word_base,
debug->bbp.word_count,
debug->bbp.word_size);
data += sprintf(data, "rf\t%d\t%d\t%d\n",
debug->rf.word_base,
debug->rf.word_count,
debug->rf.word_size);
blob->size = strlen(blob->data);
return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
}
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
struct rt2x00debug_intf *intf;
intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
if (!intf) {
ERROR(rt2x00dev, "Failed to allocate debug handler.\n");
return;
}
intf->debug = debug;
intf->rt2x00dev = rt2x00dev;
rt2x00dev->debugfs_intf = intf;
intf->driver_folder =
debugfs_create_dir(intf->rt2x00dev->ops->name,
rt2x00dev->hw->wiphy->debugfsdir);
if (IS_ERR(intf->driver_folder) || !intf->driver_folder)
goto exit;
intf->driver_entry =
rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
if (IS_ERR(intf->driver_entry) || !intf->driver_entry)
goto exit;
intf->chipset_entry =
rt2x00debug_create_file_chipset("chipset",
intf, &intf->chipset_blob);
if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry)
goto exit;
intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR,
intf->driver_folder, intf,
&rt2x00debug_fop_dev_flags);
if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
goto exit;
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
if (IS_ERR(intf->register_folder) || !intf->register_folder)
goto exit;
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
({ \
(__intf)->__name##_off_entry = \
debugfs_create_u32(__stringify(__name) "_offset", \
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
&(__intf)->offset_##__name); \
if (IS_ERR((__intf)->__name##_off_entry) \
|| !(__intf)->__name##_off_entry) \
goto exit; \
\
(__intf)->__name##_val_entry = \
debugfs_create_file(__stringify(__name) "_value", \
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
(__intf), &rt2x00debug_fop_##__name);\
if (IS_ERR((__intf)->__name##_val_entry) \
|| !(__intf)->__name##_val_entry) \
goto exit; \
})
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf);
#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
intf->queue_folder =
debugfs_create_dir("queue", intf->driver_folder);
if (IS_ERR(intf->queue_folder) || !intf->queue_folder)
goto exit;
intf->queue_frame_dump_entry =
debugfs_create_file("dump", S_IRUSR, intf->queue_folder,
intf, &rt2x00debug_fop_queue_dump);
if (IS_ERR(intf->queue_frame_dump_entry)
|| !intf->queue_frame_dump_entry)
goto exit;
skb_queue_head_init(&intf->frame_dump_skbqueue);
init_waitqueue_head(&intf->frame_dump_waitqueue);
intf->queue_stats_entry =
debugfs_create_file("queue", S_IRUSR, intf->queue_folder,
intf, &rt2x00debug_fop_queue_stats);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
intf->crypto_stats_entry =
debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
intf, &rt2x00debug_fop_crypto_stats);
#endif
return;
exit:
rt2x00debug_deregister(rt2x00dev);
ERROR(rt2x00dev, "Failed to register debug handler.\n");
return;
}
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
if (unlikely(!intf))
return;
skb_queue_purge(&intf->frame_dump_skbqueue);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
debugfs_remove(intf->crypto_stats_entry);
#endif
debugfs_remove(intf->queue_stats_entry);
debugfs_remove(intf->queue_frame_dump_entry);
debugfs_remove(intf->queue_folder);
debugfs_remove(intf->rf_val_entry);
debugfs_remove(intf->rf_off_entry);
debugfs_remove(intf->bbp_val_entry);
debugfs_remove(intf->bbp_off_entry);
debugfs_remove(intf->eeprom_val_entry);
debugfs_remove(intf->eeprom_off_entry);
debugfs_remove(intf->csr_val_entry);
debugfs_remove(intf->csr_off_entry);
debugfs_remove(intf->register_folder);
debugfs_remove(intf->dev_flags);
debugfs_remove(intf->chipset_entry);
debugfs_remove(intf->driver_entry);
debugfs_remove(intf->driver_folder);
kfree(intf->chipset_blob.data);
kfree(intf->driver_blob.data);
kfree(intf);
rt2x00dev->debugfs_intf = NULL;
}

View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00debug
Abstract: Data structures for the rt2x00debug.
*/
#ifndef RT2X00DEBUG_H
#define RT2X00DEBUG_H
struct rt2x00_dev;
/**
* enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry
*
* @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset
* as argument when using the callback function read()/write()
*/
enum rt2x00debugfs_entry_flags {
RT2X00DEBUGFS_OFFSET = (1 << 0),
};
#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \
struct reg##__name { \
void (*read)(struct rt2x00_dev *rt2x00dev, \
const unsigned int word, __type *data); \
void (*write)(struct rt2x00_dev *rt2x00dev, \
const unsigned int word, __type data); \
\
unsigned int flags; \
\
unsigned int word_base; \
unsigned int word_size; \
unsigned int word_count; \
} __name
struct rt2x00debug {
/*
* Reference to the modules structure.
*/
struct module *owner;
/*
* Register access entries.
*/
RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32);
RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
};
#endif /* RT2X00DEBUG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00dump
Abstract: Data structures for the rt2x00debug & userspace.
*/
#ifndef RT2X00DUMP_H
#define RT2X00DUMP_H
/**
* DOC: Introduction
*
* This header is intended to be exported to userspace,
* to make the structures and enumerations available to userspace
* applications. This means that all data types should be exportable.
*
* When rt2x00 is compiled with debugfs support enabled,
* it is possible to capture all data coming in and out of the device
* by reading the frame dump file. This file can have only a single reader.
* The following frames will be reported:
* - All incoming frames (rx)
* - All outgoing frames (tx, including beacon and atim)
* - All completed frames (txdone including atim)
*
* The data is send to the file using the following format:
*
* [rt2x00dump header][hardware descriptor][ieee802.11 frame]
*
* rt2x00dump header: The description of the dumped frame, as well as
* additional information usefull for debugging. See &rt2x00dump_hdr.
* hardware descriptor: Descriptor that was used to receive or transmit
* the frame.
* ieee802.11 frame: The actual frame that was received or transmitted.
*/
/**
* enum rt2x00_dump_type - Frame type
*
* These values are used for the @type member of &rt2x00dump_hdr.
* @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
* @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
* @DUMP_FRAME_TXDONE: This frame indicates the device has handled
* the tx event which has either succeeded or failed. A frame
* with this type should also have been reported with as a
* %DUMP_FRAME_TX frame.
*/
enum rt2x00_dump_type {
DUMP_FRAME_RXDONE = 1,
DUMP_FRAME_TX = 2,
DUMP_FRAME_TXDONE = 3,
};
/**
* struct rt2x00dump_hdr - Dump frame header
*
* Each frame dumped to the debugfs file starts with this header
* attached. This header contains the description of the actual
* frame which was dumped.
*
* New fields inside the structure must be appended to the end of
* the structure. This way userspace tools compiled for earlier
* header versions can still correctly handle the frame dump
* (although they will not handle all data passed to them in the dump).
*
* @version: Header version should always be set to %DUMP_HEADER_VERSION.
* This field must be checked by userspace to determine if it can
* handle this frame.
* @header_length: The length of the &rt2x00dump_hdr structure. This is
* used for compatibility reasons so userspace can easily determine
* the location of the next field in the dump.
* @desc_length: The length of the device descriptor.
* @data_length: The length of the frame data (including the ieee802.11 header.
* @chip_rt: RT chipset
* @chip_rf: RF chipset
* @chip_rev: Chipset revision
* @type: The frame type (&rt2x00_dump_type)
* @queue_index: The index number of the data queue.
* @entry_index: The index number of the entry inside the data queue.
* @timestamp_sec: Timestamp - seconds
* @timestamp_usec: Timestamp - microseconds
*/
struct rt2x00dump_hdr {
__le32 version;
#define DUMP_HEADER_VERSION 2
__le32 header_length;
__le32 desc_length;
__le32 data_length;
__le16 chip_rt;
__le16 chip_rf;
__le32 chip_rev;
__le16 type;
__u8 queue_index;
__u8 entry_index;
__le32 timestamp_sec;
__le32 timestamp_usec;
};
#endif /* RT2X00DUMP_H */

View File

@@ -0,0 +1,127 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 firmware loading routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
{
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
const struct firmware *fw;
char *fw_name;
int retval;
/*
* Read correct firmware from harddisk.
*/
fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
if (!fw_name) {
ERROR(rt2x00dev,
"Invalid firmware filename.\n"
"Please file bug report to %s.\n", DRV_PROJECT);
return -EINVAL;
}
INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name);
retval = request_firmware(&fw, fw_name, device);
if (retval) {
ERROR(rt2x00dev, "Failed to request Firmware.\n");
return retval;
}
if (!fw || !fw->size || !fw->data) {
ERROR(rt2x00dev, "Failed to read Firmware.\n");
return -ENOENT;
}
INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
fw->data[fw->size - 4], fw->data[fw->size - 3]);
retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size);
switch (retval) {
case FW_OK:
break;
case FW_BAD_CRC:
ERROR(rt2x00dev, "Firmware checksum error.\n");
goto exit;
case FW_BAD_LENGTH:
ERROR(rt2x00dev,
"Invalid firmware file length (len=%zu)\n", fw->size);
goto exit;
case FW_BAD_VERSION:
ERROR(rt2x00dev,
"Current firmware does not support detected chipset.\n");
goto exit;
};
rt2x00dev->fw = fw;
return 0;
exit:
release_firmware(fw);
return -ENOENT;
}
int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
int retval;
if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags))
return 0;
if (!rt2x00dev->fw) {
retval = rt2x00lib_request_firmware(rt2x00dev);
if (retval)
return retval;
}
/*
* Send firmware to the device.
*/
retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
rt2x00dev->fw->data,
rt2x00dev->fw->size);
/*
* When the firmware is uploaded to the hardware the LED
* association status might have been triggered, for correct
* LED handling it should now be reset.
*/
rt2x00leds_led_assoc(rt2x00dev, false);
return retval;
}
void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
{
release_firmware(rt2x00dev->fw);
rt2x00dev->fw = NULL;
}

View File

@@ -0,0 +1,69 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 HT specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
if (tx_info->control.sta)
txdesc->mpdu_density =
tx_info->control.sta->ht_cap.ampdu_density;
else
txdesc->mpdu_density = 0;
txdesc->ba_size = 7; /* FIXME: What value is needed? */
txdesc->stbc = 0; /* FIXME: What value is needed? */
txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
txdesc->mcs |= 0x08;
/*
* Convert flags
*/
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
__set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
/*
* Determine HT Mix/Greenfield rate mode
*/
if (txrate->flags & IEEE80211_TX_RC_MCS)
txdesc->rate_mode = RATE_MODE_HT_MIX;
if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
txdesc->rate_mode = RATE_MODE_HT_GREENFIELD;
if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
}

View File

@@ -0,0 +1,246 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 led specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
{
struct rt2x00_led *led = &rt2x00dev->led_qual;
unsigned int brightness;
if ((led->type != LED_TYPE_QUALITY) || !(led->flags & LED_REGISTERED))
return;
/*
* Led handling requires a positive value for the rssi,
* to do that correctly we need to add the correction.
*/
rssi += rt2x00dev->rssi_offset;
/*
* Get the rssi level, this is used to convert the rssi
* to a LED value inside the range LED_OFF - LED_FULL.
*/
if (rssi <= 30)
rssi = 0;
else if (rssi <= 39)
rssi = 1;
else if (rssi <= 49)
rssi = 2;
else if (rssi <= 53)
rssi = 3;
else if (rssi <= 63)
rssi = 4;
else
rssi = 5;
/*
* Note that we must _not_ send LED_OFF since the driver
* is going to calculate the value and might use it in a
* division.
*/
brightness = ((LED_FULL / 6) * rssi) + 1;
if (brightness != led->led_dev.brightness) {
led->led_dev.brightness_set(&led->led_dev, brightness);
led->led_dev.brightness = brightness;
}
}
static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled)
{
unsigned int brightness = enabled ? LED_FULL : LED_OFF;
if (!(led->flags & LED_REGISTERED))
return;
led->led_dev.brightness_set(&led->led_dev, brightness);
led->led_dev.brightness = brightness;
}
void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
{
if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY)
rt2x00led_led_simple(&rt2x00dev->led_qual, enabled);
}
void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
{
if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC)
rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled);
}
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled)
{
if (rt2x00dev->led_radio.type == LED_TYPE_RADIO)
rt2x00led_led_simple(&rt2x00dev->led_radio, enabled);
}
static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
struct rt2x00_led *led,
const char *name)
{
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
int retval;
led->led_dev.name = name;
led->led_dev.brightness = LED_OFF;
retval = led_classdev_register(device, &led->led_dev);
if (retval) {
ERROR(rt2x00dev, "Failed to register led handler.\n");
return retval;
}
led->flags |= LED_REGISTERED;
return 0;
}
void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
{
char dev_name[16];
char name[32];
int retval;
unsigned long on_period;
unsigned long off_period;
snprintf(dev_name, sizeof(dev_name), "%s-%s",
rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy));
if (rt2x00dev->led_radio.flags & LED_INITIALIZED) {
snprintf(name, sizeof(name), "%s::radio", dev_name);
retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_radio,
name);
if (retval)
goto exit_fail;
}
if (rt2x00dev->led_assoc.flags & LED_INITIALIZED) {
snprintf(name, sizeof(name), "%s::assoc", dev_name);
retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_assoc,
name);
if (retval)
goto exit_fail;
}
if (rt2x00dev->led_qual.flags & LED_INITIALIZED) {
snprintf(name, sizeof(name), "%s::quality", dev_name);
retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_qual,
name);
if (retval)
goto exit_fail;
}
/*
* Initialize blink time to default value:
* On period: 70ms
* Off period: 30ms
*/
if (rt2x00dev->led_radio.led_dev.blink_set) {
on_period = 70;
off_period = 30;
rt2x00dev->led_radio.led_dev.blink_set(
&rt2x00dev->led_radio.led_dev, &on_period, &off_period);
}
return;
exit_fail:
rt2x00leds_unregister(rt2x00dev);
}
static void rt2x00leds_unregister_led(struct rt2x00_led *led)
{
led_classdev_unregister(&led->led_dev);
/*
* This might look weird, but when we are unregistering while
* suspended the led is already off, and since we haven't
* fully resumed yet, access to the device might not be
* possible yet.
*/
if (!(led->led_dev.flags & LED_SUSPENDED))
led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->flags &= ~LED_REGISTERED;
}
void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
rt2x00leds_unregister_led(&rt2x00dev->led_qual);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
rt2x00leds_unregister_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
rt2x00leds_unregister_led(&rt2x00dev->led_radio);
}
static inline void rt2x00leds_suspend_led(struct rt2x00_led *led)
{
led_classdev_suspend(&led->led_dev);
/* This shouldn't be needed, but just to be safe */
led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->led_dev.brightness = LED_OFF;
}
void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
rt2x00leds_suspend_led(&rt2x00dev->led_qual);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
rt2x00leds_suspend_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
rt2x00leds_suspend_led(&rt2x00dev->led_radio);
}
static inline void rt2x00leds_resume_led(struct rt2x00_led *led)
{
led_classdev_resume(&led->led_dev);
/* Device might have enabled the LEDS during resume */
led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->led_dev.brightness = LED_OFF;
}
void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
rt2x00leds_resume_led(&rt2x00dev->led_radio);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
rt2x00leds_resume_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
rt2x00leds_resume_led(&rt2x00dev->led_qual);
}

View File

@@ -0,0 +1,50 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 led datastructures and routines
*/
#ifndef RT2X00LEDS_H
#define RT2X00LEDS_H
enum led_type {
LED_TYPE_RADIO,
LED_TYPE_ASSOC,
LED_TYPE_ACTIVITY,
LED_TYPE_QUALITY,
};
#ifdef CONFIG_RT2X00_LIB_LEDS
struct rt2x00_led {
struct rt2x00_dev *rt2x00dev;
struct led_classdev led_dev;
enum led_type type;
unsigned int flags;
#define LED_INITIALIZED ( 1 << 0 )
#define LED_REGISTERED ( 1 << 1 )
};
#endif /* CONFIG_RT2X00_LIB_LEDS */
#endif /* RT2X00LEDS_H */

View File

@@ -0,0 +1,470 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: Data structures and definitions for the rt2x00lib module.
*/
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
#include "rt2x00dump.h"
/*
* Interval defines
*/
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
/*
* rt2x00_rate: Per rate device information
*/
struct rt2x00_rate {
unsigned short flags;
#define DEV_RATE_CCK 0x0001
#define DEV_RATE_OFDM 0x0002
#define DEV_RATE_SHORT_PREAMBLE 0x0004
unsigned short bitrate; /* In 100kbit/s */
unsigned short ratemask;
unsigned short plcp;
unsigned short mcs;
};
extern const struct rt2x00_rate rt2x00_supported_rates[12];
static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value)
{
return &rt2x00_supported_rates[hw_value & 0xff];
}
#define RATE_MCS(__mode, __mcs) \
( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) )
static inline int rt2x00_get_rate_mcs(const u16 mcs_value)
{
return (mcs_value & 0x00ff);
}
/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state);
/*
* Initialization handlers.
*/
int rt2x00lib_start(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev);
/*
* Configuration handlers.
*/
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
enum nl80211_iftype type,
const u8 *mac, const u8 *bssid);
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *conf);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
const unsigned int changed_flags);
/**
* DOC: Queue handlers
*/
/**
* rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: The queue for which the skb will be applicable.
*/
struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to unmap.
*/
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
* rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free.
*/
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
* rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary
* @skb: The skb to align
*
* Align the start of the 802.11 frame to a 4-byte boundary, this could
* mean the payload is not aligned properly though.
*/
void rt2x00queue_align_frame(struct sk_buff *skb);
/**
* rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
* @skb: The skb to align
* @header_length: Length of 802.11 header
*
* Align the 802.11 payload to a 4-byte boundary, this could
* mean the header is not aligned properly though.
*/
void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length);
/**
* rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
* @skb: The skb to align
* @header_length: Length of 802.11 header
*
* Apply L2 padding to align both header and payload to 4-byte boundary
*/
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length);
/**
* rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame
* @skb: The skb to align
* @header_length: Length of 802.11 header
*
* Remove L2 padding used to align both header and payload to 4-byte boundary,
* by removing the L2 padding the header will no longer be 4-byte aligned.
*/
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
/**
* rt2x00queue_write_tx_frame - Write TX frame to hardware
* @queue: Queue over which the frame should be send
* @skb: The skb to send
*/
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
/**
* rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @vif: Interface for which the beacon should be updated.
* @enable_beacon: Enable beaconing
*/
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif,
const bool enable_beacon);
/**
* rt2x00queue_index_inc - Index incrementation function
* @queue: Queue (&struct data_queue) to perform the action on.
* @index: Index type (&enum queue_index) to perform the action on.
*
* This function will increase the requested index on the queue,
* it will grab the appropriate locks and handle queue overflow events by
* resetting the index to the start of the queue.
*/
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
/**
* rt2x00queue_stop_queues - Halt all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* This function will loop through all available queues to stop
* any pending outgoing frames.
*/
void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00queue_init_queues - Initialize all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* This function will loop through all available queues to clear all
* index numbers and set the queue entry to the correct initialization
* state.
*/
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_free(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_update_stats - Update link statistics from RX frame
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: Received frame
* @rxdesc: Received frame descriptor
*
* Update link statistics based on the information from the
* received frame descriptor.
*/
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc);
/**
* rt2x00link_calculate_signal - Calculate signal quality
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @rssi: RX Frame RSSI
*
* Calculate the signal quality of a frame based on the rssi
* measured during the receiving of the frame and the global
* link quality statistics measured since the start of the
* link tuning. The result is a value between 0 and 100 which
* is an indication of the signal quality.
*/
int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi);
/**
* rt2x00link_start_tuner - Start periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* This start the link tuner periodic work, this work will
* be executed periodically until &rt2x00link_stop_tuner has
* been called.
*/
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_stop_tuner - Stop periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* After this function completed the link tuner will not
* be running until &rt2x00link_start_tuner is called.
*/
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_reset_tuner - Reset periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @antenna: Should the antenna tuning also be reset
*
* The VGC limit configured in the hardware will be reset to 0
* which forces the driver to rediscover the correct value for
* the current association. This is needed when configuration
* options have changed which could drastically change the
* SNR level or link quality (i.e. changing the antenna setting).
*
* Resetting the link tuner will also cause the periodic work counter
* to be reset. Any driver which has a fixed limit on the number
* of rounds the link tuner is supposed to work will accept the
* tuner actions again if this limit was previously reached.
*
* If @antenna is set to true a the software antenna diversity
* tuning will also be reset.
*/
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
/**
* rt2x00link_register - Initialize link tuning functionality
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* Initialize work structure and all link tuning related
* parameters. This will not start the link tuning process itself.
*/
void rt2x00link_register(struct rt2x00_dev *rt2x00dev);
/*
* Firmware handlers.
*/
#ifdef CONFIG_RT2X00_LIB_FIRMWARE
int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev);
#else
static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
return 0;
}
static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
{
}
#endif /* CONFIG_RT2X00_LIB_FIRMWARE */
/*
* Debugfs handlers.
*/
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct sk_buff *skb);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc);
#else
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type,
struct sk_buff *skb)
{
}
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
}
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
/*
* Crypto handlers.
*/
#ifdef CONFIG_RT2X00_LIB_CRYPTO
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc);
unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb);
void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
struct txentry_desc *txdesc);
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
struct txentry_desc *txdesc);
void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length);
void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc);
#else
static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
{
return CIPHER_NONE;
}
static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
}
static inline unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
return 0;
}
static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
struct txentry_desc *txdesc)
{
}
static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
struct txentry_desc *txdesc)
{
}
static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb,
unsigned int header_length)
{
}
static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc)
{
}
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
/*
* HT handlers.
*/
#ifdef CONFIG_RT2X00_LIB_HT
void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate);
#else
static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate)
{
}
#endif /* CONFIG_RT2X00_LIB_HT */
/*
* RFkill handlers.
*/
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
/*
* LED handlers
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi);
void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_register(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev);
#else
static inline void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev,
int rssi)
{
}
static inline void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
}
static inline void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
}
static inline void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
}
static inline void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
{
}
#endif /* CONFIG_RT2X00_LIB_LEDS */
#endif /* RT2X00LIB_H */

View File

@@ -0,0 +1,482 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 generic link tuning routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
/*
* When we lack RSSI information return something less then -80 to
* tell the driver to tune the device to maximum sensitivity.
*/
#define DEFAULT_RSSI -128
/*
* When no TX/RX percentage could be calculated due to lack of
* frames on the air, we fallback to a percentage of 50%.
* This will assure we will get at least get some decent value
* when the link tuner starts.
* The value will be dropped and overwritten with the correct (measured)
* value anyway during the first run of the link tuner.
*/
#define DEFAULT_PERCENTAGE 50
/*
* Small helper macro for percentage calculation
* This is a very simple macro with the only catch that it will
* produce a default value in case no total value was provided.
*/
#define PERCENTAGE(__value, __total) \
( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
/*
* Helper struct and macro to work with moving/walking averages.
* When adding a value to the average value the following calculation
* is needed:
*
* avg_rssi = ((avg_rssi * 7) + rssi) / 8;
*
* The advantage of this approach is that we only need 1 variable
* to store the average in (No need for a count and a total).
* But more importantly, normal average values will over time
* move less and less towards newly added values this results
* that with link tuning, the device can have a very good RSSI
* for a few minutes but when the device is moved away from the AP
* the average will not decrease fast enough to compensate.
* The walking average compensates this and will move towards
* the new values correctly allowing a effective link tuning,
* the speed of the average moving towards other values depends
* on the value for the number of samples. The higher the number
* of samples, the slower the average will move.
* We use two variables to keep track of the average value to
* compensate for the rounding errors. This can be a significant
* error (>5dBm) if the factor is too low.
*/
#define AVG_SAMPLES 8
#define AVG_FACTOR 1000
#define MOVING_AVERAGE(__avg, __val) \
({ \
struct avg_val __new; \
__new.avg_weight = \
(__avg).avg_weight ? \
((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \
((__val) * (AVG_FACTOR))) / \
(AVG_SAMPLES) ) : \
((__val) * (AVG_FACTOR)); \
__new.avg = __new.avg_weight / (AVG_FACTOR); \
__new; \
})
/*
* For calculating the Signal quality we have determined
* the total number of success and failed RX and TX frames.
* With the addition of the average RSSI value we can determine
* the link quality using the following algorithm:
*
* rssi_percentage = (avg_rssi * 100) / rssi_offset
* rx_percentage = (rx_success * 100) / rx_total
* tx_percentage = (tx_success * 100) / tx_total
* avg_signal = ((WEIGHT_RSSI * avg_rssi) +
* (WEIGHT_TX * tx_percentage) +
* (WEIGHT_RX * rx_percentage)) / 100
*
* This value should then be checked to not be greater then 100.
* This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must
* sum up to 100 as well.
*/
#define WEIGHT_RSSI 20
#define WEIGHT_RX 40
#define WEIGHT_TX 40
static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success)
return ant->rssi_ant.avg;
return DEFAULT_RSSI;
}
static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
if (ant->rssi_history)
return ant->rssi_history;
return DEFAULT_RSSI;
}
static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
int rssi)
{
struct link_ant *ant = &rt2x00dev->link.ant;
ant->rssi_history = rssi;
}
static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
{
rt2x00dev->link.ant.rssi_ant.avg = 0;
rt2x00dev->link.ant.rssi_ant.avg_weight = 0;
}
static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup new_ant;
int other_antenna;
int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
memcpy(&new_ant, &ant->active, sizeof(new_ant));
/*
* We are done sampling. Now we should evaluate the results.
*/
ant->flags &= ~ANTENNA_MODE_SAMPLE;
/*
* During the last period we have sampled the RSSI
* from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
* performance, just create a good starting point
* for the history and we are done.
*/
if (sample_current >= sample_other) {
rt2x00link_antenna_update_rssi_history(rt2x00dev,
sample_current);
return;
}
other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (ant->flags & ANTENNA_RX_DIVERSITY)
new_ant.rx = other_antenna;
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = other_antenna;
rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup new_ant;
int rssi_curr;
int rssi_old;
memcpy(&new_ant, &ant->active, sizeof(new_ant));
/*
* Get current RSSI value along with the historical value,
* after that update the history with the current value.
*/
rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
/*
* Legacy driver indicates that we should swap antenna's
* when the difference in RSSI is greater that 5. This
* also should be done when the RSSI was actually better
* then the previous sample.
* When the difference exceeds the threshold we should
* sample the rssi from the other antenna to make a valid
* comparison between the 2 antennas.
*/
if (abs(rssi_curr - rssi_old) < 5)
return;
ant->flags |= ANTENNA_MODE_SAMPLE;
if (ant->flags & ANTENNA_RX_DIVERSITY)
new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
unsigned int flags = ant->flags;
/*
* Determine if software diversity is enabled for
* either the TX or RX antenna (or both).
* Always perform this check since within the link
* tuner interval the configuration might have changed.
*/
flags &= ~ANTENNA_RX_DIVERSITY;
flags &= ~ANTENNA_TX_DIVERSITY;
if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
flags |= ANTENNA_RX_DIVERSITY;
if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
flags |= ANTENNA_TX_DIVERSITY;
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
ant->flags = 0;
return true;
}
/* Update flags */
ant->flags = flags;
/*
* If we have only sampled the data over the last period
* we should now harvest the data. Otherwise just evaluate
* the data. The latter should only be performed once
* every 2 seconds.
*/
if (ant->flags & ANTENNA_MODE_SAMPLE) {
rt2x00lib_antenna_diversity_sample(rt2x00dev);
return true;
} else if (rt2x00dev->link.count & 1) {
rt2x00lib_antenna_diversity_eval(rt2x00dev);
return true;
}
return false;
}
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
{
struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
struct link_ant *ant = &rt2x00dev->link.ant;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
/*
* Frame was received successfully since non-succesfull
* frames would have been dropped by the hardware.
*/
qual->rx_success++;
/*
* We are only interested in quality statistics from
* beacons which came from the BSS which we are
* associated with.
*/
if (!ieee80211_is_beacon(hdr->frame_control) ||
!(rxdesc->dev_flags & RXDONE_MY_BSS))
return;
/*
* Update global RSSI
*/
link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi);
/*
* Update antenna RSSI
*/
ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi);
}
static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
link->rx_percentage =
PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success);
link->tx_percentage =
PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success);
}
int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
{
struct link *link = &rt2x00dev->link;
int rssi_percentage = 0;
int signal;
/*
* We need a positive value for the RSSI.
*/
if (rssi < 0)
rssi += rt2x00dev->rssi_offset;
/*
* Calculate the different percentages,
* which will be used for the signal.
*/
rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset);
/*
* Add the individual percentages and use the WEIGHT
* defines to calculate the current link signal.
*/
signal = ((WEIGHT_RSSI * rssi_percentage) +
(WEIGHT_TX * link->tx_percentage) +
(WEIGHT_RX * link->rx_percentage)) / 100;
return max_t(int, signal, 100);
}
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
/*
* Link tuning should only be performed when
* an active sta or master interface exists.
* Single monitor mode interfaces should never have
* work with link tuners.
*/
if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
return;
link->rx_percentage = DEFAULT_PERCENTAGE;
link->tx_percentage = DEFAULT_PERCENTAGE;
rt2x00link_reset_tuner(rt2x00dev, false);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
{
cancel_delayed_work_sync(&rt2x00dev->link.work);
}
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
{
struct link_qual *qual = &rt2x00dev->link.qual;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/*
* Reset link information.
* Both the currently active vgc level as well as
* the link tuner counter should be reset. Resetting
* the counter is important for devices where the
* device should only perform link tuning during the
* first minute after being enabled.
*/
rt2x00dev->link.count = 0;
memset(qual, 0, sizeof(*qual));
/*
* Reset the link tuner.
*/
rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
if (antenna)
rt2x00link_antenna_reset(rt2x00dev);
}
static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
{
struct link_qual *qual = &rt2x00dev->link.qual;
qual->rx_success = 0;
qual->rx_failed = 0;
qual->tx_success = 0;
qual->tx_failed = 0;
}
static void rt2x00link_tuner(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, link.work.work);
struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
/*
* When the radio is shutting down we should
* immediately cease all link tuning.
*/
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/*
* Update statistics.
*/
rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
/*
* Update quality RSSI for link tuning,
* when we have received some frames and we managed to
* collect the RSSI data we could use this. Otherwise we
* must fallback to the default RSSI value.
*/
if (!link->avg_rssi.avg || !qual->rx_success)
qual->rssi = DEFAULT_RSSI;
else
qual->rssi = link->avg_rssi.avg;
/*
* Only perform the link tuning when Link tuning
* has been enabled (This could have been disabled from the EEPROM).
*/
if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
* Precalculate a portion of the link signal which is
* in based on the tx/rx success/failure counters.
*/
rt2x00link_precalculate_signal(rt2x00dev);
/*
* Send a signal to the led to update the led signal strength.
*/
rt2x00leds_led_quality(rt2x00dev, qual->rssi);
/*
* Evaluate antenna setup, make this the last step when
* rt2x00lib_antenna_diversity made changes the quality
* statistics will be reset.
*/
if (rt2x00lib_antenna_diversity(rt2x00dev))
rt2x00link_reset_qual(rt2x00dev);
/*
* Increase tuner counter, and reschedule the next link tuner run.
*/
link->count++;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
}

View File

@@ -0,0 +1,692 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00mac
Abstract: rt2x00 generic mac80211 routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue,
struct sk_buff *frag_skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
struct ieee80211_tx_info *rts_info;
struct sk_buff *skb;
unsigned int data_length;
int retval = 0;
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
data_length = sizeof(struct ieee80211_cts);
else
data_length = sizeof(struct ieee80211_rts);
skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom);
if (unlikely(!skb)) {
WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
return -ENOMEM;
}
skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
skb_put(skb, data_length);
/*
* Copy TX information over from original frame to
* RTS/CTS frame. Note that we set the no encryption flag
* since we don't want this frame to be encrypted.
* RTS frames should be acked, while CTS-to-self frames
* should not. The ready for TX flag is cleared to prevent
* it being automatically send when the descriptor is
* written to the hardware.
*/
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
rts_info = IEEE80211_SKB_CB(skb);
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
/* Disable hardware encryption */
rts_info->control.hw_key = NULL;
/*
* RTS/CTS frame should use the length of the frame plus any
* encryption overhead that will be added by the hardware.
*/
data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb);
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, data_length, tx_info,
(struct ieee80211_cts *)(skb->data));
else
ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, data_length, tx_info,
(struct ieee80211_rts *)(skb->data));
retval = rt2x00queue_write_tx_frame(queue, skb);
if (retval) {
dev_kfree_skb_any(skb);
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
}
return retval;
}
int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
enum data_queue_qid qid = skb_get_queue_mapping(skb);
struct data_queue *queue;
u16 frame_control;
/*
* Mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
* Note that we can only stop the TX queues inside the TX path
* due to possible race conditions in mac80211.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
goto exit_fail;
/*
* Determine which queue to put packet on.
*/
if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM);
else
queue = rt2x00queue_get_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n", qid, DRV_PROJECT);
goto exit_fail;
}
/*
* If CTS/RTS is required. create and queue that frame first.
* Make sure we have at least enough entries available to send
* this CTS/RTS frame as well as the data frame.
* Note that when the driver has set the set_rts_threshold()
* callback function it doesn't need software generation of
* either RTS or CTS-to-self frame and handles everything
* inside the hardware.
*/
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
!rt2x00dev->ops->hw->set_rts_threshold) {
if (rt2x00queue_available(queue) <= 1)
goto exit_fail;
if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb))
goto exit_fail;
}
if (rt2x00queue_write_tx_frame(queue, skb))
goto exit_fail;
if (rt2x00queue_threshold(queue))
ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_OK;
exit_fail:
ieee80211_stop_queue(rt2x00dev->hw, qid);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
EXPORT_SYMBOL_GPL(rt2x00mac_tx);
int rt2x00mac_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
return rt2x00lib_start(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_start);
void rt2x00mac_stop(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
rt2x00lib_stop(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_stop);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(conf->vif);
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
struct queue_entry *entry = NULL;
unsigned int i;
/*
* Don't allow interfaces to be added
* the device has disappeared.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return -ENODEV;
switch (conf->type) {
case NL80211_IFTYPE_AP:
/*
* We don't support mixed combinations of
* sta and ap interfaces.
*/
if (rt2x00dev->intf_sta_count)
return -ENOBUFS;
/*
* Check if we exceeded the maximum amount
* of supported interfaces.
*/
if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf)
return -ENOBUFS;
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_WDS:
/*
* We don't support mixed combinations of
* sta and ap interfaces.
*/
if (rt2x00dev->intf_ap_count)
return -ENOBUFS;
/*
* Check if we exceeded the maximum amount
* of supported interfaces.
*/
if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)
return -ENOBUFS;
break;
default:
return -EINVAL;
}
/*
* Loop through all beacon queues to find a free
* entry. Since there are as much beacon entries
* as the maximum interfaces, this search shouldn't
* fail.
*/
for (i = 0; i < queue->limit; i++) {
entry = &queue->entries[i];
if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
break;
}
if (unlikely(i == queue->limit))
return -ENOBUFS;
/*
* We are now absolutely sure the interface can be created,
* increase interface count and start initialization.
*/
if (conf->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count++;
else
rt2x00dev->intf_sta_count++;
spin_lock_init(&intf->lock);
spin_lock_init(&intf->seqlock);
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
if (conf->type == NL80211_IFTYPE_AP)
memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
/*
* The MAC adddress must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
*/
rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
/*
* Some filters depend on the current working mode. We can force
* an update during the next configure_filter() run by mac80211 by
* resetting the current packet_filter state.
*/
rt2x00dev->packet_filter = 0;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(conf->vif);
/*
* Don't allow interfaces to be remove while
* either the device has disappeared or when
* no interface is present.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
(conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
(conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
return;
if (conf->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count--;
else
rt2x00dev->intf_sta_count--;
/*
* Release beacon entry so it is available for
* new interfaces again.
*/
clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
/*
* Make sure the bssid and mac address registers
* are cleared to prevent false ACKing of frames.
*/
rt2x00lib_config_intf(rt2x00dev, intf,
NL80211_IFTYPE_UNSPECIFIED, NULL, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
/*
* mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
/*
* Some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled, but do require the RX to
* be off.
*/
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
/*
* When we've just turned on the radio, we want to reprogram
* everything to ensure a consistent state
*/
rt2x00lib_config(rt2x00dev, conf, changed);
/*
* After the radio has been enabled we need to configure
* the antenna to the default settings. rt2x00lib_config_antenna()
* should determine if any action should be taken based on
* checking if diversity has been enabled or no antenna changes
* have been made since the last configuration change.
*/
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
/* Turn RX back on */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_config);
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Mask off any flags we are going to ignore
* from the total_flags field.
*/
*total_flags &=
FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_PSPOLL |
FIF_OTHER_BSS |
FIF_PROMISC_IN_BSS;
/*
* Apply some rules to the filters:
* - Some filters imply different filters to be set.
* - Some things we can't filter out at all.
* - Multicast filter seems to kill broadcast traffic so never use it.
*/
*total_flags |= FIF_ALLMULTI;
if (*total_flags & FIF_OTHER_BSS ||
*total_flags & FIF_PROMISC_IN_BSS)
*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
/*
* If the device has a single filter for all control frames,
* FIF_CONTROL and FIF_PSPOLL flags imply each other.
* And if the device has more than one filter for control frames
* of different types, but has no a separate filter for PS Poll frames,
* FIF_CONTROL flag implies FIF_PSPOLL.
*/
if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) {
if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
*total_flags |= FIF_CONTROL | FIF_PSPOLL;
}
if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) {
if (*total_flags & FIF_CONTROL)
*total_flags |= FIF_PSPOLL;
}
/*
* Check if there is any work left for us.
*/
if (rt2x00dev->packet_filter == *total_flags)
return;
rt2x00dev->packet_filter = *total_flags;
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
rt2x00lib_beacondone(rt2x00dev);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
memcpy(&crypto->key,
&key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
sizeof(crypto->key));
if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
memcpy(&crypto->tx_mic,
&key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
sizeof(crypto->tx_mic));
if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
memcpy(&crypto->rx_mic,
&key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
sizeof(crypto->rx_mic));
}
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
int (*set_key) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
struct rt2x00lib_crypto crypto;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
return -EOPNOTSUPP;
else if (key->keylen > 32)
return -ENOSPC;
memset(&crypto, 0, sizeof(crypto));
/*
* When in STA mode, bssidx is always 0 otherwise local_address[5]
* contains the bss number, see BSS_ID_MASK comments for details.
*/
if (rt2x00dev->intf_sta_count)
crypto.bssidx = 0;
else
crypto.bssidx = intf->mac[5] & (rt2x00dev->ops->max_ap_intf - 1);
crypto.cipher = rt2x00crypto_key_to_cipher(key);
if (crypto.cipher == CIPHER_NONE)
return -EOPNOTSUPP;
crypto.cmd = cmd;
if (sta) {
/* some drivers need the AID */
crypto.aid = sta->aid;
crypto.address = sta->addr;
} else
crypto.address = bcast_addr;
if (crypto.cipher == CIPHER_TKIP)
memcpy_tkip(&crypto, &key->key[0], key->keylen);
else
memcpy(&crypto.key, &key->key[0], key->keylen);
/*
* Each BSS has a maximum of 4 shared keys.
* Shared key index values:
* 0) BSS0 key0
* 1) BSS0 key1
* ...
* 4) BSS1 key0
* ...
* 8) BSS2 key0
* ...
* Both pairwise as shared key indeces are determined by
* driver. This is required because the hardware requires
* keys to be assigned in correct order (When key 1 is
* provided but key 0 is not, then the key is not found
* by the hardware during RX).
*/
if (cmd == SET_KEY)
key->hw_key_idx = 0;
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
set_key = rt2x00dev->ops->lib->config_pairwise_key;
else
set_key = rt2x00dev->ops->lib->config_shared_key;
if (!set_key)
return -EOPNOTSUPP;
return set_key(rt2x00dev, &crypto, key);
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* The dot11ACKFailureCount, dot11RTSFailureCount and
* dot11RTSSuccessCount are updated in interrupt time.
* dot11FCSErrorCount is updated in the link tuner.
*/
memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i;
for (i = 0; i < rt2x00dev->ops->tx_queues; i++) {
stats[i].len = rt2x00dev->tx[i].length;
stats[i].limit = rt2x00dev->tx[i].limit;
stats[i].count = rt2x00dev->tx[i].count;
}
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
int update_bssid = 0;
/*
* mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
spin_lock(&intf->lock);
/*
* conf->bssid can be NULL if coming from the internal
* beacon update routine.
*/
if (changes & BSS_CHANGED_BSSID) {
update_bssid = 1;
memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
}
spin_unlock(&intf->lock);
/*
* Call rt2x00_config_intf() outside of the spinlock context since
* the call will sleep for USB drivers. By using the ieee80211_if_conf
* values as arguments we make keep access to rt2x00_intf thread safe
* even without the lock.
*/
if (changes & BSS_CHANGED_BSSID)
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
update_bssid ? bss_conf->bssid : NULL);
/*
* Update the beacon.
*/
if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED))
rt2x00queue_update_beacon(rt2x00dev, vif,
bss_conf->enable_beacon);
/*
* When the association status has changed we must reset the link
* tuner counter. This is because some drivers determine if they
* should perform link tuning based on the number of seconds
* while associated or not associated.
*/
if (changes & BSS_CHANGED_ASSOC) {
rt2x00dev->link.count = 0;
if (bss_conf->assoc)
rt2x00dev->intf_associated++;
else
rt2x00dev->intf_associated--;
rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
}
/*
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT))
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
if (unlikely(!queue))
return -EINVAL;
/*
* The passed variables are stored as real value ((2^n)-1).
* Ralink registers require to know the bit number 'n'.
*/
if (params->cw_min > 0)
queue->cw_min = fls(params->cw_min);
else
queue->cw_min = 5; /* cw_min: 2^5 = 32. */
if (params->cw_max > 0)
queue->cw_max = fls(params->cw_max);
else
queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
queue->aifs = params->aifs;
queue->txop = params->txop;
INFO(rt2x00dev,
"Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
wiphy_rfkill_set_hw_state(hw->wiphy, !active);
}
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);

View File

@@ -0,0 +1,409 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00pci
Abstract: rt2x00 generic pci device routines.
*/
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "rt2x00.h"
#include "rt2x00pci.h"
/*
* Register access.
*/
int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg)
{
unsigned int i;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2x00pci_register_read(rt2x00dev, offset, reg);
if (!rt2x00_get_field32(*reg, field))
return 1;
udelay(REGISTER_BUSY_DELAY);
}
ERROR(rt2x00dev, "Indirect register access failed: "
"offset=0x%.08x, value=0x%.08x\n", offset, *reg);
*reg = ~0;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
/*
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc;
/*
* This should not happen, we already checked the entry
* was ours. When the hardware disagrees there has been
* a queue corruption!
*/
if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) {
ERROR(rt2x00dev,
"Corrupt queue %d, accessing entry which is not ours.\n"
"Please file bug report to %s.\n",
entry->queue->qid, DRV_PROJECT);
return -EINVAL;
}
/*
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = entry->queue->desc_size;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
/*
* TX/RX data handlers.
*/
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry;
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
while (1) {
entry = rt2x00queue_get_entry(queue, Q_INDEX);
entry_priv = entry->priv_data;
if (rt2x00dev->ops->lib->get_entry_state(entry))
break;
/*
* Fill in desc fields of the skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = entry->queue->desc_size;
/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(rt2x00dev, entry);
}
}
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
/*
* Device initialization handlers.
*/
static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct queue_entry_priv_pci *entry_priv;
void *addr;
dma_addr_t dma;
unsigned int i;
/*
* Allocate DMA memory for descriptor and buffer.
*/
addr = dma_alloc_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size,
&dma, GFP_KERNEL | GFP_DMA);
if (!addr)
return -ENOMEM;
memset(addr, 0, queue->limit * queue->desc_size);
/*
* Initialize all queue entries to contain valid addresses.
*/
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
entry_priv->desc = addr + i * queue->desc_size;
entry_priv->desc_dma = dma + i * queue->desc_size;
}
return 0;
}
static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct queue_entry_priv_pci *entry_priv =
queue->entries[0].priv_data;
if (entry_priv->desc)
dma_free_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size,
entry_priv->desc, entry_priv->desc_dma);
entry_priv->desc = NULL;
}
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
int status;
/*
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
if (status)
goto exit;
}
/*
* Register interrupt handler.
*/
status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler,
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
if (status) {
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
rt2x00dev->irq, status);
goto exit;
}
return 0;
exit:
queue_for_each(rt2x00dev, queue)
rt2x00pci_free_queue_dma(rt2x00dev, queue);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
/*
* Free irq line.
*/
free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev);
/*
* Free DMA
*/
queue_for_each(rt2x00dev, queue)
rt2x00pci_free_queue_dma(rt2x00dev, queue);
}
EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
/*
* PCI driver handlers.
*/
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rf);
rt2x00dev->rf = NULL;
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
if (rt2x00dev->csr.base) {
iounmap(rt2x00dev->csr.base);
rt2x00dev->csr.base = NULL;
}
}
static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0);
if (!rt2x00dev->csr.base)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
if (!rt2x00dev->eeprom)
goto exit;
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
if (!rt2x00dev->rf)
goto exit;
return 0;
exit:
ERROR_PROBE("Failed to allocate registers.\n");
rt2x00pci_free_reg(rt2x00dev);
return -ENOMEM;
}
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
{
struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
u16 chip;
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
if (retval) {
ERROR_PROBE("PCI request regions failed.\n");
return retval;
}
retval = pci_enable_device(pci_dev);
if (retval) {
ERROR_PROBE("Enable device failed.\n");
goto exit_release_regions;
}
pci_set_master(pci_dev);
if (pci_set_mwi(pci_dev))
ERROR_PROBE("MWI not available.\n");
if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
ERROR_PROBE("PCI DMA not supported.\n");
retval = -EIO;
goto exit_disable_device;
}
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
ERROR_PROBE("Failed to allocate hardware.\n");
retval = -ENOMEM;
goto exit_disable_device;
}
pci_set_drvdata(pci_dev, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = &pci_dev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
/*
* Determine RT chipset by reading PCI header.
*/
pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
rt2x00_set_chip_rt(rt2x00dev, chip);
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
goto exit_free_reg;
return 0;
exit_free_reg:
rt2x00pci_free_reg(rt2x00dev);
exit_free_device:
ieee80211_free_hw(hw);
exit_disable_device:
if (retval != -EBUSY)
pci_disable_device(pci_dev);
exit_release_regions:
pci_release_regions(pci_dev);
pci_set_drvdata(pci_dev, NULL);
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_probe);
void rt2x00pci_remove(struct pci_dev *pci_dev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
rt2x00pci_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
/*
* Free the PCI device data.
*/
pci_set_drvdata(pci_dev, NULL);
pci_disable_device(pci_dev);
pci_release_regions(pci_dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_remove);
#ifdef CONFIG_PM
int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
int retval;
retval = rt2x00lib_suspend(rt2x00dev, state);
if (retval)
return retval;
pci_save_state(pci_dev);
pci_disable_device(pci_dev);
return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
}
EXPORT_SYMBOL_GPL(rt2x00pci_suspend);
int rt2x00pci_resume(struct pci_dev *pci_dev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
if (pci_set_power_state(pci_dev, PCI_D0) ||
pci_enable_device(pci_dev) ||
pci_restore_state(pci_dev)) {
ERROR(rt2x00dev, "Failed to resume device.\n");
return -EIO;
}
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
#endif /* CONFIG_PM */
/*
* rt2x00pci module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2x00 pci library");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,144 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00pci
Abstract: Data structures for the rt2x00pci module.
*/
#ifndef RT2X00PCI_H
#define RT2X00PCI_H
#include <linux/io.h>
/*
* This variable should be used with the
* pci_driver structure initialization.
*/
#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
/*
* Register defines.
* Some registers require multiple attempts before success,
* in those cases REGISTER_BUSY_COUNT attempts should be
* taken with a REGISTER_BUSY_DELAY interval.
*/
#define REGISTER_BUSY_COUNT 5
#define REGISTER_BUSY_DELAY 100
/*
* Register access.
*/
static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
*value = readl(rt2x00dev->csr.base + offset);
}
static inline void
rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u16 length)
{
memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
}
static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
writel(value, rt2x00dev->csr.base + offset);
}
static inline void
rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const void *value, const u16 length)
{
memcpy_toio(rt2x00dev->csr.base + offset, value, length);
}
/**
* rt2x00pci_regbusy_read - Read from register with busy check
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @field: Field to check if register is busy
* @reg: Pointer to where register contents should be stored
*
* This function will read the given register, and checks if the
* register is busy. If it is, it will sleep for a couple of
* microseconds before reading the register again. If the register
* is not read after a certain timeout, this function will return
* FALSE.
*/
int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg);
/**
* rt2x00pci_write_tx_data - Initialize data for TX operation
* @entry: The entry where the frame is located
*
* This function will initialize the DMA and skb descriptor
* to prepare the entry for the actual TX operation.
*/
int rt2x00pci_write_tx_data(struct queue_entry *entry);
/**
* struct queue_entry_priv_pci: Per entry PCI specific information
*
* @desc: Pointer to device descriptor
* @desc_dma: DMA pointer to &desc.
* @data: Pointer to device's entry memory.
* @data_dma: DMA pointer to &data.
*/
struct queue_entry_priv_pci {
__le32 *desc;
dma_addr_t desc_dma;
};
/**
* rt2x00pci_rxdone - Handle RX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
*/
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
/*
* Device initialization handlers.
*/
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
/*
* PCI driver handlers.
*/
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
void rt2x00pci_remove(struct pci_dev *pci_dev);
#ifdef CONFIG_PM
int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state);
int rt2x00pci_resume(struct pci_dev *pci_dev);
#else
#define rt2x00pci_suspend NULL
#define rt2x00pci_resume NULL
#endif /* CONFIG_PM */
#endif /* RT2X00PCI_H */

View File

@@ -0,0 +1,921 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00lib
Abstract: rt2x00 queue specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
unsigned int frame_size;
unsigned int head_size = 0;
unsigned int tail_size = 0;
/*
* The frame size includes descriptor size, because the
* hardware directly receive the frame into the skbuffer.
*/
frame_size = entry->queue->data_size + entry->queue->desc_size;
/*
* The payload should be aligned to a 4-byte boundary,
* this means we need at least 3 bytes for moving the frame
* into the correct offset.
*/
head_size = 4;
/*
* For IV/EIV/ICV assembly we must make sure there is
* at least 8 bytes bytes available in headroom for IV/EIV
* and 8 bytes for ICV data as tailroon.
*/
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
head_size += 8;
tail_size += 8;
}
/*
* Allocate skbuffer.
*/
skb = dev_alloc_skb(frame_size + head_size + tail_size);
if (!skb)
return NULL;
/*
* Make sure we not have a frame with the requested bytes
* available in the head and tail.
*/
skb_reserve(skb, head_size);
skb_put(skb, frame_size);
/*
* Populate skbdesc.
*/
skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
skb->data,
skb->len,
DMA_FROM_DEVICE);
skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
}
return skb;
}
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
/*
* If device has requested headroom, we should make sure that
* is also mapped to the DMA so it can be used for transfering
* additional descriptor information to the hardware.
*/
skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
skbdesc->skb_dma =
dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
/*
* Restore data pointer to original location again.
*/
skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_FROM_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
/*
* Add headroom to the skb length, it has been removed
* by the driver, but it was actually mapped to DMA.
*/
dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
skb->len + rt2x00dev->ops->extra_tx_headroom,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
}
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
if (!skb)
return;
rt2x00queue_unmap_skb(rt2x00dev, skb);
dev_kfree_skb_any(skb);
}
void rt2x00queue_align_frame(struct sk_buff *skb)
{
unsigned int frame_length = skb->len;
unsigned int align = ALIGN_SIZE(skb, 0);
if (!align)
return;
skb_push(skb, align);
memmove(skb->data, skb->data + align, frame_length);
skb_trim(skb, frame_length);
}
void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt)
{
unsigned int frame_length = skb->len;
unsigned int align = ALIGN_SIZE(skb, header_lengt);
if (!align)
return;
skb_push(skb, align);
memmove(skb->data, skb->data + align, frame_length);
skb_trim(skb, frame_length);
}
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
unsigned int frame_length = skb->len;
unsigned int header_align = ALIGN_SIZE(skb, 0);
unsigned int payload_align = ALIGN_SIZE(skb, header_length);
unsigned int l2pad = 4 - (payload_align - header_align);
if (header_align == payload_align) {
/*
* Both header and payload must be moved the same
* amount of bytes to align them properly. This means
* we don't use the L2 padding but just move the entire
* frame.
*/
rt2x00queue_align_frame(skb);
} else if (!payload_align) {
/*
* Simple L2 padding, only the header needs to be moved,
* the payload is already properly aligned.
*/
skb_push(skb, header_align);
memmove(skb->data, skb->data + header_align, frame_length);
skbdesc->flags |= SKBDESC_L2_PADDED;
} else {
/*
*
* Complicated L2 padding, both header and payload need
* to be moved. By default we only move to the start
* of the buffer, so our header alignment needs to be
* increased if there is not enough room for the header
* to be moved.
*/
if (payload_align > header_align)
header_align += 4;
skb_push(skb, header_align);
memmove(skb->data, skb->data + header_align, header_length);
memmove(skb->data + header_length + l2pad,
skb->data + header_length + l2pad + header_align,
frame_length - header_length);
skbdesc->flags |= SKBDESC_L2_PADDED;
}
}
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
unsigned int l2pad = 4 - (header_length & 3);
if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
return;
memmove(skb->data + l2pad, skb->data, header_length);
skb_pull(skb, l2pad);
}
static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
unsigned long irqflags;
if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) ||
unlikely(!tx_info->control.vif))
return;
/*
* Hardware should insert sequence counter.
* FIXME: We insert a software sequence counter first for
* hardware that doesn't support hardware sequence counting.
*
* This is wrong because beacons are not getting sequence
* numbers assigned properly.
*
* A secondary problem exists for drivers that cannot toggle
* sequence counting per-frame, since those will override the
* sequence counter given by mac80211.
*/
spin_lock_irqsave(&intf->seqlock, irqflags);
if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
intf->seqno += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
spin_unlock_irqrestore(&intf->seqlock, irqflags);
__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
}
static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
unsigned int data_length;
unsigned int duration;
unsigned int residual;
/* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */
data_length = entry->skb->len + 4;
data_length += rt2x00crypto_tx_overhead(rt2x00dev, entry->skb);
/*
* PLCP setup
* Length calculation depends on OFDM/CCK rate.
*/
txdesc->signal = hwrate->plcp;
txdesc->service = 0x04;
if (hwrate->flags & DEV_RATE_OFDM) {
txdesc->length_high = (data_length >> 6) & 0x3f;
txdesc->length_low = data_length & 0x3f;
} else {
/*
* Convert length to microseconds.
*/
residual = GET_DURATION_RES(data_length, hwrate->bitrate);
duration = GET_DURATION(data_length, hwrate->bitrate);
if (residual != 0) {
duration++;
/*
* Check if we need to set the Length Extension
*/
if (hwrate->bitrate == 110 && residual <= 30)
txdesc->service |= 0x80;
}
txdesc->length_high = (duration >> 8) & 0xff;
txdesc->length_low = duration & 0xff;
/*
* When preamble is enabled we should set the
* preamble bit for the signal.
*/
if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
txdesc->signal |= 0x08;
}
}
static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
struct ieee80211_rate *rate =
ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
const struct rt2x00_rate *hwrate;
memset(txdesc, 0, sizeof(*txdesc));
/*
* Initialize information from queue
*/
txdesc->queue = entry->queue->qid;
txdesc->cw_min = entry->queue->cw_min;
txdesc->cw_max = entry->queue->cw_max;
txdesc->aifs = entry->queue->aifs;
/*
* Header and alignment information.
*/
txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length);
/*
* Check whether this frame is to be acked.
*/
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
__set_bit(ENTRY_TXD_ACK, &txdesc->flags);
/*
* Check if this is a RTS/CTS frame
*/
if (ieee80211_is_rts(hdr->frame_control) ||
ieee80211_is_cts(hdr->frame_control)) {
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
if (ieee80211_is_rts(hdr->frame_control))
__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
else
__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
if (tx_info->control.rts_cts_rate_idx >= 0)
rate =
ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
}
/*
* Determine retry information.
*/
txdesc->retry_limit = tx_info->control.rates[0].count - 1;
if (txdesc->retry_limit >= rt2x00dev->long_retry)
__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
/*
* Check if more fragments are pending
*/
if (ieee80211_has_morefrags(hdr->frame_control) ||
(tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) {
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
}
/*
* Beacons and probe responses require the tsf timestamp
* to be inserted into the frame.
*/
if (ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control))
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
/*
* Determine with what IFS priority this frame should be send.
* Set ifs to IFS_SIFS when the this is not the first fragment,
* or this fragment came after RTS/CTS.
*/
if ((tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) &&
!test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) {
__set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags);
txdesc->ifs = IFS_BACKOFF;
} else
txdesc->ifs = IFS_SIFS;
/*
* Determine rate modulation.
*/
hwrate = rt2x00_get_rate(rate->hw_value);
txdesc->rate_mode = RATE_MODE_CCK;
if (hwrate->flags & DEV_RATE_OFDM)
txdesc->rate_mode = RATE_MODE_OFDM;
/*
* Apply TX descriptor handling by components
*/
rt2x00crypto_create_tx_descriptor(entry, txdesc);
rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate);
rt2x00queue_create_tx_descriptor_seq(entry, txdesc);
rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
}
static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
/*
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
/*
* Check if we need to kick the queue, there are however a few rules
* 1) Don't kick beacon queue
* 2) Don't kick unless this is the last in frame in a burst.
* When the burst flag is set, this frame is always followed
* by another frame which in some way are related to eachother.
* This is true for fragments, RTS or CTS-to-self frames.
* 3) Rule 2 can be broken when the available entries
* in the queue are less then a certain threshold.
*/
if (entry->queue->qid == QID_BEACON)
return;
if (rt2x00queue_threshold(queue) ||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
}
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info;
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
struct txentry_desc txdesc;
struct skb_frame_desc *skbdesc;
u8 rate_idx, rate_flags;
if (unlikely(rt2x00queue_full(queue)))
return -ENOBUFS;
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
ERROR(queue->rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
queue->qid, DRV_PROJECT);
return -EINVAL;
}
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
entry->skb = skb;
rt2x00queue_create_tx_descriptor(entry, &txdesc);
/*
* All information is retrieved from the skb->cb array,
* now we should claim ownership of the driver part of that
* array, preserving the bitrate index and flags.
*/
tx_info = IEEE80211_SKB_CB(skb);
rate_idx = tx_info->control.rates[0].idx;
rate_flags = tx_info->control.rates[0].flags;
skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
skbdesc->tx_rate_idx = rate_idx;
skbdesc->tx_rate_flags = rate_flags;
/*
* When hardware encryption is supported, and this frame
* is to be encrypted, we should strip the IV/EIV data from
* the frame so we can provide it to the driver seperately.
*/
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags))
rt2x00crypto_tx_copy_iv(skb, &txdesc);
else
rt2x00crypto_tx_remove_iv(skb, &txdesc);
}
/*
* When DMA allocation is required we should guarentee to the
* driver that the DMA is aligned to a 4-byte boundary.
* However some drivers require L2 padding to pad the payload
* rather then the header. This could be a requirement for
* PCI and USB devices, while header alignment only is valid
* for PCI devices.
*/
if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
rt2x00queue_align_frame(entry->skb);
/*
* It could be possible that the queue was corrupted and this
* call failed. Since we always return NETDEV_TX_OK to mac80211,
* this frame will simply be dropped.
*/
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
entry->skb = NULL;
return -EIO;
}
if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
rt2x00queue_map_txskb(queue->rt2x00dev, skb);
set_bit(ENTRY_DATA_PENDING, &entry->flags);
rt2x00queue_index_inc(queue, Q_INDEX);
rt2x00queue_write_tx_descriptor(entry, &txdesc);
return 0;
}
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif,
const bool enable_beacon)
{
struct rt2x00_intf *intf = vif_to_intf(vif);
struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
__le32 desc[16];
if (unlikely(!intf->beacon))
return -ENOBUFS;
mutex_lock(&intf->beacon_skb_mutex);
/*
* Clean up the beacon skb.
*/
rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
intf->beacon->skb = NULL;
if (!enable_beacon) {
rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
if (!intf->beacon->skb) {
mutex_unlock(&intf->beacon_skb_mutex);
return -ENOMEM;
}
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/*
* For the descriptor we use a local array from where the
* driver can move it to the correct location required for
* the hardware.
*/
memset(desc, 0, sizeof(desc));
/*
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(intf->beacon->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->desc = desc;
skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon;
/*
* Write TX descriptor into reserved room in front of the beacon.
*/
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
/*
* Send beacon to hardware.
* Also enable beacon generation, which might have been disabled
* by the driver during the config_beacon() callback function.
*/
rt2x00dev->ops->lib->write_beacon(intf->beacon);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
if (queue == QID_RX)
return rt2x00dev->rx;
if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx)
return &rt2x00dev->tx[queue];
if (!rt2x00dev->bcn)
return NULL;
if (queue == QID_BEACON)
return &rt2x00dev->bcn[0];
else if (queue == QID_ATIM && atim)
return &rt2x00dev->bcn[1];
return NULL;
}
EXPORT_SYMBOL_GPL(rt2x00queue_get_queue);
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index)
{
struct queue_entry *entry;
unsigned long irqflags;
if (unlikely(index >= Q_INDEX_MAX)) {
ERROR(queue->rt2x00dev,
"Entry requested from invalid index type (%d)\n", index);
return NULL;
}
spin_lock_irqsave(&queue->lock, irqflags);
entry = &queue->entries[queue->index[index]];
spin_unlock_irqrestore(&queue->lock, irqflags);
return entry;
}
EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
{
unsigned long irqflags;
if (unlikely(index >= Q_INDEX_MAX)) {
ERROR(queue->rt2x00dev,
"Index change on invalid index type (%d)\n", index);
return;
}
spin_lock_irqsave(&queue->lock, irqflags);
queue->index[index]++;
if (queue->index[index] >= queue->limit)
queue->index[index] = 0;
if (index == Q_INDEX) {
queue->length++;
} else if (index == Q_INDEX_DONE) {
queue->length--;
queue->count++;
}
spin_unlock_irqrestore(&queue->lock, irqflags);
}
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
spin_lock_irqsave(&queue->lock, irqflags);
queue->count = 0;
queue->length = 0;
memset(queue->index, 0, sizeof(queue->index));
spin_unlock_irqrestore(&queue->lock, irqflags);
}
void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
txall_queue_for_each(rt2x00dev, queue)
rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, queue->qid);
}
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
unsigned int i;
queue_for_each(rt2x00dev, queue) {
rt2x00queue_reset(queue);
for (i = 0; i < queue->limit; i++) {
queue->entries[i].flags = 0;
rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
}
}
}
static int rt2x00queue_alloc_entries(struct data_queue *queue,
const struct data_queue_desc *qdesc)
{
struct queue_entry *entries;
unsigned int entry_size;
unsigned int i;
rt2x00queue_reset(queue);
queue->limit = qdesc->entry_num;
queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10);
queue->data_size = qdesc->data_size;
queue->desc_size = qdesc->desc_size;
/*
* Allocate all queue entries.
*/
entry_size = sizeof(*entries) + qdesc->priv_size;
entries = kzalloc(queue->limit * entry_size, GFP_KERNEL);
if (!entries)
return -ENOMEM;
#define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \
( ((char *)(__base)) + ((__limit) * (__esize)) + \
((__index) * (__psize)) )
for (i = 0; i < queue->limit; i++) {
entries[i].flags = 0;
entries[i].queue = queue;
entries[i].skb = NULL;
entries[i].entry_idx = i;
entries[i].priv_data =
QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit,
sizeof(*entries), qdesc->priv_size);
}
#undef QUEUE_ENTRY_PRIV_OFFSET
queue->entries = entries;
return 0;
}
static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
unsigned int i;
if (!queue->entries)
return;
for (i = 0; i < queue->limit; i++) {
if (queue->entries[i].skb)
rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb);
}
}
static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
unsigned int i;
struct sk_buff *skb;
for (i = 0; i < queue->limit; i++) {
skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]);
if (!skb)
return -ENOMEM;
queue->entries[i].skb = skb;
}
return 0;
}
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
int status;
status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
if (status)
goto exit;
tx_queue_for_each(rt2x00dev, queue) {
status = rt2x00queue_alloc_entries(queue, rt2x00dev->ops->tx);
if (status)
goto exit;
}
status = rt2x00queue_alloc_entries(rt2x00dev->bcn, rt2x00dev->ops->bcn);
if (status)
goto exit;
if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) {
status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
rt2x00dev->ops->atim);
if (status)
goto exit;
}
status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx);
if (status)
goto exit;
return 0;
exit:
ERROR(rt2x00dev, "Queue entries allocation failed.\n");
rt2x00queue_uninitialize(rt2x00dev);
return status;
}
void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
queue_for_each(rt2x00dev, queue) {
kfree(queue->entries);
queue->entries = NULL;
}
}
static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, enum data_queue_qid qid)
{
spin_lock_init(&queue->lock);
queue->rt2x00dev = rt2x00dev;
queue->qid = qid;
queue->txop = 0;
queue->aifs = 2;
queue->cw_min = 5;
queue->cw_max = 10;
}
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
enum data_queue_qid qid;
unsigned int req_atim =
!!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
/*
* We need the following queues:
* RX: 1
* TX: ops->tx_queues
* Beacon: 1
* Atim: 1 (if required)
*/
rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
if (!queue) {
ERROR(rt2x00dev, "Queue allocation failed.\n");
return -ENOMEM;
}
/*
* Initialize pointers
*/
rt2x00dev->rx = queue;
rt2x00dev->tx = &queue[1];
rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues];
/*
* Initialize queue parameters.
* RX: qid = QID_RX
* TX: qid = QID_AC_BE + index
* TX: cw_min: 2^5 = 32.
* TX: cw_max: 2^10 = 1024.
* BCN: qid = QID_BEACON
* ATIM: qid = QID_ATIM
*/
rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);
qid = QID_AC_BE;
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_init(rt2x00dev, queue, qid++);
rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[0], QID_BEACON);
if (req_atim)
rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[1], QID_ATIM);
return 0;
}
void rt2x00queue_free(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rx);
rt2x00dev->rx = NULL;
rt2x00dev->tx = NULL;
rt2x00dev->bcn = NULL;
}

View File

@@ -0,0 +1,639 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00
Abstract: rt2x00 queue datastructures and routines
*/
#ifndef RT2X00QUEUE_H
#define RT2X00QUEUE_H
#include <linux/prefetch.h>
/**
* DOC: Entry frame size
*
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of
* 2432 makes sense since it is big enough to contain the maximum fragment
* size according to the ieee802.11 specs.
* The aggregation size depends on support from the driver, but should
* be something around 3840 bytes.
*/
#define DATA_FRAME_SIZE 2432
#define MGMT_FRAME_SIZE 256
#define AGGREGATION_SIZE 3840
/**
* DOC: Number of entries per queue
*
* Under normal load without fragmentation, 12 entries are sufficient
* without the queue being filled up to the maximum. When using fragmentation
* and the queue threshold code, we need to add some additional margins to
* make sure the queue will never (or only under extreme load) fill up
* completely.
* Since we don't use preallocated DMA, having a large number of queue entries
* will have minimal impact on the memory requirements for the queue.
*/
#define RX_ENTRIES 24
#define TX_ENTRIES 24
#define BEACON_ENTRIES 1
#define ATIM_ENTRIES 8
/**
* enum data_queue_qid: Queue identification
*
* @QID_AC_BE: AC BE queue
* @QID_AC_BK: AC BK queue
* @QID_AC_VI: AC VI queue
* @QID_AC_VO: AC VO queue
* @QID_HCCA: HCCA queue
* @QID_MGMT: MGMT queue (prio queue)
* @QID_RX: RX queue
* @QID_OTHER: None of the above (don't use, only present for completeness)
* @QID_BEACON: Beacon queue (value unspecified, don't send it to device)
* @QID_ATIM: Atim queue (value unspeficied, don't send it to device)
*/
enum data_queue_qid {
QID_AC_BE = 0,
QID_AC_BK = 1,
QID_AC_VI = 2,
QID_AC_VO = 3,
QID_HCCA = 4,
QID_MGMT = 13,
QID_RX = 14,
QID_OTHER = 15,
QID_BEACON,
QID_ATIM,
};
/**
* enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
*
* @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX
* @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
* @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by
* mac80211 but was stripped for processing by the driver.
* @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
* the padded bytes are located between header and payload.
*/
enum skb_frame_desc_flags {
SKBDESC_DMA_MAPPED_RX = 1 << 0,
SKBDESC_DMA_MAPPED_TX = 1 << 1,
SKBDESC_IV_STRIPPED = 1 << 2,
SKBDESC_L2_PADDED = 1 << 3
};
/**
* struct skb_frame_desc: Descriptor information for the skb buffer
*
* This structure is placed over the driver_data array, this means that
* this structure should not exceed the size of that array (40 bytes).
*
* @flags: Frame flags, see &enum skb_frame_desc_flags.
* @desc_len: Length of the frame descriptor.
* @tx_rate_idx: the index of the TX rate, used for TX status reporting
* @tx_rate_flags: the TX rate flags, used for TX status reporting
* @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside
* of the scope of the skb->data pointer.
* @iv: IV/EIV data used during encryption/decryption.
* @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
* @entry: The entry to which this sk buffer belongs.
*/
struct skb_frame_desc {
u8 flags;
u8 desc_len;
u8 tx_rate_idx;
u8 tx_rate_flags;
void *desc;
__le32 iv[2];
dma_addr_t skb_dma;
struct queue_entry *entry;
};
/**
* get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff.
* @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc
*/
static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct skb_frame_desc) >
IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data;
}
/**
* enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc
*
* @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
* @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
* @RXDONE_SIGNAL_MCS: Signal field contains the mcs value.
* @RXDONE_MY_BSS: Does this frame originate from device's BSS.
* @RXDONE_CRYPTO_IV: Driver provided IV/EIV data.
* @RXDONE_CRYPTO_ICV: Driver provided ICV data.
* @RXDONE_L2PAD: 802.11 payload has been padded to 4-byte boundary.
*/
enum rxdone_entry_desc_flags {
RXDONE_SIGNAL_PLCP = BIT(0),
RXDONE_SIGNAL_BITRATE = BIT(1),
RXDONE_SIGNAL_MCS = BIT(2),
RXDONE_MY_BSS = BIT(3),
RXDONE_CRYPTO_IV = BIT(4),
RXDONE_CRYPTO_ICV = BIT(5),
RXDONE_L2PAD = BIT(6),
};
/**
* RXDONE_SIGNAL_MASK - Define to mask off all &rxdone_entry_desc_flags flags
* except for the RXDONE_SIGNAL_* flags. This is useful to convert the dev_flags
* from &rxdone_entry_desc to a signal value type.
*/
#define RXDONE_SIGNAL_MASK \
( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE | RXDONE_SIGNAL_MCS )
/**
* struct rxdone_entry_desc: RX Entry descriptor
*
* Summary of information that has been read from the RX frame descriptor.
*
* @timestamp: RX Timestamp
* @signal: Signal of the received frame.
* @rssi: RSSI of the received frame.
* @noise: Measured noise during frame reception.
* @size: Data size of the received frame.
* @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
* @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
* @rate_mode: Rate mode (See @enum rate_modulation).
* @cipher: Cipher type used during decryption.
* @cipher_status: Decryption status.
* @iv: IV/EIV data used during decryption.
* @icv: ICV data used during decryption.
*/
struct rxdone_entry_desc {
u64 timestamp;
int signal;
int rssi;
int noise;
int size;
int flags;
int dev_flags;
u16 rate_mode;
u8 cipher;
u8 cipher_status;
__le32 iv[2];
__le32 icv;
};
/**
* enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
*
* @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
* @TXDONE_SUCCESS: Frame was successfully send
* @TXDONE_FALLBACK: Frame was successfully send using a fallback rate.
* @TXDONE_FAILURE: Frame was not successfully send
* @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
* frame transmission failed due to excessive retries.
*/
enum txdone_entry_desc_flags {
TXDONE_UNKNOWN,
TXDONE_SUCCESS,
TXDONE_FALLBACK,
TXDONE_FAILURE,
TXDONE_EXCESSIVE_RETRY,
};
/**
* struct txdone_entry_desc: TX done entry descriptor
*
* Summary of information that has been read from the TX frame descriptor
* after the device is done with transmission.
*
* @flags: TX done flags (See &enum txdone_entry_desc_flags).
* @retry: Retry count.
*/
struct txdone_entry_desc {
unsigned long flags;
int retry;
};
/**
* enum txentry_desc_flags: Status flags for TX entry descriptor
*
* @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
* @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
* @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter.
* @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
* @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
* @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
* @ENTRY_TXD_BURST: This frame belongs to the same burst event.
* @ENTRY_TXD_ACK: An ACK is required for this frame.
* @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
* @ENTRY_TXD_ENCRYPT: This frame should be encrypted.
* @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared).
* @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware.
* @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware.
* @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU.
* @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth.
* @ENTRY_TXD_HT_SHORT_GI: Use short GI.
*/
enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
ENTRY_TXD_CTS_FRAME,
ENTRY_TXD_GENERATE_SEQ,
ENTRY_TXD_FIRST_FRAGMENT,
ENTRY_TXD_MORE_FRAG,
ENTRY_TXD_REQ_TIMESTAMP,
ENTRY_TXD_BURST,
ENTRY_TXD_ACK,
ENTRY_TXD_RETRY_MODE,
ENTRY_TXD_ENCRYPT,
ENTRY_TXD_ENCRYPT_PAIRWISE,
ENTRY_TXD_ENCRYPT_IV,
ENTRY_TXD_ENCRYPT_MMIC,
ENTRY_TXD_HT_AMPDU,
ENTRY_TXD_HT_BW_40,
ENTRY_TXD_HT_SHORT_GI,
};
/**
* struct txentry_desc: TX Entry descriptor
*
* Summary of information for the frame descriptor before sending a TX frame.
*
* @flags: Descriptor flags (See &enum queue_entry_flags).
* @queue: Queue identification (See &enum data_queue_qid).
* @header_length: Length of 802.11 header.
* @l2pad: Amount of padding to align 802.11 payload to 4-byte boundrary.
* @length_high: PLCP length high word.
* @length_low: PLCP length low word.
* @signal: PLCP signal.
* @service: PLCP service.
* @msc: MCS.
* @stbc: STBC.
* @ba_size: BA size.
* @rate_mode: Rate mode (See @enum rate_modulation).
* @mpdu_density: MDPU density.
* @retry_limit: Max number of retries.
* @aifs: AIFS value.
* @ifs: IFS value.
* @cw_min: cwmin value.
* @cw_max: cwmax value.
* @cipher: Cipher type used for encryption.
* @key_idx: Key index used for encryption.
* @iv_offset: Position where IV should be inserted by hardware.
* @iv_len: Length of IV data.
*/
struct txentry_desc {
unsigned long flags;
enum data_queue_qid queue;
u16 header_length;
u16 l2pad;
u16 length_high;
u16 length_low;
u16 signal;
u16 service;
u16 mcs;
u16 stbc;
u16 ba_size;
u16 rate_mode;
u16 mpdu_density;
short retry_limit;
short aifs;
short ifs;
short cw_min;
short cw_max;
enum cipher cipher;
u16 key_idx;
u16 iv_offset;
u16 iv_len;
};
/**
* enum queue_entry_flags: Status flags for queue entry
*
* @ENTRY_BCN_ASSIGNED: This entry has been assigned to an interface.
* As long as this bit is set, this entry may only be touched
* through the interface structure.
* @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data
* transfer (either TX or RX depending on the queue). The entry should
* only be touched after the device has signaled it is done with it.
* @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data
* encryption or decryption. The entry should only be touched after
* the device has signaled it is done with it.
* @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
* for the signal to start sending.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_OWNER_DEVICE_CRYPTO,
ENTRY_DATA_PENDING,
};
/**
* struct queue_entry: Entry inside the &struct data_queue
*
* @flags: Entry flags, see &enum queue_entry_flags.
* @queue: The data queue (&struct data_queue) to which this entry belongs.
* @skb: The buffer which is currently being transmitted (for TX queue),
* or used to directly recieve data in (for RX queue).
* @entry_idx: The entry index number.
* @priv_data: Private data belonging to this queue entry. The pointer
* points to data specific to a particular driver and queue type.
*/
struct queue_entry {
unsigned long flags;
struct data_queue *queue;
struct sk_buff *skb;
unsigned int entry_idx;
void *priv_data;
};
/**
* enum queue_index: Queue index type
*
* @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
* owned by the hardware then the queue is considered to be full.
* @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
* the hardware and for which we need to run the txdone handler. If this
* entry is not owned by the hardware the queue is considered to be empty.
* @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription
* will be completed by the hardware next.
* @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size
* of the index array.
*/
enum queue_index {
Q_INDEX,
Q_INDEX_DONE,
Q_INDEX_CRYPTO,
Q_INDEX_MAX,
};
/**
* struct data_queue: Data queue
*
* @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to.
* @entries: Base address of the &struct queue_entry which are
* part of this queue.
* @qid: The queue identification, see &enum data_queue_qid.
* @lock: Spinlock to protect index handling. Whenever @index, @index_done or
* @index_crypt needs to be changed this lock should be grabbed to prevent
* index corruption due to concurrency.
* @count: Number of frames handled in the queue.
* @limit: Maximum number of entries in the queue.
* @threshold: Minimum number of free entries before queue is kicked by force.
* @length: Number of frames in queue.
* @index: Index pointers to entry positions in the queue,
* use &enum queue_index to get a specific index field.
* @txop: maximum burst time.
* @aifs: The aifs value for outgoing frames (field ignored in RX queue).
* @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
* @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
* @data_size: Maximum data size for the frames in this queue.
* @desc_size: Hardware descriptor size for the data in this queue.
* @usb_endpoint: Device endpoint used for communication (USB only)
* @usb_maxpacket: Max packet size for given endpoint (USB only)
*/
struct data_queue {
struct rt2x00_dev *rt2x00dev;
struct queue_entry *entries;
enum data_queue_qid qid;
spinlock_t lock;
unsigned int count;
unsigned short limit;
unsigned short threshold;
unsigned short length;
unsigned short index[Q_INDEX_MAX];
unsigned short txop;
unsigned short aifs;
unsigned short cw_min;
unsigned short cw_max;
unsigned short data_size;
unsigned short desc_size;
unsigned short usb_endpoint;
unsigned short usb_maxpacket;
};
/**
* struct data_queue_desc: Data queue description
*
* The information in this structure is used by drivers
* to inform rt2x00lib about the creation of the data queue.
*
* @entry_num: Maximum number of entries for a queue.
* @data_size: Maximum data size for the frames in this queue.
* @desc_size: Hardware descriptor size for the data in this queue.
* @priv_size: Size of per-queue_entry private data.
*/
struct data_queue_desc {
unsigned short entry_num;
unsigned short data_size;
unsigned short desc_size;
unsigned short priv_size;
};
/**
* queue_end - Return pointer to the last queue (HELPER MACRO).
* @__dev: Pointer to &struct rt2x00_dev
*
* Using the base rx pointer and the maximum number of available queues,
* this macro will return the address of 1 position beyond the end of the
* queues array.
*/
#define queue_end(__dev) \
&(__dev)->rx[(__dev)->data_queues]
/**
* tx_queue_end - Return pointer to the last TX queue (HELPER MACRO).
* @__dev: Pointer to &struct rt2x00_dev
*
* Using the base tx pointer and the maximum number of available TX
* queues, this macro will return the address of 1 position beyond
* the end of the TX queue array.
*/
#define tx_queue_end(__dev) \
&(__dev)->tx[(__dev)->ops->tx_queues]
/**
* queue_next - Return pointer to next queue in list (HELPER MACRO).
* @__queue: Current queue for which we need the next queue
*
* Using the current queue address we take the address directly
* after the queue to take the next queue. Note that this macro
* should be used carefully since it does not protect against
* moving past the end of the list. (See macros &queue_end and
* &tx_queue_end for determining the end of the queue).
*/
#define queue_next(__queue) \
&(__queue)[1]
/**
* queue_loop - Loop through the queues within a specific range (HELPER MACRO).
* @__entry: Pointer where the current queue entry will be stored in.
* @__start: Start queue pointer.
* @__end: End queue pointer.
*
* This macro will loop through all queues between &__start and &__end.
*/
#define queue_loop(__entry, __start, __end) \
for ((__entry) = (__start); \
prefetch(queue_next(__entry)), (__entry) != (__end);\
(__entry) = queue_next(__entry))
/**
* queue_for_each - Loop through all queues
* @__dev: Pointer to &struct rt2x00_dev
* @__entry: Pointer where the current queue entry will be stored in.
*
* This macro will loop through all available queues.
*/
#define queue_for_each(__dev, __entry) \
queue_loop(__entry, (__dev)->rx, queue_end(__dev))
/**
* tx_queue_for_each - Loop through the TX queues
* @__dev: Pointer to &struct rt2x00_dev
* @__entry: Pointer where the current queue entry will be stored in.
*
* This macro will loop through all TX related queues excluding
* the Beacon and Atim queues.
*/
#define tx_queue_for_each(__dev, __entry) \
queue_loop(__entry, (__dev)->tx, tx_queue_end(__dev))
/**
* txall_queue_for_each - Loop through all TX related queues
* @__dev: Pointer to &struct rt2x00_dev
* @__entry: Pointer where the current queue entry will be stored in.
*
* This macro will loop through all TX related queues including
* the Beacon and Atim queues.
*/
#define txall_queue_for_each(__dev, __entry) \
queue_loop(__entry, (__dev)->tx, queue_end(__dev))
/**
* rt2x00queue_empty - Check if the queue is empty.
* @queue: Queue to check if empty.
*/
static inline int rt2x00queue_empty(struct data_queue *queue)
{
return queue->length == 0;
}
/**
* rt2x00queue_full - Check if the queue is full.
* @queue: Queue to check if full.
*/
static inline int rt2x00queue_full(struct data_queue *queue)
{
return queue->length == queue->limit;
}
/**
* rt2x00queue_free - Check the number of available entries in queue.
* @queue: Queue to check.
*/
static inline int rt2x00queue_available(struct data_queue *queue)
{
return queue->limit - queue->length;
}
/**
* rt2x00queue_threshold - Check if the queue is below threshold
* @queue: Queue to check.
*/
static inline int rt2x00queue_threshold(struct data_queue *queue)
{
return rt2x00queue_available(queue) < queue->threshold;
}
/**
* _rt2x00_desc_read - Read a word from the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
* @value: Address where the descriptor value should be written into.
*/
static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value)
{
*value = desc[word];
}
/**
* rt2x00_desc_read - Read a word from the hardware descriptor, this
* function will take care of the byte ordering.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
* @value: Address where the descriptor value should be written into.
*/
static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value)
{
__le32 tmp;
_rt2x00_desc_read(desc, word, &tmp);
*value = le32_to_cpu(tmp);
}
/**
* rt2x00_desc_write - write a word to the hardware descriptor, this
* function will take care of the byte ordering.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be written.
* @value: Value that should be written into the descriptor.
*/
static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value)
{
desc[word] = value;
}
/**
* rt2x00_desc_write - write a word to the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be written.
* @value: Value that should be written into the descriptor.
*/
static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value)
{
_rt2x00_desc_write(desc, word, cpu_to_le32(value));
}
#endif /* RT2X00QUEUE_H */

View File

@@ -0,0 +1,272 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00
Abstract: rt2x00 generic register information.
*/
#ifndef RT2X00REG_H
#define RT2X00REG_H
/*
* RX crypto status
*/
enum rx_crypto {
RX_CRYPTO_SUCCESS = 0,
RX_CRYPTO_FAIL_ICV = 1,
RX_CRYPTO_FAIL_MIC = 2,
RX_CRYPTO_FAIL_KEY = 3,
};
/*
* Antenna values
*/
enum antenna {
ANTENNA_SW_DIVERSITY = 0,
ANTENNA_A = 1,
ANTENNA_B = 2,
ANTENNA_HW_DIVERSITY = 3,
};
/*
* Led mode values.
*/
enum led_mode {
LED_MODE_DEFAULT = 0,
LED_MODE_TXRX_ACTIVITY = 1,
LED_MODE_SIGNAL_STRENGTH = 2,
LED_MODE_ASUS = 3,
LED_MODE_ALPHA = 4,
};
/*
* TSF sync values
*/
enum tsf_sync {
TSF_SYNC_NONE = 0,
TSF_SYNC_INFRA = 1,
TSF_SYNC_BEACON = 2,
};
/*
* Device states
*/
enum dev_state {
STATE_DEEP_SLEEP = 0,
STATE_SLEEP = 1,
STATE_STANDBY = 2,
STATE_AWAKE = 3,
/*
* Additional device states, these values are
* not strict since they are not directly passed
* into the device.
*/
STATE_RADIO_ON,
STATE_RADIO_OFF,
STATE_RADIO_RX_ON,
STATE_RADIO_RX_OFF,
STATE_RADIO_RX_ON_LINK,
STATE_RADIO_RX_OFF_LINK,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
};
/*
* IFS backoff values
*/
enum ifs {
IFS_BACKOFF = 0,
IFS_SIFS = 1,
IFS_NEW_BACKOFF = 2,
IFS_NONE = 3,
};
/*
* Cipher types for hardware encryption
*/
enum cipher {
CIPHER_NONE = 0,
CIPHER_WEP64 = 1,
CIPHER_WEP128 = 2,
CIPHER_TKIP = 3,
CIPHER_AES = 4,
/*
* The following fields were added by rt61pci and rt73usb.
*/
CIPHER_CKIP64 = 5,
CIPHER_CKIP128 = 6,
CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */
/*
* Max cipher type.
* Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128
* are excluded due to limitations in mac80211.
*/
CIPHER_MAX = 4,
};
/*
* Rate modulations
*/
enum rate_modulation {
RATE_MODE_CCK = 0,
RATE_MODE_OFDM = 1,
RATE_MODE_HT_MIX = 2,
RATE_MODE_HT_GREENFIELD = 3,
};
/*
* Firmware validation error codes
*/
enum firmware_errors {
FW_OK,
FW_BAD_CRC,
FW_BAD_LENGTH,
FW_BAD_VERSION,
};
/*
* Register handlers.
* We store the position of a register field inside a field structure,
* This will simplify the process of setting and reading a certain field
* inside the register while making sure the process remains byte order safe.
*/
struct rt2x00_field8 {
u8 bit_offset;
u8 bit_mask;
};
struct rt2x00_field16 {
u16 bit_offset;
u16 bit_mask;
};
struct rt2x00_field32 {
u32 bit_offset;
u32 bit_mask;
};
/*
* Power of two check, this will check
* if the mask that has been given contains and contiguous set of bits.
* Note that we cannot use the is_power_of_2() function since this
* check must be done at compile-time.
*/
#define is_power_of_two(x) ( !((x) & ((x)-1)) )
#define low_bit_mask(x) ( ((x)-1) & ~(x) )
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
* Macros to find first set bit in a variable.
* These macros behave the same as the __ffs() functions but
* the most important difference that this is done during
* compile-time rather then run-time.
*/
#define compile_ffs2(__x) \
__builtin_choose_expr(((__x) & 0x1), 0, 1)
#define compile_ffs4(__x) \
__builtin_choose_expr(((__x) & 0x3), \
(compile_ffs2((__x))), \
(compile_ffs2((__x) >> 2) + 2))
#define compile_ffs8(__x) \
__builtin_choose_expr(((__x) & 0xf), \
(compile_ffs4((__x))), \
(compile_ffs4((__x) >> 4) + 4))
#define compile_ffs16(__x) \
__builtin_choose_expr(((__x) & 0xff), \
(compile_ffs8((__x))), \
(compile_ffs8((__x) >> 8) + 8))
#define compile_ffs32(__x) \
__builtin_choose_expr(((__x) & 0xffff), \
(compile_ffs16((__x))), \
(compile_ffs16((__x) >> 16) + 16))
/*
* This macro will check the requirements for the FIELD{8,16,32} macros
* The mask should be a constant non-zero contiguous set of bits which
* does not exceed the given typelimit.
*/
#define FIELD_CHECK(__mask, __type) \
BUILD_BUG_ON(!(__mask) || \
!is_valid_mask(__mask) || \
(__mask) != (__type)(__mask)) \
#define FIELD8(__mask) \
({ \
FIELD_CHECK(__mask, u8); \
(struct rt2x00_field8) { \
compile_ffs8(__mask), (__mask) \
}; \
})
#define FIELD16(__mask) \
({ \
FIELD_CHECK(__mask, u16); \
(struct rt2x00_field16) { \
compile_ffs16(__mask), (__mask) \
}; \
})
#define FIELD32(__mask) \
({ \
FIELD_CHECK(__mask, u32); \
(struct rt2x00_field32) { \
compile_ffs32(__mask), (__mask) \
}; \
})
#define SET_FIELD(__reg, __type, __field, __value)\
({ \
typecheck(__type, __field); \
*(__reg) &= ~((__field).bit_mask); \
*(__reg) |= ((__value) << \
((__field).bit_offset)) & \
((__field).bit_mask); \
})
#define GET_FIELD(__reg, __type, __field) \
({ \
typecheck(__type, __field); \
((__reg) & ((__field).bit_mask)) >> \
((__field).bit_offset); \
})
#define rt2x00_set_field32(__reg, __field, __value) \
SET_FIELD(__reg, struct rt2x00_field32, __field, __value)
#define rt2x00_get_field32(__reg, __field) \
GET_FIELD(__reg, struct rt2x00_field32, __field)
#define rt2x00_set_field16(__reg, __field, __value) \
SET_FIELD(__reg, struct rt2x00_field16, __field, __value)
#define rt2x00_get_field16(__reg, __field) \
GET_FIELD(__reg, struct rt2x00_field16, __field)
#define rt2x00_set_field8(__reg, __field, __value) \
SET_FIELD(__reg, struct rt2x00_field8, __field, __value)
#define rt2x00_get_field8(__reg, __field) \
GET_FIELD(__reg, struct rt2x00_field8, __field)
#endif /* RT2X00REG_H */

View File

@@ -0,0 +1,739 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00usb
Abstract: rt2x00 generic usb device routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/bug.h>
#include "rt2x00.h"
#include "rt2x00usb.h"
/*
* Interfacing with the HW.
*/
int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, const u16 value,
void *buffer, const u16 buffer_length,
const int timeout)
{
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
int status;
unsigned int i;
unsigned int pipe =
(requesttype == USB_VENDOR_REQUEST_IN) ?
usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return -ENODEV;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
status = usb_control_msg(usb_dev, pipe, request, requesttype,
value, offset, buffer, buffer_length,
timeout);
if (status >= 0)
return 0;
/*
* Check for errors
* -ENODEV: Device has disappeared, no point continuing.
* All other errors: Try again.
*/
else if (status == -ENODEV) {
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
break;
}
}
ERROR(rt2x00dev,
"Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n",
request, offset, status);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout)
{
int status;
BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex));
/*
* Check for Cache availability.
*/
if (unlikely(!rt2x00dev->csr.cache || buffer_length > CSR_CACHE_SIZE)) {
ERROR(rt2x00dev, "CSR cache not available.\n");
return -ENOMEM;
}
if (requesttype == USB_VENDOR_REQUEST_OUT)
memcpy(rt2x00dev->csr.cache, buffer, buffer_length);
status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype,
offset, 0, rt2x00dev->csr.cache,
buffer_length, timeout);
if (!status && requesttype == USB_VENDOR_REQUEST_IN)
memcpy(buffer, rt2x00dev->csr.cache, buffer_length);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_req_buff_lock);
int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout)
{
int status;
mutex_lock(&rt2x00dev->csr_mutex);
status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
requesttype, offset, buffer,
buffer_length, timeout);
mutex_unlock(&rt2x00dev->csr_mutex);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, const void *buffer,
const u16 buffer_length,
const int timeout)
{
int status = 0;
unsigned char *tb;
u16 off, len, bsize;
mutex_lock(&rt2x00dev->csr_mutex);
tb = (char *)buffer;
off = offset;
len = buffer_length;
while (len && !status) {
bsize = min_t(u16, CSR_CACHE_SIZE, len);
status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
requesttype, off, tb,
bsize, timeout);
tb += bsize;
len -= bsize;
off += bsize;
}
mutex_unlock(&rt2x00dev->csr_mutex);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
struct rt2x00_field32 field,
u32 *reg)
{
unsigned int i;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return -ENODEV;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2x00usb_register_read_lock(rt2x00dev, offset, reg);
if (!rt2x00_get_field32(*reg, field))
return 1;
udelay(REGISTER_BUSY_DELAY);
}
ERROR(rt2x00dev, "Indirect register access failed: "
"offset=0x%.08x, value=0x%.08x\n", offset, *reg);
*reg = ~0;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
/*
* TX data handlers.
*/
static void rt2x00usb_interrupt_txdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct txdone_entry_desc txdesc;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
* Obtain the status about this packet.
* Note that when the status is 0 it does not mean the
* frame was send out correctly. It only means the frame
* was succesfully pushed to the hardware, we have no
* way to determine the transmission status right now.
* (Only indirectly by looking at the failed TX counters
* in the register).
*/
txdesc.flags = 0;
if (!urb->status)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
else
__set_bit(TXDONE_FAILURE, &txdesc.flags);
txdesc.retry = 0;
rt2x00lib_txdone(entry, &txdesc);
}
int rt2x00usb_write_tx_data(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc;
u32 length;
/*
* Add the descriptor in front of the skb.
*/
skb_push(entry->skb, entry->queue->desc_size);
memset(entry->skb->data, 0, entry->queue->desc_size);
/*
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->desc = entry->skb->data;
skbdesc->desc_len = entry->queue->desc_size;
/*
* USB devices cannot blindly pass the skb->len as the
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
*/
length = rt2x00dev->ops->lib->get_tx_data_len(entry);
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
/*
* Make sure the skb->data pointer points to the frame, not the
* descriptor.
*/
skb_pull(entry->skb, entry->queue->desc_size);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
}
void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid qid)
{
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
unsigned long irqflags;
unsigned int index;
unsigned int index_done;
unsigned int i;
/*
* Only protect the range we are going to loop over,
* if during our loop a extra entry is set to pending
* it should not be kicked during this run, since it
* is part of another TX operation.
*/
spin_lock_irqsave(&queue->lock, irqflags);
index = queue->index[Q_INDEX];
index_done = queue->index[Q_INDEX_DONE];
spin_unlock_irqrestore(&queue->lock, irqflags);
/*
* Start from the TX done pointer, this guarentees that we will
* send out all frames in the correct order.
*/
if (index_done < index) {
for (i = index_done; i < index; i++)
rt2x00usb_kick_tx_entry(&queue->entries[i]);
} else {
for (i = index_done; i < queue->limit; i++)
rt2x00usb_kick_tx_entry(&queue->entries[i]);
for (i = 0; i < index; i++)
rt2x00usb_kick_tx_entry(&queue->entries[i]);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid qid)
{
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
bool kill_guard;
/*
* When killing the beacon queue, we must also kill
* the beacon guard byte.
*/
kill_guard =
(qid == QID_BEACON) &&
(test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags));
/*
* Cancel all entries.
*/
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
usb_kill_urb(entry_priv->urb);
/*
* Kill guardian urb (if required by driver).
*/
if (kill_guard) {
bcn_priv = queue->entries[i].priv_data;
usb_kill_urb(bcn_priv->guardian_urb);
}
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
/*
* RX data handlers.
*/
static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u8 rxd[32];
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
* Check if the received data is simply too small
* to be actually valid, or if the urb is signaling
* a problem.
*/
if (urb->actual_length < entry->queue->desc_size || urb->status) {
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(urb, GFP_ATOMIC);
return;
}
/*
* Fill in desc fields of the skb descriptor
*/
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;
/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(rt2x00dev, entry);
}
/*
* Radio handlers
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
/*
* The USB version of kill_tx_queue also works
* on the RX queue.
*/
rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
/*
* Device initialization handlers.
*/
void rt2x00usb_clear_entry(struct queue_entry *entry)
{
struct usb_device *usb_dev =
to_usb_device_intf(entry->queue->rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int pipe;
if (entry->queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry);
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
} else {
entry->flags = 0;
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
static void rt2x00usb_assign_endpoint(struct data_queue *queue,
struct usb_endpoint_descriptor *ep_desc)
{
struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
int pipe;
queue->usb_endpoint = usb_endpoint_num(ep_desc);
if (queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
} else {
pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
}
if (!queue->usb_maxpacket)
queue->usb_maxpacket = 1;
}
static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
{
struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
struct usb_host_interface *intf_desc = intf->cur_altsetting;
struct usb_endpoint_descriptor *ep_desc;
struct data_queue *queue = rt2x00dev->tx;
struct usb_endpoint_descriptor *tx_ep_desc = NULL;
unsigned int i;
/*
* Walk through all available endpoints to search for "bulk in"
* and "bulk out" endpoints. When we find such endpoints collect
* the information we need from the descriptor and assign it
* to the queue.
*/
for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
ep_desc = &intf_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(ep_desc)) {
rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
} else if (usb_endpoint_is_bulk_out(ep_desc) &&
(queue != queue_end(rt2x00dev))) {
rt2x00usb_assign_endpoint(queue, ep_desc);
queue = queue_next(queue);
tx_ep_desc = ep_desc;
}
}
/*
* At least 1 endpoint for RX and 1 endpoint for TX must be available.
*/
if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
return -EPIPE;
}
/*
* It might be possible not all queues have a dedicated endpoint.
* Loop through all TX queues and copy the endpoint information
* which we have gathered from already assigned endpoints.
*/
txall_queue_for_each(rt2x00dev, queue) {
if (!queue->usb_endpoint)
rt2x00usb_assign_endpoint(queue, tx_ep_desc);
}
return 0;
}
static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!entry_priv->urb)
return -ENOMEM;
}
/*
* If this is not the beacon queue or
* no guardian byte was required for the beacon,
* then we are done.
*/
if (rt2x00dev->bcn != queue ||
!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
return 0;
for (i = 0; i < queue->limit; i++) {
bcn_priv = queue->entries[i].priv_data;
bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!bcn_priv->guardian_urb)
return -ENOMEM;
}
return 0;
}
static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
if (!queue->entries)
return;
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
usb_kill_urb(entry_priv->urb);
usb_free_urb(entry_priv->urb);
}
/*
* If this is not the beacon queue or
* no guardian byte was required for the beacon,
* then we are done.
*/
if (rt2x00dev->bcn != queue ||
!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
return;
for (i = 0; i < queue->limit; i++) {
bcn_priv = queue->entries[i].priv_data;
usb_kill_urb(bcn_priv->guardian_urb);
usb_free_urb(bcn_priv->guardian_urb);
}
}
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
int status;
/*
* Find endpoints for each queue
*/
status = rt2x00usb_find_endpoints(rt2x00dev);
if (status)
goto exit;
/*
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
status = rt2x00usb_alloc_urb(rt2x00dev, queue);
if (status)
goto exit;
}
return 0;
exit:
rt2x00usb_uninitialize(rt2x00dev);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_initialize);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
queue_for_each(rt2x00dev, queue)
rt2x00usb_free_urb(rt2x00dev, queue);
}
EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
/*
* USB driver handlers.
*/
static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rf);
rt2x00dev->rf = NULL;
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
kfree(rt2x00dev->csr.cache);
rt2x00dev->csr.cache = NULL;
}
static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
rt2x00dev->csr.cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
if (!rt2x00dev->csr.cache)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
if (!rt2x00dev->eeprom)
goto exit;
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
if (!rt2x00dev->rf)
goto exit;
return 0;
exit:
ERROR_PROBE("Failed to allocate registers.\n");
rt2x00usb_free_reg(rt2x00dev);
return -ENOMEM;
}
int rt2x00usb_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
usb_dev = usb_get_dev(usb_dev);
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
ERROR_PROBE("Failed to allocate hardware.\n");
retval = -ENOMEM;
goto exit_put_device;
}
usb_set_intfdata(usb_intf, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = &usb_intf->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
goto exit_free_reg;
return 0;
exit_free_reg:
rt2x00usb_free_reg(rt2x00dev);
exit_free_device:
ieee80211_free_hw(hw);
exit_put_device:
usb_put_dev(usb_dev);
usb_set_intfdata(usb_intf, NULL);
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00usb_probe);
void rt2x00usb_disconnect(struct usb_interface *usb_intf)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
rt2x00usb_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
/*
* Free the USB device data.
*/
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
}
EXPORT_SYMBOL_GPL(rt2x00usb_disconnect);
#ifdef CONFIG_PM
int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
int retval;
retval = rt2x00lib_suspend(rt2x00dev, state);
if (retval)
return retval;
/*
* Decrease usbdev refcount.
*/
usb_put_dev(interface_to_usbdev(usb_intf));
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
int rt2x00usb_resume(struct usb_interface *usb_intf)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
usb_get_dev(interface_to_usbdev(usb_intf));
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00usb_resume);
#endif /* CONFIG_PM */
/*
* rt2x00usb module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2x00 usb library");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,454 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00usb
Abstract: Data structures for the rt2x00usb module.
*/
#ifndef RT2X00USB_H
#define RT2X00USB_H
#define to_usb_device_intf(d) \
({ \
struct usb_interface *intf = to_usb_interface(d); \
interface_to_usbdev(intf); \
})
/*
* This variable should be used with the
* usb_driver structure initialization.
*/
#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
/*
* Register defines.
* Some registers require multiple attempts before success,
* in those cases REGISTER_BUSY_COUNT attempts should be
* taken with a REGISTER_BUSY_DELAY interval.
* For USB vendor requests we need to pass a timeout
* time in ms, for this we use the REGISTER_TIMEOUT,
* however when loading firmware a higher value is
* required. In that case we use the REGISTER_TIMEOUT_FIRMWARE.
*/
#define REGISTER_BUSY_COUNT 5
#define REGISTER_BUSY_DELAY 100
#define REGISTER_TIMEOUT 500
#define REGISTER_TIMEOUT_FIRMWARE 1000
/**
* REGISTER_TIMEOUT16 - Determine the timeout for 16bit register access
* @__datalen: Data length
*/
#define REGISTER_TIMEOUT16(__datalen) \
( REGISTER_TIMEOUT * ((__datalen) / sizeof(u16)) )
/**
* REGISTER_TIMEOUT32 - Determine the timeout for 32bit register access
* @__datalen: Data length
*/
#define REGISTER_TIMEOUT32(__datalen) \
( REGISTER_TIMEOUT * ((__datalen) / sizeof(u32)) )
/*
* Cache size
*/
#define CSR_CACHE_SIZE 64
/*
* USB request types.
*/
#define USB_VENDOR_REQUEST ( USB_TYPE_VENDOR | USB_RECIP_DEVICE )
#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST )
#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST )
/**
* enum rt2x00usb_vendor_request: USB vendor commands.
*/
enum rt2x00usb_vendor_request {
USB_DEVICE_MODE = 1,
USB_SINGLE_WRITE = 2,
USB_SINGLE_READ = 3,
USB_MULTI_WRITE = 6,
USB_MULTI_READ = 7,
USB_EEPROM_WRITE = 8,
USB_EEPROM_READ = 9,
USB_LED_CONTROL = 10, /* RT73USB */
USB_RX_CONTROL = 12,
};
/**
* enum rt2x00usb_mode_offset: Device modes offset.
*/
enum rt2x00usb_mode_offset {
USB_MODE_RESET = 1,
USB_MODE_UNPLUG = 2,
USB_MODE_FUNCTION = 3,
USB_MODE_TEST = 4,
USB_MODE_SLEEP = 7, /* RT73USB */
USB_MODE_FIRMWARE = 8, /* RT73USB */
USB_MODE_WAKEUP = 9, /* RT73USB */
};
/**
* rt2x00usb_vendor_request - Send register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register offset to perform action on
* @value: Value to write to device
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
* @timeout: Operation timeout
*
* This is the main function to communicate with the device,
* the &buffer argument _must_ either be NULL or point to
* a buffer allocated by kmalloc. Failure to do so can lead
* to unexpected behavior depending on the architecture.
*/
int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, const u16 value,
void *buffer, const u16 buffer_length,
const int timeout);
/**
* rt2x00usb_vendor_request_buff - Send register command to device (buffered)
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register offset to perform action on
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
* @timeout: Operation timeout
*
* This function will use a previously with kmalloc allocated cache
* to communicate with the device. The contents of the buffer pointer
* will be copied to this cache when writing, or read from the cache
* when reading.
* Buffers send to &rt2x00usb_vendor_request _must_ be allocated with
* kmalloc. Hence the reason for using a previously allocated cache
* which has been allocated properly.
*/
int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout);
/**
* rt2x00usb_vendor_request_buff - Send register command to device (buffered)
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register offset to perform action on
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
* @timeout: Operation timeout
*
* A version of &rt2x00usb_vendor_request_buff which must be called
* if the usb_cache_mutex is already held.
*/
int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout);
/**
* rt2x00usb_vendor_request_large_buff - Send register command to device (buffered)
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register start offset to perform action on
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
* @timeout: Operation timeout
*
* This function is used to transfer register data in blocks larger
* then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons.
*/
int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, const void *buffer,
const u16 buffer_length,
const int timeout);
/**
* rt2x00usb_vendor_request_sw - Send single register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @offset: Register offset to perform action on
* @value: Value to write to device
* @timeout: Operation timeout
*
* Simple wrapper around rt2x00usb_vendor_request to write a single
* command to the device. Since we don't use the buffer argument we
* don't have to worry about kmalloc here.
*/
static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev,
const u8 request,
const u16 offset,
const u16 value,
const int timeout)
{
return rt2x00usb_vendor_request(rt2x00dev, request,
USB_VENDOR_REQUEST_OUT, offset,
value, NULL, 0, timeout);
}
/**
* rt2x00usb_eeprom_read - Read eeprom from device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @eeprom: Pointer to eeprom array to store the information in
* @length: Number of bytes to read from the eeprom
*
* Simple wrapper around rt2x00usb_vendor_request to read the eeprom
* from the device. Note that the eeprom argument _must_ be allocated using
* kmalloc for correct handling inside the kernel USB layer.
*/
static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
__le16 *eeprom, const u16 length)
{
return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
USB_VENDOR_REQUEST_IN, 0, 0,
eeprom, length,
REGISTER_TIMEOUT16(length));
}
/**
* rt2x00usb_regbusy_read - Read 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Pointer to where register contents should be stored
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
__le32 reg;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
&reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le32_to_cpu(reg);
}
/**
* rt2x00usb_register_read_lock - Read 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Pointer to where register contents should be stored
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_req_buff_lock().
*/
static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
__le32 reg;
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
&reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le32_to_cpu(reg);
}
/**
* rt2x00usb_register_multiread - Read 32bit register words
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Pointer to where register contents should be stored
* @length: Length of the data
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
value, length,
REGISTER_TIMEOUT32(length));
}
/**
* rt2x00usb_register_write - Write 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Data which should be written
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
__le32 reg = cpu_to_le32(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
&reg, sizeof(reg), REGISTER_TIMEOUT);
}
/**
* rt2x00usb_register_write_lock - Write 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Data which should be written
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_req_buff_lock().
*/
static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
__le32 reg = cpu_to_le32(value);
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
&reg, sizeof(reg), REGISTER_TIMEOUT);
}
/**
* rt2x00usb_register_multiwrite - Write 32bit register words
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Data which should be written
* @length: Length of the data
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
value, length,
REGISTER_TIMEOUT32(length));
}
/**
* rt2x00usb_regbusy_read - Read from register with busy check
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @field: Field to check if register is busy
* @reg: Pointer to where register contents should be stored
*
* This function will read the given register, and checks if the
* register is busy. If it is, it will sleep for a couple of
* microseconds before reading the register again. If the register
* is not read after a certain timeout, this function will return
* FALSE.
*/
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
struct rt2x00_field32 field,
u32 *reg);
/*
* Radio handlers
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00usb_write_tx_data - Initialize URB for TX operation
* @entry: The entry where the frame is located
*
* This function will initialize the URB and skb descriptor
* to prepare the entry for the actual TX operation.
*/
int rt2x00usb_write_tx_data(struct queue_entry *entry);
/**
* struct queue_entry_priv_usb: Per entry USB specific information
*
* @urb: Urb structure used for device communication.
*/
struct queue_entry_priv_usb {
struct urb *urb;
};
/**
* struct queue_entry_priv_usb_bcn: Per TX entry USB specific information
*
* The first section should match &struct queue_entry_priv_usb exactly.
* rt2500usb can use this structure to send a guardian byte when working
* with beacons.
*
* @urb: Urb structure used for device communication.
* @guardian_data: Set to 0, used for sending the guardian data.
* @guardian_urb: Urb structure used to send the guardian data.
*/
struct queue_entry_priv_usb_bcn {
struct urb *urb;
unsigned int guardian_data;
struct urb *guardian_urb;
};
/**
* rt2x00usb_kick_tx_queue - Kick data queue
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @qid: Data queue to kick
*
* This will walk through all entries of the queue and push all pending
* frames to the hardware as a single burst.
*/
void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid qid);
/**
* rt2x00usb_kill_tx_queue - Kill data queue
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @qid: Data queue to kill
*
* This will walk through all entries of the queue and kill all
* previously kicked frames before they can be send.
*/
void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid qid);
/*
* Device initialization handlers.
*/
void rt2x00usb_clear_entry(struct queue_entry *entry);
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
/*
* USB driver handlers.
*/
int rt2x00usb_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id);
void rt2x00usb_disconnect(struct usb_interface *usb_intf);
#ifdef CONFIG_PM
int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
int rt2x00usb_resume(struct usb_interface *usb_intf);
#else
#define rt2x00usb_suspend NULL
#define rt2x00usb_resume NULL
#endif /* CONFIG_PM */
#endif /* RT2X00USB_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff