/*
Driver for the Marvell 8385 based compact flash WLAN cards.
(C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <linux/io.h>
#define DRV_NAME "libertas_cs"
#include "decl.h"
#include "defs.h"
#include "dev.h"
/********************************************************************/
/* Module stuff */
/********************************************************************/
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
MODULE_LICENSE("GPL");
/********************************************************************/
/* Data structures */
/********************************************************************/
struct if_cs_card {
struct pcmcia_device *p_dev;
struct lbs_private *priv;
void __iomem *iobase;
bool align_regs;
u32 model;
};
enum {
MODEL_UNKNOWN = 0x00,
MODEL_8305 = 0x01,
MODEL_8381 = 0x02,
MODEL_8385 = 0x03
};
static const struct lbs_fw_table fw_table[] = {
{ MODEL_8305, "libertas/cf8305.bin", NULL },
{ MODEL_8305, "libertas_cs_helper.fw", NULL },
{ MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
{ MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
{ MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
{ MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
{ 0, NULL, NULL }
};
MODULE_FIRMWARE("libertas/cf8305.bin");
MODULE_FIRMWARE("libertas/cf8381_helper.bin");
MODULE_FIRMWARE("libertas/cf8381.bin");
MODULE_FIRMWARE("libertas/cf8385_helper.bin");
MODULE_FIRMWARE("libertas/cf8385.bin");
MODULE_FIRMWARE("libertas_cs_helper.fw");
MODULE_FIRMWARE("libertas_cs.fw");
/********************************************************************/
/* Hardware access */
/********************************************************************/
/* This define enables wrapper functions which allow you
to dump all register accesses. You normally won't this,
except for development */
/* #define DEBUG_IO */
#ifdef DEBUG_IO
static int debug_output = 0;
#else
/* This way the compiler optimizes the printk's away */
#define debug_output 0
#endif
static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
{
unsigned int val = ioread8(card->iobase + reg);
if (debug_output)
printk(KERN_INFO "inb %08x<%02x\n", reg, val);
return val;
}
static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
{
unsigned int val = ioread16(card->iobase + reg);
if (debug_output)
printk(KERN_INFO "inw %08x<%04x\n", reg, val);
return val;
}
static inline void if_cs_read16_rep(
struct if_cs_card *card,
uint reg,
void *buf,
unsigned long count)
{
if (debug_output)
printk(KERN_INFO "insw %08x<(0x%lx words)\n",
reg, count);
ioread16_rep(card->iobase + reg, buf, count);
}
static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
{
if (debug_output)
printk(KERN_INFO "outb %08x>%02x\n", reg, val);
iowrite8(val, card->iobase + reg);
}
static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
{
if (debug_output)
printk(KERN_INFO "outw %08x>%04x\n", reg, val);
iowrite16(val, card->iobase + reg);
}
static inline void if_cs_write16_rep(
struct if_cs_card *card,
uint reg,
const void *buf,
unsigned long count)
{
if (debug_output)
printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
reg,