rt2x00pci.h
linux_drivers/rt2x00-2.0.0-b3/rt2x00pci.h
/*
Copyright (C) 2004 - 2005 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 and registers for the rt2x00 pci modules.
Supported chipsets: RT2460 & RT2560.
*/
#ifndef RT2X00PCI_H
#define RT2X00PCI_H
/*
* PCI data structure.
*/
/*
* Ring handlers.
*/
static inline int
rt2x00_pci_alloc_ring(
struct _rt2x00_device *device,
struct _data_ring *ring,
const u8 ring_type,
const u16 max_entries,
const u16 entry_size,
const u16 desc_size)
{
struct _rt2x00_pci *rt2x00pci = rt2x00_priv(device);
rt2x00_init_ring(device, ring, ring_type, max_entries, entry_size, desc_size);
ring->data_addr = dma_alloc_coherent(&rt2x00pci->pci_dev->dev, ring->mem_size, &ring->data_dma, GFP_KERNEL);
if(!ring->data_addr)
return -ENOMEM;
memset(ring->data_addr, 0x00, ring->mem_size);
return 0;
}
static int
rt2x00_pci_alloc_rings(struct _rt2x00_device *device)
{
struct _rt2x00_pci *rt2x00pci = rt2x00_priv(device);
if(rt2x00_pci_alloc_ring(device, &rt2x00pci->rx, RING_RX, RX_ENTRIES, DATA_FRAME_SIZE, SIZE_DESCRIPTOR)
|| rt2x00_pci_alloc_ring(device, &rt2x00pci->tx, RING_TX, TX_ENTRIES, DATA_FRAME_SIZE, SIZE_DESCRIPTOR)
|| rt2x00_pci_alloc_ring(device, &rt2x00pci->atim, RING_ATIM, ATIM_ENTRIES, MGMT_FRAME_SIZE, SIZE_DESCRIPTOR)
|| rt2x00_pci_alloc_ring(device, &rt2x00pci->prio, RING_PRIO, PRIO_ENTRIES, MGMT_FRAME_SIZE, SIZE_DESCRIPTOR)
|| rt2x00_pci_alloc_ring(device, &rt2x00pci->beacon, RING_BEACON, BEACON_ENTRIES, MGMT_FRAME_SIZE, SIZE_DESCRIPTOR)){
ERROR("DMA allocation failed.\n");
return -ENOMEM;
}
return 0;
}
static inline void
rt2x00_pci_free_ring(struct _data_ring *ring)
{
struct _rt2x00_pci *rt2x00pci = rt2x00_priv(ring->device);
if(ring->data_addr)
dma_free_coherent(&rt2x00pci->pci_dev->dev, ring->mem_size, ring->data_addr, ring->data_dma);
ring->data_addr = NULL;
rt2x00_deinit_ring(ring);
}
static void
rt2x00_pci_free_rings(struct _rt2x00_device *device)
{
struct _rt2x00_pci *rt2x00pci = rt2x00_priv(device);
rt2x00_pci_free_ring(&rt2x00pci->rx);
rt2x00_pci_free_ring(&rt2x00pci->tx);
rt2x00_pci_free_ring(&rt2x00pci->atim);
rt2x00_pci_free_ring(&rt2x00pci->prio);
rt2x00_pci_free_ring(&rt2x00pci->beacon);
}
/*
* Macro's for calculating exact position in data ring.
*/
#define DESC_BASE(__ring) ( (void*)((__ring)->data_addr) )
#define DATA_BASE(__ring) ( (void*)(DESC_BASE(__ring) + ((__ring)->max_entries * (__ring)->desc_size)) )
#define __DESC_ADDR(__ring, __index) ( (void*)(DESC_BASE(__ring) + ((__index) * (__ring)->desc_size)) )
#define __DATA_ADDR(__ring, __index) ( (void*)(DATA_BASE(__ring) + ((__index) * (__ring)->entry_size)) )
#define DESC_ADDR(__ring) ( __DESC_ADDR(__ring, (__ring)->index) )
#define DESC_ADDR_DONE(__ring) ( __DESC_ADDR(__ring, (__ring)->index_done) )
#define DATA_ADDR(__ring) ( __DATA_ADDR(__ring, (__ring)->index) )
#define DATA_ADDR_DONE(__ring) ( __DATA_ADDR(__ring, (__ring)->index_done) )
/*
* Register access.
* All access to the registers will go through rt2x00_register_read and rt2x00_register_write.
* BBP and RF register require indirect register access through the register BBPCSR and RFCSR.
* The indirect register access work with busy bits, and a read or write function call can fail.
* Specific fields within a register can be accessed using the set and get field routines,
* these function will handle the requirement of little_endian and big_endian conversions.
*/
#define REGISTER_BUSY_COUNT 10 /* Number of retries before failing access BBP & RF indirect register */
#define REGISTER_BUSY_DELAY 100 /* Delay between each register access retry. (us) */
static void
rt2x00_register_read(const struct _rt2x00_pci *rt2x00pci, const unsigned long offset, u32 *value)
{
*value = readl((void*)(rt2x00pci->csr_addr + offset));
}
static void
rt2x00_register_multiread(const struct _rt2x00_pci *rt2x00pci, const unsigned long offset, u32 *value, const u16 length)
{
memcpy_fromio((void*)value, (void*)(rt2x00pci->csr_addr + offset), length);
}
static void
rt2x00_register_write(const struct _rt2x00_pci *rt2x00pci, const unsigned long offset, const u32 value)
{
writel(value, (void*)(rt2x00pci->csr_addr + offset));
}
static void
rt2x00_register_multiwrite(const struct _rt2x00_pci *rt2x00pci, const unsigned long offset, u32 *value, const u16 length)
{
memcpy_toio((void*)(rt2x00pci->csr_addr + offset), (void*)value, length);
}
static void
rt2x00_bbp_regwrite(const struct _rt2x00_pci *rt2x00pci, const u8 reg_id, const u8 value)
{
u32 reg = 0x00000000;
u8 counter = 0x00;
for(counter = 0x00; counter < REGISTER_BUSY_COUNT; counter++){
rt2x00_register_read(rt2x00pci, BBPCSR, ®);
if(!rt2x00_get_field32(reg, BBPCSR_BUSY))
goto bbp_write;
udelay(REGISTER_BUSY_DELAY);
}
ERROR("BBPCSR register busy. Write failed\n");
return;
bbp_write:
reg = 0x00000000;
rt2x00_set_field32(®, BBPCSR_VALUE, value);
rt2x00_set_field32(®, BBPCSR_REGNUM, reg_id);
rt2x00_set_field32(®, BBPCSR_BUSY, 1);
rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1);
rt2x00_register_write(rt2x00pci, BBPCSR, reg);
}
static void
rt2x00_bbp_regread(const struct _rt2x00_pci *rt2x00pci, const u8 reg_id, u8 *value)
{
u32 reg = 0x00000000;
u8 counter = 0x00;
/*
* We first have to acquire the requested BBP register,
* so we write the register id into the BBP register first.
*/
rt2x00_set_field32(®, BBPCSR_REGNUM, reg_id);
rt2x00_set_field32(®, BBPCSR_BUSY, 1);
rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0);
rt2x00_register_write(rt2x00pci, BBPCSR, reg);
for(counter = 0x00; counter < REGISTER_BUSY_COUNT; counter++){
rt2x00_register_read(rt2x00pci, BBPCSR, ®);
if(!rt2x00_get_field32(reg, BBPCSR_BUSY)){
*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
return;
}
udelay(REGISTER_BUSY_DELAY);
}
ERROR("BBPCSR register busy. Read failed\n");
*value = 0xff;
}
static void
rt2x00_rf_regwrite(const struct _rt2x00_pci *rt2x00pci, const u32 value)
{
u32 reg = 0x00000000;
u8 counter = 0x00;
for(counter = 0x00; counter < REGISTER_BUSY_COUNT; counter++){
rt2x00_register_read(rt2x00pci, RFCSR, ®);
if(!rt2x00_get_field32(reg, RFCSR_BUSY))
goto rf_write;
udelay(REGISTER_BUSY_DELAY);
}
ERROR("RFCSR register busy. Write failed\n");
return;
rf_write:
reg = value;
rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20);
rt2x00_set_field32(®, RFCSR_IF_SELECT, 0);
rt2x00_set_field32(®, RFCSR_BUSY, 1);
rt2x00_register_write(rt2x00pci, RFCSR, reg);
}
/*
* EEPROM access.
* The EEPROM is being accessed by word index.
* rt2x00_eeprom_read_word is the main access function that can be called by
* the rest of the module. It will take the index number of the eeprom word
* and the bus width.
*/
static inline void
rt2x00_eeprom_pulse_high(const struct _rt2x00_pci *rt2x00pci, u32 *flags)
{
rt2x00_set_field32(flags, CSR21_EEPROM_DATA_CLOCK, 1);
rt2x00_register_write(rt2x00pci, CSR21, *flags);
udelay(1);
}
static inline void
rt2x00_eeprom_pulse_low(const struct _rt2x00_pci *rt2x00pci, u32 *flags)
{
rt2x00_set_field32(flags, CSR21_EEPROM_DATA_CLOCK, 0);
rt2x00_register_write(rt2x00pci, CSR21, *flags);
udelay(1);
}
static void
rt2x00_eeprom_shift_out_bits(const struct _rt2x00_pci *rt2x00pci, const u16 data, const u16 count)
{
u32 flags = 0x00000000;
u32 mask = 0x0001 << (count - 1);
rt2x00_register_read(rt2x00pci, CSR21, &flags);
/*
* Clear data flags.
*/
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, 0);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_OUT, 0);
/*
* Start writing all bits.
*/
do{
/*
* Only set the data_in flag when we are at the correct bit.
*/
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, (data & mask) ? 1 : 0);
rt2x00_register_write(rt2x00pci, CSR21, flags);
rt2x00_eeprom_pulse_high(rt2x00pci, &flags);
rt2x00_eeprom_pulse_low(rt2x00pci, &flags);
/*
* Shift to next bit.
*/
mask >>= 1;
} while(mask);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, 0);
rt2x00_register_write(rt2x00pci, CSR21, flags);
}
static void
rt2x00_eeprom_shift_in_bits(const struct _rt2x00_pci *rt2x00pci, u16 *data)
{
u32 flags = 0x00000000;
u8 counter = 0x00;
rt2x00_register_read(rt2x00pci, CSR21, &flags);
/*
* Clear data flags.
*/
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, 0);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_OUT, 0);
/*
* Start reading all 16 bits.
*/
for(counter = 0; counter < 16; counter++){
/*
* Shift to the next bit.
*/
*data <<= 1;
rt2x00_eeprom_pulse_high(rt2x00pci, &flags);
rt2x00_register_read(rt2x00pci, CSR21, &flags);
/*
* Clear data_in flag and set the data bit to 1 when the data_out flag is set.
*/
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, 0);
if(rt2x00_get_field32(flags, CSR21_EEPROM_DATA_OUT))
*data |= 1;
rt2x00_eeprom_pulse_low(rt2x00pci, &flags);
}
}
static u16
rt2x00_eeprom_read_word(const struct _rt2x00_pci *rt2x00pci, const u8 word)
{
u32 flags = 0x00000000;
u16 data = 0x0000;
/*
* Clear all flags, and enable chip select.
*/
rt2x00_register_read(rt2x00pci, CSR21, &flags);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, 0);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_OUT, 0);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_CLOCK, 0);
rt2x00_set_field32(&flags, CSR21_EEPROM_CHIP_SELECT, 1);
rt2x00_register_write(rt2x00pci, CSR21, flags);
/*
* kick a pulse.
*/
rt2x00_eeprom_pulse_high(rt2x00pci, &flags);
rt2x00_eeprom_pulse_low(rt2x00pci, &flags);
/*
* Select the read opcode and bus_width.
*/
rt2x00_eeprom_shift_out_bits(rt2x00pci, EEPROM_READ_OPCODE, 3);
rt2x00_eeprom_shift_out_bits(rt2x00pci, word, rt2x00pci->eeprom_width);
rt2x00_eeprom_shift_in_bits(rt2x00pci, &data);
/*
* Clear chip_select and data_in flags.
*/
rt2x00_register_read(rt2x00pci, CSR21, &flags);
rt2x00_set_field32(&flags, CSR21_EEPROM_DATA_IN, 0);
rt2x00_set_field32(&flags, CSR21_EEPROM_CHIP_SELECT, 0);
rt2x00_register_write(rt2x00pci, CSR21, flags);
/*
* kick a pulse.
*/
rt2x00_eeprom_pulse_high(rt2x00pci, &flags);
rt2x00_eeprom_pulse_low(rt2x00pci, &flags);
return data;
}
#endif /* RT2X00PCI_H */
Articoli correlati
HW2.cpp
HW2.cpp — cpp source code from the linux drivers learning materials (linux_drivers/HW2.cpp).
Leggi l'articolo →cycle_link.cpp
cycle_link.cpp — cpp source code from the linux drivers learning materials (linux_drivers/cycle_link.cpp).
Leggi l'articolo →ieee80211_crypt.c
ieee80211_crypt.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt.c).
Leggi l'articolo →ieee80211_crypt_ccmp.c
ieee80211_crypt_ccmp.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt_ccmp.c).
Leggi l'articolo →ieee80211_crypt_tkip.c
ieee80211_crypt_tkip.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt_tkip.c).
Leggi l'articolo →ieee80211_crypt_wep.c
ieee80211_crypt_wep.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt_wep.c).
Leggi l'articolo →