diff options
Diffstat (limited to 'uClinux-2.4.20-uc1/drivers/net/wireless')
-rw-r--r-- | uClinux-2.4.20-uc1/drivers/net/wireless/Config.in | 4 | ||||
-rw-r--r-- | uClinux-2.4.20-uc1/drivers/net/wireless/Makefile | 1 | ||||
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/net/wireless/Queue.c | 90 | ||||
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/net/wireless/Queue.h | 37 | ||||
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.c | 998 | ||||
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.h | 863 | ||||
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/net/wireless/base.c | 1783 |
7 files changed, 3776 insertions, 0 deletions
diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/Config.in b/uClinux-2.4.20-uc1/drivers/net/wireless/Config.in index 9f85072..d0a9a5a 100644 --- a/uClinux-2.4.20-uc1/drivers/net/wireless/Config.in +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/Config.in @@ -8,6 +8,10 @@ fi tristate ' Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)' CONFIG_HERMES +if [ "$CONFIG_CPU_W90N745" = "y" ]; then + bool ' W90745 PRISM2 chipset 802.11b support ' CONFIG_N745PRISM +fi + if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate ' Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT $CONFIG_HERMES fi diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/Makefile b/uClinux-2.4.20-uc1/drivers/net/wireless/Makefile index 7c76eb6..cd611c2 100644 --- a/uClinux-2.4.20-uc1/drivers/net/wireless/Makefile +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/Makefile @@ -15,6 +15,7 @@ obj- := export-objs := airo.o orinoco.o hermes.o obj-$(CONFIG_HERMES) += orinoco.o hermes.o +obj-$(CONFIG_N745PRISM) += W90N745Prism.o base.o Queue.o obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o obj-$(CONFIG_APPLE_AIRPORT) += airport.o obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/Queue.c b/uClinux-2.4.20-uc1/drivers/net/wireless/Queue.c new file mode 100755 index 0000000..3df0044 --- /dev/null +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/Queue.c @@ -0,0 +1,90 @@ +#include "W90N745Prism.h" +#include "Queue.h" + + +extern Queue_txfid TxQueueObj; +/* private txfid queue function, for interval use */ +INT16 Init_Queue() +{ + INT16 i; + INT16 result = 0; + INT16 retry = 0; + + memset(&TxQueueObj, 0, sizeof(Queue_txfid)); + for (i = 0; i < PRISM2_TX_FIDSTACKLEN_MAX; i++) + { +retryalloc: + result = prism_cmd_allocate(PRISM2_TXBUF_MAX, &(TxQueueObj.cells[i].fid)); + if (result != 0) { + printk("Allocate(tx) command failed\n"); + result = -1; + if(retry < 4) { + retry++; + goto retryalloc; + } + goto out; + } + retry = 0; + TxQueueObj.cells[i].flag |=0x1; + } +out: + TxQueueObj.capability = i; + return i; +} + +/* Dump for debuging queue */ +void Queue_dump() +{ +#ifdef WDEBUG + int i; + + printk("Number of Cells in Queue: %d\n", TxQueueObj.capability); + for(i = 0; i < TxQueueObj.capability; i++) + { + printk("%dth: txfid: %x, flag: %d\n", i, (TxQueueObj.cells[i].fid), TxQueueObj.cells[i].flag); + } +#endif +} + +/* public txfid queue function, for geting a tx fid */ +INT16 Get_txfid() +{ + int i; + + if(GetAvailableCellNum(TxQueueObj) <= 0) { + printk("No available cell for tx\n"); + return -1; + } + + for(i = 0; (i < PRISM2_TX_FIDSTACKLEN_MAX)&&(!TxQueueObj.cells[i].flag); i++); + if(i >= PRISM2_TX_FIDSTACKLEN_MAX) { + printk("Erro:No available cell for tx\n"); + return -1; + } + TxQueueObj.cells[i].flag = 0; + ReduceAvailableCellNum(TxQueueObj); + return TxQueueObj.cells[i].fid; +} + +/* public txfid queue function, for puting a tx fid */ +INT16 Put_txfid(UINT16 val) +{ + INT16 result = 0; + int i; + + if(GetAvailableCellNum(TxQueueObj) >= PRISM2_TX_FIDSTACKLEN_MAX) { + //printk("queue have full\n"); + return -1; + } + + for(i = 0; (i < PRISM2_TX_FIDSTACKLEN_MAX)&&(TxQueueObj.cells[i].fid != val); i++); + if(i >= PRISM2_TX_FIDSTACKLEN_MAX) { + printk("Illegal txfid for tx: %d \n", val); + return -1; + } + if(!TxQueueObj.cells[i].flag) { + TxQueueObj.cells[i].flag = 1; + AddAvailableCellNum(TxQueueObj); + } + return result; +} diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/Queue.h b/uClinux-2.4.20-uc1/drivers/net/wireless/Queue.h new file mode 100755 index 0000000..adab295 --- /dev/null +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/Queue.h @@ -0,0 +1,37 @@ +#ifndef __QUEUE_H__ +#define __QUEUE_H__ + +#define UINT16 short +#define INT16 short +#define UINT8 unsigned char +#define UINT32 unsigned int + +/*--------------fids queue-----------------*/ +typedef struct prism_txfid_cell +{ + UINT8 flag; //whether in use + UINT16 fid; //fid value +}txfid_cell; + +typedef struct prism_txfid_queue +{ + txfid_cell cells[PRISM2_TX_FIDSTACKLEN_MAX]; + UINT8 capability; //queue size +}Queue_txfid; +/*-------------fid queue operations--------------*/ +#define GetAvailableCellNum(x) (x.capability) +#define ReduceAvailableCellNum(x) (--(x.capability)) +#define AddAvailableCellNum(x) (++(x.capability)) + + +/*-----------------function phototype----------------*/ +/* private txfid queue function, for interval use */ +INT16 Init_Queue(); +/* Dump for debuging queue */ +void Queue_dump(); +/* public txfid queue function, for geting a tx fid */ +INT16 Get_txfid(); +/* public txfid queue function, for puting a tx fid */ +INT16 Put_txfid(UINT16 val); + +#endif diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.c b/uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.c new file mode 100755 index 0000000..de76f6d --- /dev/null +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.c @@ -0,0 +1,998 @@ +/*-------------------------------------------------------------------------------*/ +/* Wireless driver for winbond W90N745 */ +/* version 1.0.2 (used only for Station) */ +/* ------------------------------------------------------------------------------*/ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/pagemap.h> +#include <linux/vmalloc.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <asm/irq.h> + +#include "W90N745Prism.h" +/* tx buffer queue, you can replace it as what you designed */ +#include "Queue.h" + + + +extern char PRISM_DesireSSID_DEFAULT[]; +extern char PRISM_BSSID[]; +extern char PRISM_LLC[]; +extern unsigned char Mac_address[6]; +extern Queue_txfid TxQueueObj; +/* Debug for now */ +extern UINT8 *DebugpBuffer; +//#define PRSIM_DEBUG +extern int nums; + +/* -------------------------all functions--------------------------- */ + +/* Here handle the tx ,rx and other events*/ +void prism_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + UINT16 reg; + struct net_device *dev = (struct net_device *)dev_id; + struct w740prism_priv *priv; + UINT16 txfid; + int count = MAX_IRQLOOPS_PER_IRQ; + static int last_irq_jiffy = 0; // jiffies value the last time we were called + static int loops_this_jiffy = 0; + + if (!dev /*paranoid*/ ) return; + + /* Lock the device */ + priv = (struct w740prism_priv *) dev->priv; + + /* read the EvStat register for interrupt enabled events */ + reg = READREG(PRISM_EVSTAT); + +#ifdef WDEBUG + //printk("Event: %x\n", reg); +#endif + if (jiffies != last_irq_jiffy) + loops_this_jiffy = 0; + last_irq_jiffy = jiffies; + + while(reg && count--) { + if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { + printk("%s: IRQ handler is looping too much! Shutting down.\n",dev->name); + WRITEREG(PRISM_INTEN, 0); + break; + } + + if(PRISM_EVSTAT_ISTICK(reg)) { + ; //printk("TICK\n"); + } + + if(PRISM_EVSTAT_ISWTERR(reg)) { +#ifdef WDEBUG + printk("WTERR\n"); //It shoudn't occur. +#endif + } + + if(PRISM_EVSTAT_ISINFDROP(reg)) { + ; //printk("INFDROP\n"); + } + + if(PRISM_EVSTAT_ISINFO(reg)) { + //printk("INFO\n"); + prism_info(dev); + } + + if(PRISM_EVSTAT_ISRX(reg)) { + prism_rx(dev); + } + + if(PRISM_EVSTAT_ISTXEXC(reg)) { +// printk("txexc "); + prism_txexc(); + } + + if(PRISM_EVSTAT_ISTX(reg)) { + prism_tx(dev); + } + + if(PRISM_EVSTAT_ISALLOC(reg)) { + txfid = READREG(PRISM_ALLOCFID); + if(Put_txfid(txfid) < 0) + { + ; + } + else { + netif_wake_queue(dev); + WRITEREG(PRISM_ALLOCFID, DUMMY_FID); + } + } + WRITEREG(PRISM_EVACK, reg); + + reg = READREG(PRISM_EVSTAT); + } +} + + +/*------------------------------------------------------------------*/ +int prism_open(struct net_device *dev) +{ + int result = 0; + MOD_INC_USE_COUNT; + /* change the interupt source from high-level sensitive to low-level sensitive */ + if(((struct w740prism_priv *)(dev->priv))->status < 0) { + result = prism_initmac(dev); + if(result >= 0) + ((struct w740prism_priv *)(dev->priv))->status = 0; //clean it + } + /* chanel 4 of IRQ2 */ + if(request_irq(dev->irq, &prism_interrupt,SA_INTERRUPT,"",dev)) + { + printk("W740 wireless driver register irq failed\n"); + return -EAGAIN; + } + + netif_start_queue(dev); +#ifdef WDEBUG + printk("enable interrupt handle,:)\n"); +#endif + + return result; +} + +int prism_release(struct net_device *dev) +{ + MOD_DEC_USE_COUNT; + netif_stop_queue(dev); + free_irq(dev->irq,dev); + return 0; +} + +int prism_config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + return 0; +} + +/* real receive function */ +void prism_rx(struct net_device *dev) +{ + int result = 0; + UINT16 rxfid, dataLen; + struct sk_buff *skb; + struct w740prism_priv *priv; + //prism_rx_frame_t + + if(!dev) + { + printk("Null dev in rx\n"); + return; + } + priv = (struct w740prism_priv *) dev->priv; + + /* Get the RxFID */ + rxfid = READREG(PRISM_RXFID); + /* Get the data length */ + result = prism_copy_from_bap(IRQ_BAP, rxfid, 44, &dataLen, 2); + if (result) { + LOGPRINT; + goto fail_reset; + } + + skb = dev_alloc_skb(dataLen+12-6 + 2); + if (!skb) { + LOGPRINT; + priv->stats.rx_dropped++; + return; + } + + skb_reserve(skb, 2); // align IP on 16B boundary + skb_put(skb, dataLen + 6); + result = prism_copy_from_bap(IRQ_BAP, rxfid, 18, skb->data, 6); + if (result) { + LOGPRINT; + priv->stats.rx_dropped++; + dev_kfree_skb(skb); + goto fail_reset; + } + result = prism_copy_from_bap(IRQ_BAP, rxfid, 30, skb->data+6, 6); + if (result) { + LOGPRINT; + priv->stats.rx_dropped++; + dev_kfree_skb(skb); + goto fail_reset; + } + + /* Get the 802.3 body */ + result = prism_copy_from_bap(IRQ_BAP, rxfid, 66, skb->data+12, dataLen - 6); + if (result) { + LOGPRINT; + priv->stats.rx_dropped++; + dev_kfree_skb(skb); + LOGPRINT; + goto fail_reset; + } + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + //skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += (dataLen+6); +#ifdef WIRELESS_SPY + ;//prism_wireless_stat(dev, skb, &desc); +#endif + //DEBUG("Receive a packet\n"); + netif_rx(skb); + return; +fail_reset: + netif_stop_queue(dev); + prism_reset(dev->priv); + netif_wake_queue(dev); + return; +} + +int prism_info(struct net_device *dev) +{ + UINT16 infoid; + UINT16 len; + UINT16 infotype = 0; + UINT16 status = 0; + struct w740prism_priv *priv = (struct w740prism_priv *)dev->priv; + + infoid = READREG(PRISM_INFOFID); +// printk("infoid: %x\n", infoid); + infotype = Read_CT_InfoType(infoid, &len); + if(infotype == -1) + { + printk("Meet erro when reading info\n"); + return -1; + } + + switch(infotype) + { + case PRISM_INQ_TALLIES: + //DEBUG("%s: PRISM_INQ_TALLIES: len: %d\n", dev->name, len); + + break; + case PRISM_INQ_SCAN: + DEBUG("%s: PRISM_INQ_SCAN: len:%d\n", dev->name, len); + get_scan_result(infoid, len, priv); + break; + case PRISM_INQ_LINKSTATUS: + DEBUG("%s: PRISM_INQ_LINKSTATUS: len: %d\n", dev->name, len); + Read_CT_InfoData(infoid, &status, len); //2 bytes + prism_lock(priv); + priv->status = status; + prism_unlock(priv); + DEBUG("%s: current link status: %x\n",dev->name, status); + break; + default: + DEBUG("%s: Unkown infotype: %x\n", dev->name, infotype); + return -1; + } + + return 0; +} + +#define PRSIM_DEBUG0 +#define PRSIM_DEBUG1 +/* + * Transmit a packet (called by the kernel) + */ +int prism_start_tx(struct sk_buff *skb, struct net_device *dev) +{ + int result = 0; + + result = send_frame(dev, skb->data, skb->len); + if(!result) + { + dev_kfree_skb(skb); + return result; + } + return result; +} + +/* interval transmit function */ +static int send_frame(struct net_device *dev ,unsigned char *data,int length) +{ + struct hermes_tx_descriptor txdesc; + UINT16 fid; + int result = 0; + int retrycount = 0; + UINT8 *pData; + UINT32 data_off, data_len, len; + struct ethhdr *eh; + struct header_struct hdr; + struct net_device_stats *stats = &(((struct w740prism_priv *) dev->priv)->stats); + + //DEBUG("Send a packet\n"); + /* check stop */ + if (! netif_running(dev)) { + printk("%s: Tx on stopped device!\n",dev->name); + return 1; + } + + /* check busy */ + if (netif_queue_stopped(dev)) { + printk("%s: Tx while transmitter busy!\n", dev->name); + return 1; + } + + prism_lock((struct w740prism_priv *)dev->priv); + disable_irq(dev->irq); + fid = Get_txfid(); + enable_irq(dev->irq); + if((signed short)fid < 0) { + printk("%s: Tx on erro fid:%x\n", dev->name, fid); + goto fail_reset; + } + /* Length of the packet body */ + /* FIXME: what if the skb is smaller than this? */ + len = max_t(int,length - ETH_HLEN, ETH_ZLEN); + + eh = (struct ethhdr *)data; + + /* Build Tx frame structure */ + /* Set up the control field */ + memset(&txdesc, 0, sizeof(txdesc)); + + /* set the control to 802.11 */ + txdesc.tx_control = cpu_to_le16(PRISM_TX_TXEX_SET(1) | PRISM_TX_TXOK_SET(1)); + disable_irq(dev->irq); + result = prism_copy_to_bap(USER_BAP, fid, 0, &txdesc, sizeof(txdesc)); + enable_irq(dev->irq); + if ( result ) { + printk("MAC tx copy_to_bap failed, %d\n", __LINE__); + if(result == -1) + goto fail_reset; + else + goto fail; + } + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > 1500) { // Ethernet-II frame + data_len = len; + data_off = HERMES_802_3_OFFSET + sizeof(hdr); + pData = data + ETH_HLEN; + + memcpy(hdr.dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.src, eh->h_source, ETH_ALEN); + + hdr.len = htons(data_len + ENCAPS_OVERHEAD); + /* 802.2 header */ + memcpy(&hdr.dsap, &PRISM_LLC, sizeof(char)*6); + hdr.ethertype = eh->h_proto; + disable_irq(dev->irq); + result = prism_copy_to_bap(USER_BAP, fid, HERMES_802_3_OFFSET, &hdr, sizeof(hdr)); + enable_irq(dev->irq); + if (result) { + printk("%s: Error %d writing packet header to BAP\n", dev->name, result); + if(result == -1) + goto fail_reset; + else + goto fail; + } + } + else { + data_len = len + ETH_HLEN; + data_off = HERMES_802_3_OFFSET; + pData = data; + } + disable_irq(dev->irq); + result = prism_copy_to_bap(USER_BAP, fid, data_off, pData, RUP_EVEN(data_len)); + enable_irq(dev->irq); + if ( result ) { + printk("MAC tx copy_to_bap failed: %d\r\n", __LINE__); + goto fail; + } + + /* Finally, we actually initiate the send */ + if(GetAvailableCellNum(TxQueueObj) <= 0) + netif_stop_queue(dev); + retrycount = 4; +retry: + /* Issue Tx command */ + result = prism_cmd_transmit(1, fid); + if (result != 0) { + if(--retrycount > 0) + goto retry; + goto fail; + } + dev->trans_start = jiffies; + prism_unlock((struct w740prism_priv *)dev->priv); + + return 0; +fail_reset: + netif_stop_queue(dev); + prism_reset(dev->priv); + netif_wake_queue(dev); +fail: + stats->tx_errors++; + disable_irq(dev->irq); + Put_txfid(fid); + enable_irq(dev->irq); + prism_unlock((struct w740prism_priv *)dev->priv); + return -1; + +} + +/* tx reponse function */ +int prism_tx(struct net_device *dev) +{ + UINT16 fid; + UINT16 status; + int result = 0; + + fid = READREG(PRISM_TXCOMPLFID); + result = prism_copy_from_bap(IRQ_BAP, fid, 0, &status, sizeof(status)); + if (result) { + printk("prism_tx:copy_from_bap failed\r\n"); + return -1; + } + ((struct w740prism_priv *)dev->priv)->stats.tx_packets++; + return result; /* Our simple device can not fail */ +} + +/* tx timeout function, timeout is set in init() */ +void prism_tx_timeout (struct net_device *dev) +{ + printk("tx timeout. :(\n"); + struct w740prism_priv *priv = (struct w740prism_priv *)dev->priv; + struct net_device_stats *stats = &priv->stats; + int err = 0; + + printk("Tx timeout! Reset Device\n"); + + stats->tx_errors++; + err = prism_reset(priv); + if(err) + printk("Erro:%d on resetting Device:%s\n", err, dev->name); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } + +} + +/* device reset, nothing to say, :( */ +int prism_reset(struct w740prism_priv *priv) +{ + int err = 0; +#ifdef WDEBUG + printk("prism_reset :( \n"); +#endif + spin_lock_bh(priv->lock); + disable_irq(priv->ndev->irq); + err = prism_reset_device(priv->ndev); + enable_irq(priv->ndev->irq); + spin_unlock_bh(priv->lock); + return err; +} + +/* Device ioctl for setting wlan configuration */ +int prism_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int err = 0; + struct iwreq *wrq = (struct iwreq *)rq; + int changed = 0; + struct w740prism_priv *priv = dev->priv; + DEBUG("cmd: %x,iwreq:%d\n", cmd,sizeof(struct iwreq)); + switch (cmd) { + case SIOCGIWNAME: + DEBUG("%s: SIOCGIWNAME\n", dev->name); + strcpy(wrq->u.name, "IEEE 802.11b"); + break; + + case SIOCGIWAP: + DEBUG("%s: SIOCGIWAP\n", dev->name); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; +// printk("mac buf addr: %x\n", wrq->u.ap_addr.sa_data); + err = prism_hw_get_bssid(dev, wrq->u.ap_addr.sa_data); + break; + + case SIOCGIWRANGE: + DEBUG("%s: SIOCGIWRANGE\n", dev->name); + break; + + case SIOCSIWMODE: + DEBUG("%s: SIOCSIWMODE\n", dev->name); + prism_lock(priv); + DEBUG("MOD: %x\n", wrq->u.mode); + switch (wrq->u.mode) { + case IW_MODE_ADHOC: + case IW_MODE_INFRA: + priv->iw_mode = wrq->u.mode; + changed = 1; + break; + + default: + err = -EINVAL; + break; + } + set_port_type(priv); + prism_unlock(priv); + break; + + case SIOCGIWMODE: + DEBUG("%s: SIOCGIWMODE\n", dev->name); + prism_lock(priv); + wrq->u.mode = priv->iw_mode; + prism_unlock(priv); + break; + + case SIOCSIWENCODE: + DEBUG("%s: SIOCSIWENCODE\n", dev->name); + + err = prism_ioctl_setiwencode(dev, &wrq->u.encoding); + if (! err) + changed = 1; + + break; + + case SIOCGIWENCODE: + DEBUG("%s: SIOCGIWENCODE\n", dev->name); + err = prism_ioctl_getiwencode(dev, &wrq->u.encoding); + break; + + case SIOCSIWESSID: + DEBUG("%s: SIOCSIWESSID\n", dev->name); + + err = prism_ioctl_setessid(dev, &wrq->u.essid); + if (! err) + changed = 1; + + break; + + case SIOCGIWESSID: + DEBUG("%s: SIOCGIWESSID\n", dev->name); + DEBUG("k wrq: %x\n", wrq); + err = prism_ioctl_getessid(dev, &wrq->u.essid); + + break; + + case SIOCSIWNICKN: + DEBUG("%s: SIOCSIWNICKN\n", dev->name); + break; + + case SIOCGIWNICKN: + DEBUG("%s: SIOCGIWNICKN\n", dev->name); + break; + + case SIOCGIWFREQ: + DEBUG("%s: SIOCGIWFREQ\n", dev->name); + err = prism_hw_get_freq(dev->priv); + DEBUG("%d: %d\n", __LINE__, err); + if(err >= 0) + wrq->u.freq.m = err; + else +#if 1 + wrq->u.freq.m = 1; //default to 1 +#else + wrq->u.freq.m = err; +#endif +// printk("freq: %x, %d\n", wrq->u.freq.m, __LINE__); + wrq->u.freq.e = 0; + break; + + case SIOCSIWFREQ: + DEBUG("%s: SIOCSIWFREQ\n", dev->name); + err = prism_ioctl_setfreq(dev, &wrq->u.freq); + if (! err) + changed = 1; + break; + + case SIOCGIWSENS: + DEBUG("%s: SIOCGIWSENS\n", dev->name); + err = prism_ioctl_getsens(dev, &wrq->u.sens); + break; + + case SIOCSIWSENS: + DEBUG("%s: SIOCSIWSENS\n", dev->name); + err = prism_ioctl_setsens(dev, &wrq->u.sens); + if(!err) + changed = 1; + break; + + case SIOCGIWRTS: + DEBUG("%s: SIOCGIWRTS\n", dev->name); + wrq->u.rts.value =((struct w740prism_priv *)(dev->priv))->rts_thresh; + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + case SIOCSIWRTS: + DEBUG("%s: SIOCSIWRTS\n", dev->name); + err = prism_ioctl_setrts(dev, &wrq->u.rts); + if( !err ) + changed = 1; + break; + + case SIOCSIWFRAG: + DEBUG("%s: SIOCSIWFRAG\n", dev->name); + break; + + case SIOCGIWFRAG: + DEBUG("%s: SIOCGIWFRAG\n", dev->name); + break; + + case SIOCSIWRATE: + DEBUG("%s: SIOCSIWRATE\n", dev->name); + err = prism_ioctl_setiwrate(dev, &wrq->u.bitrate); + if (! err) + changed = 1; + break; + + case SIOCGIWRATE: + DEBUG("%s: SIOCGIWRATE\n", dev->name); + err = prism_ioctl_getiwrate(dev, &wrq->u.bitrate); + break; + + case SIOCSIWPOWER: + DEBUG("%s: SIOCSIWPOWER\n", dev->name); + err = prism_ioctl_setpower(dev, &wrq->u.power); + if(!err) + changed = 1; + break; + + case SIOCGIWPOWER: + DEBUG("%s: SIOCGIWPOWER\n", dev->name); + err = prism_ioctl_getpower(dev, &wrq->u.power); + break; + + case SIOCGIWTXPOW: + DEBUG("%s: SIOCGIWTXPOW\n", dev->name); + /* The card only supports one tx power, so this is easy */ + break; + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + DEBUG("%s: SIOCSIWRETRY\n", dev->name); + break; + + case SIOCGIWRETRY: + DEBUG("%s: SIOCGIWRETRY\n", dev->name); + break; +#endif /* WIRELESS_EXT > 10 */ + + case SIOCSIWSPY: + DEBUG("%s: SIOCSIWSPY\n", dev->name); + err = prism_ioctl_setspy(dev, &wrq->u.data); + break; + + case SIOCGIWSPY: + DEBUG("%s: SIOCGIWSPY\n", dev->name); + err = prism_ioctl_getspy(dev, &wrq->u.data); + break; + + case SIOCGIWAPLIST: + DEBUG("%s: SIOCGIWAPLIST\n", dev->name); + err = prism_ioctl_getaplist(dev, &wrq->u.data); + break; + + case SIOCGIWPRIV: + DEBUG("%s: SIOCGIWPRIV\n", dev->name); +#if 0 + if (wrq->u.data.pointer) { + struct iw_priv_args privtab[] = { + { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, + { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, + { SIOCIWFIRSTPRIV + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCIWFIRSTPRIV + 0x3, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" }, + { SIOCIWFIRSTPRIV + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_preamble" }, + { SIOCIWFIRSTPRIV + 0x5, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_preamble" }, + { SIOCIWFIRSTPRIV + 0x6, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_ibssport" }, + { SIOCIWFIRSTPRIV + 0x7, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ibssport" } + }; + + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + err = -EFAULT; + } +#endif + break; + + case SIOCIWFIRSTPRIV + 0x0: /* force_reset */ + case SIOCIWFIRSTPRIV + 0x1: /* card_reset */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n", + dev->name); + netif_stop_queue(dev); + err = prism_reset(dev->priv); + netif_wake_queue(dev); + break; + + case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x2 (set_port3)\n", + dev->name); + break; + + case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n", + dev->name); + break; + + case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x4 (set_preamble)\n", + dev->name); + break; + + case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n", + dev->name); + + break; + case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n", + dev->name); + break; + + case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */ + DEBUG("%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n", + dev->name); + break; + + case SIOCIWFIRSTPRIV + 0x8: + DEBUG("%s: SIOCGIWSTATS\n", + dev->name); + err = prism_ioctl_getstat(dev, wrq); +// printk("%s: %d\n", __FILE__,__LINE__); + break; + case SIOCIWFIRSTPRIV + 0x9: + DEBUG("%s: SIOCGIWLINKSTATS\n", + dev->name); + err = prism_ioctl_getlinkstat(dev, &wrq->u.data); +// printk("%s: %d\n", __FILE__,__LINE__); + break; + case SIOCSIWSCAN: + DEBUG("%s: SIOCSIWSCAN\n", + dev->name); + if(netif_running(dev)) { +#ifdef SCAN_ENABLE + err = prism_ioctl_setscan(dev, &wrq->u.data); +#endif + } + DEBUG("addr: %x\n", wrq); + break; + + case SIOCGIWSCAN: + DEBUG("%s: SIOCGIWSCAN\n", + dev->name); + DEBUG("kwrq: %x\n", wrq); + break; + + + default: + printk("%s:No such cmd: %d\n", dev->name, cmd); + err = -EOPNOTSUPP; + } + + if (! err && changed && netif_running(dev)) { + /* We need the xmit lock because it protects the + multicast list which orinoco_reset() reads */ + spin_lock_bh(&dev->xmit_lock); + + netif_stop_queue(dev); + err = prism_reset(dev->priv); + netif_wake_queue(dev); + + spin_unlock_bh(&dev->xmit_lock); + if (err) { + /* Ouch ! What are we supposed to do ? */ + printk("prism: Failed to set parameters on %s\n", + dev->name); + netif_device_detach(dev); + } + } + + + + + return 0; +} + +/* device status */ +struct net_device_stats *prism_stats(struct net_device *dev) +{ + struct w740prism_priv *priv = (struct w740prism_priv *) dev->priv; + prism_lock(priv); + prism_unlock(priv); + return &priv->stats; +} + +struct iw_statistics *prism_wireless_stats(struct net_device *dev) +{ + struct w740prism_priv *priv = (struct w740prism_priv *) dev->priv; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + int temp1, temp2; + + prism_lock(priv); + if (priv->iw_mode == IW_MODE_ADHOC) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (SPY_NUMBER(priv)) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; + } + } else { + struct { + u16 qual, signal, noise; + } __attribute__ ((packed)) cq; + + Read_RID_Config(PRISM_RID_COMMSQUALITY, &cq); + + DEBUG("%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + wstats->qual.qual = cq.qual; + wstats->qual.level = cq.signal; + wstats->qual.noise = cq.noise; + wstats->qual.updated = 7; + DEBUG("%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + + } + /* FIXME: Hmm.. seems a bit ugly, I wonder if there's a way to + do better - dgibson */ + prism_cmd_inquiry(PRISM_INQ_TALLIES); + + prism_unlock(priv); + + if (err) + return NULL; + + return wstats; +} + +static void prism_set_multicast_list(struct net_device *dev) +{ +} + +/* it shouldn't be useful, setting mac address from inside */ +static int prism_set_mac_address(struct net_device *dev, void *addr) +{ +#if 0 + struct w740_priv * priv=(struct w740_priv *)dev->priv; + + if(netif_running(dev)) + return -EBUSY; + memcpy(&priv->mac_address[0],addr+2,ETH_ALEN); + + memcpy(dev->dev_addr,priv->mac_address,ETH_ALEN); + if(priv->which) + memcpy(w740_mac_address1,dev->dev_addr,ETH_ALEN); + else + memcpy(w740_mac_address0,dev->dev_addr,ETH_ALEN); + + TRACE_ERROR("\nSet MaC Address %u:%u:%u:%u:%u:%u\n", + dev->dev_addr[0],\ + dev->dev_addr[1],\ + dev->dev_addr[2],\ + dev->dev_addr[3],\ + dev->dev_addr[4],\ + dev->dev_addr[5]); + + //w740_WriteReg(CAMEN,w740_ReadReg(CAMEN,priv->which) & ~1,priv->which); + + return 0; +#endif + return 0; +} + +/* Driver init() */ +int prism_init(struct net_device *dev) +{ + int result = 0; + + //ether_setup(dev); /* assign some of the fields *///?? + dev->open = prism_open; + dev->stop = prism_release; + dev->set_config = prism_config; + dev->hard_start_xmit = prism_start_tx; + dev->do_ioctl = prism_ioctl; + dev->get_stats = prism_stats; + dev->get_wireless_stats = prism_wireless_stats; + //dev->change_mtu = snull_change_mtu; + //dev->rebuild_header = snull_rebuild_header; + //dev->hard_header = snull_header; + dev->irq = 4; //:) + dev->tx_timeout = prism_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + /* keep the default flags, just add NOARP */ + //dev->flags |= IFF_NOARP; + dev->hard_header_cache = NULL; /* Disable caching */ + SET_MODULE_OWNER(dev); + + /* + * Then, allocate the priv field. This encloses the statistics + * and a few private fields. + */ + dev->priv = kmalloc(sizeof(struct w740prism_priv), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct w740prism_priv)); + + result = prism_initmac(dev); + if(result<0) + return result; + memcpy(dev->dev_addr, ((struct w740prism_priv *) dev->priv)->mac_address, ETH_ALEN); + ((struct w740prism_priv *)(dev->priv))->ndev = dev; + + spin_lock_init(& ((struct w740prism_priv *) dev->priv)->lock); + init_MUTEX_LOCKED(&((struct w740prism_priv *) dev->priv)->sema); + + /* debug data */ + DebugpBuffer = kmalloc(sizeof(UINT8)*6, GFP_KERNEL); + if (DebugpBuffer == NULL) + return -ENOMEM; + + if(result < 0) /* init fail, and need try again */ + { + ((struct w740prism_priv *)(dev->priv))->status = -1; + } + + memcpy(((struct w740prism_priv *)(dev->priv))->desired_essid, "PC32WebCam", strlen("PC32WebCam")+1); + ether_setup(dev); /* assign some of the fields */ + +// printk("address length: %d\n", dev->addr_len); + + return (result>=0?0:-1); +} + +/* Our device struct */ +struct net_device prism_dev = +{ + name: "wlan0", + init: prism_init, /* init function */ +}; + +/* module init call function */ +int prism_init_module(void) +{ + int result = 0; + printk("Welcome wireless network! :)\n"); + if ( (result = register_netdev(&prism_dev)) ) { + printk("prism: error %i registering device \"%s\"\n", + result, prism_dev.name); + return -ENODEV; + } +#ifndef PRSIM_DEBUG + EXPORT_NO_SYMBOLS; +#endif + + return 0; +} + +/* module cleanup function, our don't clean up in our system now */ +void prism_cleanup(void) +{ + kfree(prism_dev.priv); + unregister_netdev(&prism_dev); + return; +} + +module_init(prism_init_module); +module_exit(prism_cleanup); diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.h b/uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.h new file mode 100755 index 0000000..18130f1 --- /dev/null +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.h @@ -0,0 +1,863 @@ +#ifndef __W90N745PRISM_H__ +#define __W90N745PRISM_H__ + + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/if_arp.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/in.h> +#include <linux/skbuff.h> +#include <linux/wireless.h> + +#if LINUX_VERSION_CODE < 132116 + #define SIOCSIWSCAN 0x8B18 /* trigger scanning */ + #define SIOCGIWSCAN 0x8B19 /* get scanning results */ +#endif + +//#define WDEBUG + +#define UINT16 short +#define INT16 short +#define UINT8 unsigned char +#define UINT32 unsigned int + +#define __WLAN_ATTRIB_PACK__ __attribute__ ((packed)) + +/* read / write prism register macro */ +#define WRITEREG(reg, data) (*(volatile unsigned short *)(EBI_BASE + reg)) = data +#define READREG(reg) *(volatile unsigned short *)(EBI_BASE + reg) + +// ASIC Address Definitions +#define VPint *(volatile unsigned int *) +#define VPshort *(volatile unsigned short *) +#define VPchar *(volatile unsigned char *) + +// external I/O 2 control register +#define EXT0CON_REG 0xFFF01018 +#define EXT1CON_REG 0xFFF0101C +#define EXT2CON_REG 0xFFF01020 + +// Special Register Start Address After System Reset +#define EBI_BASE 0xC0800000 // on W90N745 board PCMCIA + +// Advanced Interrupt Controller Registers +#define AIC_SCR_nIRQ0 (VPint(Base_Addr+0x00082008)) +#define AIC_SCR_nIRQ2 (VPint(Base_Addr+0x00082010)) + +// MAC Interrupt Source +#define nIRQ0 2 +#define nIRQ2 4 + +#define DIAG_PATTERNA ((UINT16)0xaaaa) +#define DIAG_PATTERNB ((UINT16)~0xaaaa) + +#define HERMES_MAGIC (0x7d1f) + +#define USER_BAP 0 +#define IRQ_BAP 1 + +/* operation mode */ +#define IW_MODE_AUTO 0 /* Let the driver decides */ +#define IW_MODE_ADHOC 1 /* Single cell network */ +#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ +/*---- follow no support now -----*/ +#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ +#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ +#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ + +/*------------------------------------------------------------------------*/ +/* PRISM MAC registers */ +/* Command/Status */ +/*------------------------------------------------------------------------*/ +#define PRISM_CMD 0x00 +#define PRISM_PARAM0 0x02 +#define PRISM_PARAM1 0x04 +#define PRISM_PARAM2 0x06 +#define PRISM_STATUS 0x08 +#define PRISM_RESP0 0x0A +#define PRISM_RESP1 0x0C +#define PRISM_RESP2 0x0E +// FID Management +#define PRISM_INFOFID 0x10 +#define PRISM_RXFID 0x20 +#define PRISM_ALLOCFID 0x22 +#define PRISM_TXCOMPLFID 0x24 +// BAP0 +#define PRISM_SELECT0 0x18 +#define PRISM_OFFSET0 0x1C +#define PRISM_DATA0 0x36 +// BAP1 +#define PRISM_SELECT1 0x1A +#define PRISM_OFFSET1 0x1E +#define PRISM_DATA1 0x38 +// Event +#define PRISM_EVSTAT 0x30 +#define PRISM_INTEN 0x32 +#define PRISM_EVACK 0x34 +// Control +#define PRISM_CONTROL 0x14 +// Host Software +#define PRISM_SWSUPPORT0 0x28 +#define PRISM_SWSUPPORT1 0x2A +#define PRISM_SWSUPPORT2 0x2C +// Auxiliary Port +#define PRISM_AUXPAGE 0x3A +#define PRISM_AUXOFFSET 0x3C +#define PRISM_AUXDATA 0x3E + +// Command Code Constants +// Controller Commands +#define PRISM_CMDCODE_INIT (0x00) +#define PRISM_CMDCODE_ENABLE (0x01) +#define PRISM_CMDCODE_DISABLE (0x02) +#define PRISM_CMDCODE_DIAG (0x03) + +// Buffer Mgmt Commands +#define PRISM_CMDCODE_ALLOC (0x0A) +#define PRISM_CMDCODE_TX (0x0B) + +// Regulate Commands +#define PRISM_CMDCODE_NOTIFY (0x10) +#define PRISM_CMDCODE_INQ (0x11) + +// Configure Commands +#define PRISM_CMDCODE_ACCESS (0x21) +#define PRISM_CMDCODE_DOWNLD (0x22) + +// Serial I/O Commands +#define PRISM_CMDCODE_READMIF (0x30) +#define PRISM_CMDCODE_WRITEMIF (0x31) + +/*--- Result Codes --------------------------*/ +#define PRISM_SUCCESS ((0x00)) +#define PRISM_CARD_FAIL ((0x01)) +#define PRISM_NO_BUFF ((0x05)) +#define PRISM_CMD_ERR ((0x7F)) + + + +/*------------- Programming Modes ------------------------*/ +/* MODE 0: Disable programming */ +/* MODE 1: Enable volatile memory programming */ +/* MODE 2: Enable non-volatile memory programming */ +/* MODE 3: Program non-volatile memory section */ +/*--------------------------------------------------------*/ +#define PRISM_PROGMODE_DISABLE (0x00) //no used +#define PRISM_PROGMODE_RAM (0x01) //no used +#define PRISM_PROGMODE_NV (0x02) //no used +#define PRISM_PROGMODE_NVWRITE (0x03) //no used + +/*------------------ Register Test/Get/Set Field macros ------------------------*/ +#define PRISM_CMD_ISBUSY(value) ((UINT16)(((UINT16)value) & 0x8000)) +#define PRISM_CMD_AINFO_GET(value) ((UINT16)(((UINT16)(value) & 0x7F00) >> 8)) +#define PRISM_CMD_AINFO_SET(value) ((UINT16)((UINT16)(value) << 8)) +#define PRISM_CMD_MACPORT_GET(value) ((UINT16)(PRISM_CMD_AINFO_GET((UINT16)(value) & 0x0700))) +#define PRISM_CMD_MACPORT_SET(value) ((UINT16)PRISM_CMD_AINFO_SET(value)) +#define PRISM_CMD_ISRECL(value) ((UINT16)(PRISM_CMD_AINFO_GET((UINT16)(value) & 0x0100))) +#define PRISM_CMD_RECL_SET(value) ((UINT16)PRISM_CMD_AINFO_SET(value)) +#define PRISM_CMD_ISWRITE(value) ((UINT16)(PRISM_CMD_AINFO_GET((UINT16)(value) & 0x0100))) +#define PRISM_CMD_WRITE_SET(value) ((UINT16)PRISM_CMD_AINFO_SET((UINT16)value)) +#define PRISM_CMD_PROGMODE_GET(value) ((UINT16)(PRISM_CMD_AINFO_GET((UINT16)(value) & 0x0300))) +#define PRISM_CMD_PROGMODE_SET(value) ((UINT16)PRISM_CMD_AINFO_SET((UINT16)value)) +#define PRISM_CMD_CMDCODE_GET(value) ((UINT16)(((UINT16)(value)) & 0x003F)) +#define PRISM_CMD_CMDCODE_SET(value) ((UINT16)(value)) + +#define PRISM_STATUS_RESULT_GET(value) ((UINT16)((((UINT16)(value)) & 0x7F00) >> 8)) +#define PRISM_STATUS_RESULT_SET(value) (((UINT16)(value)) << 8) +#define PRISM_STATUS_CMDCODE_GET(value) (((UINT16)(value)) & 0x003F) +#define PRISM_STATUS_CMDCODE_SET(value) ((UINT16)(value)) + +#define PRISM_OFFSET_ISBUSY(value) ((UINT16)(((UINT16)(value)) & 0x8000)) +#define PRISM_OFFSET_ISERR(value) ((UINT16)(((UINT16)(value)) & 0x4000)) +#define PRISM_OFFSET_DATAOFF_GET(value) ((UINT16)(((UINT16)(value)) & 0x0FFE)) +#define PRISM_OFFSET_DATAOFF_SET(value) ((UINT16)(value)) + +#define PRISM_EVSTAT_ISTICK(value) ((UINT16)(((UINT16)(value)) & 0x8000)) +#define PRISM_EVSTAT_ISWTERR(value) ((UINT16)(((UINT16)(value)) & 0x4000)) +#define PRISM_EVSTAT_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & 0x2000)) +#define PRISM_EVSTAT_ISINFO(value) ((UINT16)(((UINT16)(value)) & 0x0080)) +#define PRISM_EVSTAT_ISDTIM(value) ((UINT16)(((UINT16)(value)) & 0x0020)) +#define PRISM_EVSTAT_ISCMD(value) ((UINT16)(((UINT16)(value)) & 0x0010)) +#define PRISM_EVSTAT_ISALLOC(value) ((UINT16)(((UINT16)(value)) & 0x0008)) +#define PRISM_EVSTAT_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & 0x0004)) +#define PRISM_EVSTAT_ISTX(value) ((UINT16)(((UINT16)(value)) & 0x0002)) +#define PRISM_EVSTAT_ISRX(value) ((UINT16)(((UINT16)(value)) & 0x0001)) + +#define PRISM_EVENT_MASK ((UINT16)0xFFFF) +#define PRISM_INTEN_ENABLEBITS ((UINT16)0x008F) +#define PRISM_INTEN_DISABLE ((UINT16)0x0000) + +#define PRISM_INTEN_ISTICK(value) ((UINT16)(((UINT16)(value)) & 0x8000)) +#define PRISM_INTEN_TICK_SET(value) ((UINT16)(((UINT16)(value)) << 15)) +#define PRISM_INTEN_ISWTERR(value) ((UINT16)(((UINT16)(value)) & 0x4000)) +#define PRISM_INTEN_WTERR_SET(value) ((UINT16)(((UINT16)(value)) << 14)) +#define PRISM_INTEN_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & 0x2000)) +#define PRISM_INTEN_INFDROP_SET(value) ((UINT16)(((UINT16)(value)) << 13)) +#define PRISM_INTEN_ISINFO(value) ((UINT16)(((UINT16)(value)) & 0x0080)) +#define PRISM_INTEN_INFO_SET(value) ((UINT16)(((UINT16)(value)) << 7)) +#define PRISM_INTEN_ISDTIM(value) ((UINT16)(((UINT16)(value)) & 0x0020)) +#define PRISM_INTEN_DTIM_SET(value) ((UINT16)(((UINT16)(value)) << 5)) +#define PRISM_INTEN_ISCMD(value) ((UINT16)(((UINT16)(value)) & 0x0010)) +#define PRISM_INTEN_CMD_SET(value) ((UINT16)(((UINT16)(value)) << 4)) +#define PRISM_INTEN_ISALLOC(value) ((UINT16)(((UINT16)(value)) & 0x0008)) +#define PRISM_INTEN_ALLOC_SET(value) ((UINT16)(((UINT16)(value)) << 3)) +#define PRISM_INTEN_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & 0x0004)) +#define PRISM_INTEN_TXEXC_SET(value) ((UINT16)(((UINT16)(value)) << 2)) +#define PRISM_INTEN_ISTX(value) ((UINT16)(((UINT16)(value)) & 0x0002)) +#define PRISM_INTEN_TX_SET(value) ((UINT16)(((UINT16)(value)) << 1)) +#define PRISM_INTEN_ISRX(value) ((UINT16)(((UINT16)(value)) & 0x0001)) +#define PRISM_INTEN_RX_SET(value) ((UINT16)(((UINT16)(value)) << 0)) + +#define PRISM_EVACK_ISTICK(value) ((UINT16)(((UINT16)(value)) & 0x8000)) +#define PRISM_EVACK_TICK_SET(value) ((UINT16)(((UINT16)(value)) << 15)) +#define PRISM_EVACK_ISWTERR(value) ((UINT16)(((UINT16)(value)) & 0x4000)) +#define PRISM_EVACK_WTERR_SET(value) ((UINT16)(((UINT16)(value)) << 14)) +#define PRISM_EVACK_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & 0x2000)) +#define PRISM_EVACK_INFDROP_SET(value) ((UINT16)(((UINT16)(value)) << 13)) +#define PRISM_EVACK_ISINFO(value) ((UINT16)(((UINT16)(value)) & 0x0080)) +#define PRISM_EVACK_INFO_SET(value) ((UINT16)(((UINT16)(value)) << 7)) +#define PRISM_EVACK_ISDTIM(value) ((UINT16)(((UINT16)(value)) & 0x0020)) +#define PRISM_EVACK_DTIM_SET(value) ((UINT16)(((UINT16)(value)) << 5)) +#define PRISM_EVACK_ISCMD(value) ((UINT16)(((UINT16)(value)) & 0x0010)) +#define PRISM_EVACK_CMD_SET(value) ((UINT16)(((UINT16)(value)) << 4)) +#define PRISM_EVACK_ISALLOC(value) ((UINT16)(((UINT16)(value)) & 0x0008)) +#define PRISM_EVACK_ALLOC_SET(value) ((UINT16)(((UINT16)(value)) << 3)) +#define PRISM_EVACK_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & 0x0004)) +#define PRISM_EVACK_TXEXC_SET(value) ((UINT16)(((UINT16)(value)) << 2)) +#define PRISM_EVACK_ISTX(value) ((UINT16)(((UINT16)(value)) & 0x0002)) +#define PRISM_EVACK_TX_SET(value) ((UINT16)(((UINT16)(value)) << 1)) +#define PRISM_EVACK_ISRX(value) ((UINT16)(((UINT16)(value)) & 0x0001)) +#define PRISM_EVACK_RX_SET(value) ((UINT16)(((UINT16)(value)) << 0)) + +#define PRISM_CONTROL_AUXEN_SET(value) ((UINT16)(((UINT16)(value)) << 14)) +#define PRISM_CONTROL_AUXEN_GET(value) ((UINT16)(((UINT16)(value)) >> 14)) + +/* Communication Tallies' inquiry constants and data types */ + +#define PRISM_INQ_TALLIES (0xF100) +#define PRISM_INQ_SCAN (0xF101) +#define PRISM_INQ_LINKSTATUS (0xF200) +#define PRISM_INQ_ASSOCIATIONSTATUS (0xF201) +/*-------------------- Record ID Constants ----------------------------------------*/ + +/*----------------------------------------------------------------------------------*/ +/* Configuration RIDs: Network Parameters, Static Configuration Entities */ +/*----------------------------------------------------------------------------------*/ +#define PRISM_RID_CNFPORTTYPE ((UINT16)0xFC00) +#define PRISM_RID_CNFPORTTYPE_LEN ((UINT16)2) +#define PRISM_RID_CNFOWNMACADDR ((UINT16)0xFC01) +#define PRISM_RID_CNFOWNMACADDR_LEN ((UINT16)6) +#define PRISM_RID_CNFDESIREDSSID ((UINT16)0xFC02) +#define PRISM_RID_CNFDESIREDSSID_LEN ((UINT16)34) +#define PRISM_RID_CNFOWNCHANNEL ((UINT16)0xFC03) +#define PRISM_RID_CNFOWNCHANNEL_LEN ((UINT16)2) +#define PRISM_RID_CNFOWNSSID ((UINT16)0xFC04) +#define PRISM_RID_CNFOWNSSID_LEN ((UINT16)34) +#define PRISM_RID_CNFSYSTEMSCALE ((UINT16)0xFC06) +#define PRISM_RID_CNFSYSTEMSCALE_LEN ((UINT16)2) +#define PRISM_RID_CNFMAXDATALEN ((UINT16)0xFC07) +#define PRISM_RID_CNFMAXDATALEN_LEN ((UINT16)2) +#define PRISM_RID_CNFPMENABLED ((UINT16)0xFC09) +#define PRISM_RID_CNFPMENABLED_LEN ((UINT16)2) +#define PRISM_RID_CNFMULTICASTRECEIVE ((UINT16)0xFC0B) +#define PRISM_RID_CNFMULTICASTRECEIVE_LEN ((UINT16)2) +#define PRISM_RID_CNFMAXSLEEPDURATION ((UINT16)0xFC0C) +#define PRISM_RID_CNFMAXSLEEPDURATION_LEN ((UINT16)2) +#define PRISM_RID_CNFPMHOLDOVERDURATION ((UINT16)0xFC0D) +#define PRISM_RID_CNFPMHOLDOVERDURATION_LEN ((UINT16)2) +#define PRISM_RID_CNFWEPDEFAULTKEYID ((UINT16)0xFC23) +#define PRISM_RID_CNFWEPDEFAULTKEYID_LEN ((UINT16)sizeof(UINT16)) +#define PRISM_RID_CNFDEFAULTKEY0 ((UINT16)0xFC24) +#define PRISM_RID_CNFDEFAULTKEY1 ((UINT16)0xFC25) +#define PRISM_RID_CNFDEFAULTKEY2 ((UINT16)0xFC26) +#define PRISM_RID_CNFDEFAULTKEY3 ((UINT16)0xFC27) +#define PRISM_RID_CNFWEPFLAGS ((UINT16)0xFC28) +#define PRISM_RID_CNFWEPFLAGS_LEN ((UINT16)sizeof(UINT16)) +#define PRISM_RID_CNFAUTHENTICATION ((UINT16)0xFC2A) +#define PRISM_RID_CNFAUTHENTICATION_LEN ((UINT16)sizeof(UINT16)) +#define PRISM_RID_CNFBASICRATES ((UINT16)0xFCB3) +#define PRISM_RID_CNFBASICRATES_LEN ((UINT16)2) +#define PRISM_RID_CNFSUPPRATES ((UINT16)0xFCB4) +#define PRISM_RID_CNFSUPPRATES_LEN ((UINT16)2) +#define PRISM_RID_TXRATECNTL0 ((UINT16)0xFC9E) +#define PRISM_RID_TXRATECNTL0_LEN ((UINT16)2) + +#define PRISM_RID_CNFBEACONINTERVAL ((UINT16)0xFC33) +#define PRISM_RID_CNFBEACONINTERVAL_LEN ((UINT16)2) +#define PRISM_RID_CNFOWNDTIMPERIOD ((UINT16)0xFC10) +#define PRISM_RID_CNFOWNDTIMPERIOD_LEN ((UINT16)2) + + +/* Power management flags available (along with the value, if any) */ +#define IW_POWER_ON 0x0000 /* No details... */ +#define IW_POWER_TYPE 0xF000 /* Type of parameter */ +#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ +#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ +#define IW_POWER_MODE 0x0F00 /* Power Management mode */ +#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ +#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ +#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ +#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ +#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + +/*--------------------------------------------------------------------------------*/ +/* Configuration RIDs: Network Parameters, Dynamic Configuration Entities */ +/*--------------------------------------------------------------------------------*/ +#define PRISM_RID_GROUPADDRESSES ((UINT16)0xFC80) +#define PRISM_RID_NFCREATEIBSS ((UINT16)0xFC81) +#define PRISM_RID_NFCREATEIBSS_LEN ((UINT16)2) +#define PRISM_RID_RTSTHRESHOLD ((UINT16)0xFC83) +#define PRISM_RID_RTSTHRESHOLD_LEN ((UINT16)2) +#define PRISM_RID_TXRATECNTL ((UINT16)0xFC84) +#define PRISM_RID_TXRATECNTL_LEN ((UINT16)2) + +#define PRISM_RID_PROMISCUOUS ((UINT16)0xFC85) +#define PRISM_RID_PROMISCUOUS_LEN ((UINT16)2) +#define PRISM_Promoscuous_Enable ((UINT16)0x0001) +#define PRISM_Promoscuous_Disable ((UINT16)0x0000) + + +/*------------------------------------------------------------------------------*/ +/* Information RIDs: NIC Information */ +/*------------------------------------------------------------------------------*/ +#define PRSIM_NIC_DOWNLOADBUFFER ((UINT16)0xFD01) +#define PRISM_RID_CIS ((UINT16)0xFD13) +#define PRISM_RID_CIS_LEN ((UINT16)480) + + +/*-------------------------------------------------------------------------*/ +/* Information RIDs: MAC Information */ +/*-------------------------------------------------------------------------*/ +#define PRISM_RID_PORTSTATUS ((UINT16)0xFD40) +#define PRISM_RID_PORTSTATUS_LEN ((UINT16)0) +#define PRISM_RID_CURRENTSSID ((UINT16)0xFD41) +#define PRISM_RID_CURRENTSSID_LEN ((UINT16)34) +#define PRISM_RID_CURRENTBSSID ((UINT16)0xFD42) +#define PRISM_RID_CURRENTBSSID_LEN ((UINT16)6) +#define PRISM_RID_COMMSQUALITY ((UINT16)0xFD43) +#define PRISM_RID_COMMSQUALITY_LEN ((UINT16)6) +#define PRISM_RID_CURRENTTXRATE ((UINT16)0xFD44) +#define PRISM_RID_CURRENTTXRATE_LEN ((UINT16)2) +#define PRISM_RID_OWNMACADDRESS ((UINT16)0xFD86) +#define PRISM_RID_SCANRESULT ((UINT16)0xFD88) +/*------------------------------------------------------------------------------*/ +/* Information RIDs: Modem information */ +/*------------------------------------------------------------------------------*/ +#define PRISM_RID_CURRENTCHANNEL ((UINT16)0xFDC1) /* used */ + +/*----------------------------------------------------------------------*/ +/* Information Frames */ +/*----------------------------------------------------------------------*/ +#define PRISM_CT_LINKSTATUS ((UINT16)0xF200) +#define PRISM_CT_SCANRESUTL ((UINT16)0xF101) + +/*--------------------------------------------------------------------------------------*/ +/* Communication Frames: Test/Get/Set Field Values for Transmit Frames */ +/*--------------------------------------------------------------------------------------*/ +/*--------------- Status Field ---------------*/ +#define PRISM_TXSTATUS_ISFORMERR(v) ((UINT16)(((UINT16)(v)) & 0x0008)) +#define PRISM_TXSTATUS_ISDISCON(v) ((UINT16)(((UINT16)(v)) & 0x0004)) +#define PRISM_TXSTATUS_ISAGEDERR(v) ((UINT16)(((UINT16)(v)) & 0x0002)) +#define PRISM_TXSTATUS_ISRETRYERR(v) ((UINT16)(((UINT16)(v)) & 0x0001)) + +#define PRISM_TX_GET(v,m,s) ((((UINT16)(v))&((UINT16)(m)))>>((UINT16)(s))) +#define PRISM_TX_SET(v,m,s) ((((UINT16)(v))<<((UINT16)(s)))&((UINT16)(m))) + +#define PRISM_TX_MACPORT_GET(v) PRISM_TX_GET(v, 0x0700, 8) +#define PRISM_TX_MACPORT_SET(v) PRISM_TX_SET(v, 0x0700, 8) +#define PRISM_TX_NOENCRYPT_GET(v) PRISM_TX_GET(v, 0x0080, 7) +#define PRISM_TX_NOENCRYPT_SET(v) PRISM_TX_SET(v, 0x0080, 7) +#define PRISM_TX_RETRYSTRAT_GET(v) PRISM_TX_GET(v, 0x0020, 5) +#define PRISM_TX_RETRYSTRAT_SET(v) PRISM_TX_SET(v, 0x0020, 5) +#define PRISM_TX_STRUCTYPE_GET(v) PRISM_TX_GET(v, 0x0018, 3) +#define PRISM_TX_STRUCTYPE_SET(v) PRISM_TX_SET(v, 0x0018, 3) +#define PRISM_TX_TXEX_GET(v) PRISM_TX_GET(v, 0x0004, 2) +#define PRISM_TX_TXEX_SET(v) PRISM_TX_SET(v, 0x0004, 2) +#define PRISM_TX_TXOK_GET(v) PRISM_TX_GET(v, 0x0002, 1) +#define PRISM_TX_TXOK_SET(v) PRISM_TX_SET(v, 0x0002, 1) + + +/*----------------------------------------------------------------------*/ +/* FRAME DESCRIPTORS AND FRAME STRUCTURES */ +/* FRAME DESCRIPTORS: Offsets */ +/*----------------------------------------------------------------------*/ +/*-------------Control Info---------------*/ +#define PRISM_FD_STATUS ((UINT16)0x00) +#define PRISM_FD_SWSUPPORT ((UINT16)0x03) +#define PRISM_FD_SILENCE ((UINT16)0x03) +#define PRISM_FD_SIGNAL ((UINT16)0x03) +#define PRISM_FD_RATE ((UINT16)0x04) +#define PRISM_FD_TXRATE ((UINT16)0x05) +#define PRISM_FD_RETRYCOUNT ((UINT16)0x05) +#define PRISM_FD_TXCONTROL ((UINT16)0x06) + +/*-------------802.11 Header---------------*/ +#define PRISM_FD_FRAMECONTROL ((UINT16)0x07) +#define PRISM_FD_DURATIONID ((UINT16)0x08) +#define PRISM_FD_ADDRESS1 ((UINT16)0x09) +#define PRISM_FD_ADDRESS2 ((UINT16)0x12) +#define PRISM_FD_ADDRESS3 ((UINT16)0x15) +#define PRISM_FD_SEQCONTROL ((UINT16)0x18) +#define PRISM_FD_ADDRESS4 ((UINT16)0x19) +#define PRISM_FD_DATALEN ((UINT16)0x22) + +/*--------------802.3 Header----------------*/ +#define PRISM_FD_DESTADDRESS ((UINT16)0x23) +#define PRISM_FD_SRCADDRESS ((UINT16)0x26) +#define PRISM_FD_DATALENGTH ((UINT16)0x29) + +/*--------------prism defines----------------*/ +#define PRISM2_TX_FIDSTACKLEN_MAX 6 +#define PRISM2_FIDSTACKLEN_MAX 16 + +#define HERMES_EV_CMD (0x0010) +#define HERMES_STATUS_RESULT (0x7f00) + +#define TX_TIMEOUT (HZ) + +/*-------------------------for encode---------------------------------*/ +/* Maximum number of size of encoding token available + * they are listed in the range structure */ +#define IW_MAX_ENCODING_SIZES 8 + +/* Maximum size of the encoding token in bytes */ +#define IW_ENCODING_TOKEN_MAX 32 /* 256 bits (for now) */ + +/* Flags for encoding (along with the token) */ +#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ +#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ +#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ +#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ +#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ + + +/*---------------------------------------------------------------------------*/ +/* Communication Frame: Transmit Frame Structure */ +/*---------------------------------------------------------------------------*/ +struct hermes_tx_descriptor { + u16 status; + u16 reserved1; + u16 reserved2; + u32 sw_support; + u8 retry_count; + u8 tx_rate; + u16 tx_control; +} __attribute__ ((packed)); + +struct header_struct { + /* 802.3 */ + u8 dest[ETH_ALEN]; + u8 src[ETH_ALEN]; + u16 len; + /* 802.2 */ + u8 dsap; + u8 ssap; + u8 ctrl; + /* SNAP */ + u8 oui[3]; + u16 ethertype; +} __attribute__ ((packed)); + +struct prism_tx_frame +{ + UINT16 status; + UINT16 reserved1; + UINT16 reserved2; + UINT16 sw_support0; + UINT16 sw_support1; + UINT16 reserved3; + UINT16 tx_control; + + /*-- 802.11 Header Information --*/ + + UINT16 frame_control; + UINT16 duration_id; + UINT8 address1[6]; + UINT8 address2[6]; + UINT8 address3[6]; + UINT16 sequence_control; + UINT8 address4[6]; + UINT16 data_len; /* little endian format */ + + /*-- 802.3 Header Information --*/ + + UINT8 dest_addr[6]; + UINT8 src_addr[6]; + UINT16 data_length; /* big endian format */ + UINT8 llc_data[6]; +} __attribute__ ((packed));; + +typedef struct prism_tx_frame prism_tx_frame_t; + +/*----------------------------------------------------------------*/ +/* Communication Frame: Receive Frame Structure */ +/*----------------------------------------------------------------*/ +struct prism_rx_frame +{ + /*-- MAC rx descriptor (prism byte order) --*/ + UINT16 status; + UINT16 reserved0; + UINT16 reserved1; + UINT8 silence; + UINT8 signal; + UINT8 rate; + UINT8 reserved2; + UINT16 reserved3; + UINT16 reserved4; + + /*-- 802.11 Header Information (802.11 byte order) --*/ + UINT16 frame_control; + UINT16 duration_id; + UINT8 address1[6]; + UINT8 address2[6]; + UINT8 address3[6]; + UINT16 sequence_control; + UINT8 address4[6]; + UINT16 data_len; /* little endian format */ + + /*-- 802.3 Header Information --*/ + UINT8 dest_addr[6]; + UINT8 src_addr[6]; + UINT16 data_length; /* big endian format */ +} __attribute__ ((packed)); +typedef struct prism_rx_frame prism_rx_frame_t; + +/*------------------------------------------------------------------*/ +/* MAC state structure, argument to all functions */ +/*------------------------------------------------------------------*/ +/*--prism hardware record----*/ +typedef struct prism_record +{ + UINT16 reclen; + UINT16 rid; +} prism_rec_t; + +/*------ RID Structure---------*/ +typedef struct prism_cnfDesireSSID +{ + UINT16 ssidLen __WLAN_ATTRIB_PACK__; + UINT8 ssidName[32] __WLAN_ATTRIB_PACK__; +}__WLAN_ATTRIB_PACK__ prism_cnfDesireSSID_t; + + +typedef struct prism_pdaRec +{ + unsigned short len; + unsigned short id; + unsigned short buf[60]; +} prism_pdaRec_t; + +#define SCAN_ENABLE +#ifdef SCAN_ENABLE + +typedef struct prism_ScanResultSub +{ + UINT16 chid __WLAN_ATTRIB_PACK__; + UINT16 anl __WLAN_ATTRIB_PACK__; + UINT16 sl __WLAN_ATTRIB_PACK__; + UINT8 bssid[6] __WLAN_ATTRIB_PACK__; + UINT16 bcnint __WLAN_ATTRIB_PACK__; + UINT16 capinfo __WLAN_ATTRIB_PACK__; + struct prism_cnfDesireSSID ssid __WLAN_ATTRIB_PACK__; + UINT8 supprates[10] __WLAN_ATTRIB_PACK__; /* 802.11 info element */ + UINT16 proberesp_rate __WLAN_ATTRIB_PACK__; +}__WLAN_ATTRIB_PACK__ prism_ScanResultSub_t; + +typedef struct prism_ScanResult +{ + UINT16 rsvd __WLAN_ATTRIB_PACK__; + UINT16 scanreason __WLAN_ATTRIB_PACK__; + struct prism_ScanResultSub result[35] __WLAN_ATTRIB_PACK__; +}__WLAN_ATTRIB_PACK__ prism_ScanResult_t; + +#endif + + +/*-------prism cmd responses-------*/ +typedef struct hermes_response { + UINT16 status, resp0, resp1, resp2; +} hermes_response_t; + +#define PRISM_MAX_KEY_SIZE 14 +#define PRISM_MAX_KEYS 4 + +#define SMALL_KEY_SIZE 5 +#define LARGE_KEY_SIZE 13 + +typedef struct prism_key { + u16 len; /* always store little-endian */ + char data[PRISM_MAX_KEY_SIZE]; +} __attribute__ ((packed)) prism_key_t; + +typedef prism_key_t prism_keys_t[PRISM_MAX_KEYS]; + +/*-----------------driver wireless default setting---------------------*/ +#define DEFAULT_TXRATE_MODE 0x00 +#define DEFAULT_RXSTHRESHOLD 2432 +#define DEFAULT_SENSE 1 +#define DEFAULT_POWMANAGE 0 +#define DEFAULT_MULITRECEIVE 1 +#define DEFAULT_MAXSLEEP 100 +#define DEFAULT_PMHOLDDURATION 100 +/*----------------------------------------------------*/ +/* PRISM For W90N745 Definition */ +/*----------------------------------------------------*/ +#define WIRELESS_SPY // enable iwspy support + +#ifdef WIRELESS_SPY +#define SPY_NUMBER(priv) (priv->spy_number) +#else +#define SPY_NUMBER(priv) 0 +#endif /* WIRELESS_SPY */ + +struct w740prism_priv { + struct net_device_stats stats; + struct iw_statistics wstats; + int status; // wireless link status; + // -1: setup fail + // 0: setup ok + // 1: connected + // 2: disconnected + // 3: Access Point Change + // 4: Access Point Out of Range + // 5: Access Point In Range + // 6: Association failed + unsigned char mac_address[ETH_ALEN] __attribute__ ((aligned (2))); + + int rx_packetlen; + u8 *rx_packetdata; + int tx_packetlen; + u8 *tx_packetdata; + struct sk_buff *skb; + + unsigned short txfid; /* use for debug */ + struct net_device * ndev; + + u16 wep_on, wep_restrict, tx_key; + prism_keys_t keys; + + /* Configuration paramaters */ + u32 iw_mode; + int prefer_port3; + int bitratemode; + char nick[IW_ESSID_MAX_SIZE+1] __attribute__ ((aligned (2))); + char desired_essid[IW_ESSID_MAX_SIZE+1] __attribute__ ((aligned (2))); + u16 frag_thresh, mwo_robust; + u16 channel; + u16 ap_density, rts_thresh; + u16 pm_on, pm_mcast, pm_period, pm_timeout; + u16 preamble; +#ifdef WIRELESS_SPY + int spy_number; + u8 spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif +#ifdef SCAN_ENABLE + prism_ScanResult_t scan_res; + int scan_res_len; +#endif + /* Configuration dependent variables */ + int port_type, allow_ibss; + int promiscuous, mc_count; + + struct semaphore sema; /* to sleep on */ + spinlock_t lock; +}; + + +#ifdef WDEBUG +/*------------------Debug use--------------------*/ +#define LOGPRINT printk("%s: %d\n", __FILE__,__LINE__) +#define DEBUG printk + +#else +#define LOGPRINT +#define DEBUG +#endif +//#define DEBUGPRINT +//#define NEWDOCMD + + +/*-----------------------------------------*/ +/* Inline functions */ +/*-----------------------------------------*/ +static inline void +prism_lock(struct w740prism_priv *priv) +{ + spin_lock_bh(&priv->lock); +} + +static inline void +prism_unlock(struct w740prism_priv *priv) +{ + spin_unlock_bh(&priv->lock); +} + +/*----------------------------------------------------*/ +/* PRISM For W90N745 Definition */ +/*----------------------------------------------------*/ +/*--------prism initialize set up value-------------*/ +#define PRISM_TxRate ((UINT16)0x000F) +#define PRISM_Authentication ((UINT16)0x0003) +#define PRISM_MacPortType ((UINT16)0x0001) +#define PRISM_Default_Channel ((UINT16)0x0009) +#define PRISM_Support_Rate ((UINT16)0x000F) +#define PRISM_Beacon_Interval ((UINT16)1000) +#define PRISM_DTIM_Period ((UINT16)0x0003) +#define PRISM_MAX_DATA_LEN ((UINT16)2304) + +/*-------------transmit frame buffer declaration---------------*/ +#define FRAME_DATA_MAXLEN 2304 +#define PRISM2_TXBUF_MAX (sizeof(prism_tx_frame_t) + FRAME_DATA_MAXLEN) + +#if 0 //def _BIG_ENDIAN +#define PRISM_FrameControl ((UINT16)0x0801) // ToDS = 1, FromDS = 0 STA mode +#define PRISM_DurationID ((UINT16)0x0000) +#else +#define PRISM_FrameControl ((UINT16)0x0108) // ToDS = 1, FromDS = 0 STA mode +#define PRISM_DurationID ((UINT16)0x0000) +#endif //def _BIG_ENDIAN + +/* These are maximum timeouts. Most often, card wil react much faster */ +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (1500) /* in iterations of ~10us */ +//#define CMD_COMPL_TIMEOUT (2000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ +#define BAP_BUSY_TIMEOUT (500) /* in iterations of ~1us */ + +#define MAX_IRQLOOPS_PER_IRQ 10 +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the + device can legitimately generate */ +#define HERMES_DESCRIPTOR_OFFSET 0 +#define HERMES_802_11_OFFSET (14) +#define HERMES_802_3_OFFSET (14+32) +#define HERMES_802_2_OFFSET (14+32+14) + +#define DUMMY_FID 0xFFFF + +#define ENCAPS_OVERHEAD (6*sizeof(char) + 2) + +#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) + + + +/*-----------------------------------function declares-------------------------*/ +/*------------ module routine------------- */ +int prism_init_module(void); +void prism_cleanup(void); +int prism_init(struct net_device *dev); + +/*------------------------------driver routine------------------------------*/ +/* open */ +int prism_open(struct net_device *dev); +/* as close */ +int prism_release(struct net_device *dev); +/* upper level software call to send package */ +int prism_start_tx(struct sk_buff *skb, struct net_device *dev); +/* send buffer */ +static int send_frame(struct net_device *dev ,unsigned char *data,int length); +/* prism get package from internal to upper level software */ +void prism_rx(struct net_device *dev); +/* prism get communication information */ +int prism_info(struct net_device *dev); +/* interrupt event handle function */ +void prism_interrupt(int irq, void *dev_id, struct pt_regs *regs); +/* mac driver's ioctl */ +int prism_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +/* multicast function */ +static void prism_set_multicast_list(struct net_device *dev); +/* check after tx */ +int prism_tx(struct net_device *dev); +/* timeout handle */ +void prism_tx_timeout (struct net_device *dev); +/* set mac address */ +static int prism_set_mac_address(struct net_device *dev, void *addr); +/* net device stat */ +struct net_device_stats *prism_stats(struct net_device *dev); +/* net device reset */ +int prism_reset(struct w740prism_priv *priv); + +/* ------------------------------prism's operation ------------------------------*/ +/* prism init in W90N745 */ +int prism_initmac(struct net_device *dev); +/* init command operation */ +int prism_cmd_initialize(); +/* copy content to prism though buffer access path */ +int prism_copy_to_bap(UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT32 len); +/* copy buffer from prsim though buffer access path */ +int prism_copy_from_bap(UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT32 len); +/* alloc buffer for tx */ +int prism_cmd_allocate(UINT16 len, unsigned short *txfid); +/* reset this card */ +int prism_reset_device(struct net_device *dev); +/* send command to prism and wait */ +#ifndef NEWDOCMD +int prism_docmd_wait(UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2); +int prism_docmd_nowait(UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2); +#else +//int prism_docmd_wait(UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2, hermes_response_t *resp); +int prism_docmd_wait(UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2); +int hermes_issue_cmd(UINT16 cmd, UINT16 param0, UINT16 param1, UINT16 param2); +#endif +int prism_cmd_access(UINT16 write, UINT16 rid); +int prism_cmd_diagnose(); +int prism_config(struct net_device *dev, struct ifmap *map); +int prism_cmd_enable(UINT16 macport); +int prism_cmd_disable(UINT16 macport); +/* command to start transmit which parameter is fid */ +int prism_cmd_transmit(UINT16 reclaim, UINT16 fid); +int prism_cmd_inquiry(UINT16 infoType); +int Write_RID_Config(UINT16 rid, void *buf, UINT16 len); +int Read_RID_Config(UINT16 rid, void *buf); +int Read_CT_InfoType(UINT16 Infofid, UINT16 *len); +int Read_CT_InfoData(UINT16 Infofid, void *buf, int len); +void prism_txexc(); + +/* ioctl extends functions */ +int prism_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +int prism_ioctl_setessid(struct net_device *dev, struct iw_point *essid); +long prism_hw_get_freq(struct w740prism_priv *priv); +int prism_ioctl_setfreq(struct net_device *dev, struct iw_freq *freq); +int prism_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +int prism_hw_setup_wep(struct w740prism_priv *priv); +int prism_hw_get_bssid(struct net_device *dev, char buf[ETH_ALEN]); +int prism_ioctl_getlinkstat(struct net_device *dev, struct iw_point *erq); +int prism_ioctl_getiwrate(struct net_device *dev, struct iw_param *iwp); +int prism_ioctl_setiwrate(struct net_device *dev, struct iw_param *iwp); +int prism_hw_setiwrate(struct w740prism_priv *priv); +int prism_ioctl_setrts(struct net_device *dev, struct iw_param *iwp); +int prism_ioctl_getsens(struct net_device *dev, struct iw_param *iwp); +int prism_ioctl_setsens(struct net_device *dev, struct iw_param *iwp); +int prism_hw_setapdensity(struct w740prism_priv *priv); +int prism_ioctl_getpower(struct net_device *dev, struct iw_param *iwp); +int prism_ioctl_setpower(struct net_device *dev, struct iw_param *iwp); +int prism_hw_setpower(struct w740prism_priv *priv); +int get_scan_result(UINT16 infoid, int lens, struct w740prism_priv *priv); +int prism_ioctl_getaplist(struct net_device *dev, struct iw_point * iwp); +void set_port_type(struct w740prism_priv *priv); +int prism_ioctl_setspy(struct net_device *dev, struct iw_point *iwp); +int prism_ioctl_getspy(struct net_device *dev, struct iw_point *iwp); +/*------------------Swap macro------------------*/ +static inline unsigned short Swap16(unsigned short val) +{ + return ((val & 0xFF) <<8) | ((val &0xFF00) >>8); +} + +/*----------------Test card present--------------*/ +static inline int hermes_present() +{ + UINT32 value = READREG(PRISM_SWSUPPORT0); + printk("hermes_present: %x\n", value); + return (value == HERMES_MAGIC); +} +#endif diff --git a/uClinux-2.4.20-uc1/drivers/net/wireless/base.c b/uClinux-2.4.20-uc1/drivers/net/wireless/base.c new file mode 100755 index 0000000..4d0f17a --- /dev/null +++ b/uClinux-2.4.20-uc1/drivers/net/wireless/base.c @@ -0,0 +1,1783 @@ +/*------------------------------------------------------------------------------*/
+/* Wireless driver base functions for winbond W90N745 */
+/* version 1.0.2(used only for Station) */
+/*------------------------------------------------------------------------------*/
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "W90N745Prism.h"
+#include "Queue.h"
+
+#if 0
+#define PRISM_SSIDLEN_DEFAULT ((UINT16)0x0008)
+char PRISM_DesireSSID_DEFAULT[] = {(char)'P', (char)'C', (char)'3',(char)'0',(char)'W',
+ (char)'L', (char)'A', (char)'N'};
+#else
+#define PRISM_SSIDLEN_DEFAULT ((UINT16)0x000a)
+char PRISM_DesireSSID_DEFAULT[] __attribute__ ((aligned (2)))
+ = {(char)'P', (char)'C', (char)'3', (char)'2',(char)'W',
+ (char)'e', (char)'b', (char)'C', (char)'a',(char)'m'};
+#endif// declararion desired SSID
+
+// Access Point's MAC address
+char PRISM_BSSID[] = {(char)0x00,(char)0x05,(char)0x5D,(char)0xEB,(char)0x94,(char)0x24};
+
+// 802.11 frame header type RFC1042
+char PRISM_LLC[] = {(char)0xaa,(char)0xaa,(char)0x03,(char)0x00,(char)0x00,(char)0x00};
+
+#if 1
+ //unsigned char Mac_address[6] = {0x00, 0x60, 0xB3, 0x73, 0x26, 0x3d};
+ unsigned char Mac_address[6] = {0x00, 0x60, 0xB3, 0x73, 0x26, 0x3C};
+#else
+ unsigned char Mac_address[6] = {0x00, 0x60, 0xB3, 0x73, 0x26, 0x3E};
+#endif
+/* Debug for now */
+UINT8 *DebugpBuffer = NULL;
+
+Queue_txfid TxQueueObj;
+
+/* The frequency of each channel in MHz */
+const long channel_frequency[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )
+
+/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */
+struct {
+ int bitrate; /* in 100s of kilbits */
+ u16 prism_txratectrl;
+} bitrate_table[] = {
+ {110, 15}, /* Entry 0 is the default */
+ {10, 1},
+ {20, 2},
+ {20, 3},
+ {55, 4},
+ {55, 7},
+ {110, 8},
+};
+#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
+//#define PRSIM_DEBUG
+int nums = 5;
+
+/*------------------------------Prism Base Functions ----------------------------------*/
+/* */
+int prism_cmd_access(UINT16 write, UINT16 rid)
+{
+ int result = 0;
+ UINT16 cmd;
+
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_ACCESS)|PRISM_CMD_WRITE_SET(write);
+ result = prism_docmd_wait(cmd, rid, 0, 0);
+ return result;
+}
+
+/* prism transmit a buffer command, fid-->buffer */
+int prism_cmd_transmit(UINT16 reclaim, UINT16 fid)
+{
+ int result = 0;
+ UINT16 cmd;
+
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_TX)|PRISM_CMD_RECL_SET(reclaim);
+ result = prism_docmd_wait(cmd, fid, 0, 0);
+ return result;
+}
+
+int prism_cmd_inquiry(UINT16 infoType)
+{
+ int result = 0;
+ UINT16 cmd;
+
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_INQ);
+ result = prism_docmd_nowait(cmd, infoType, 0, 0);
+
+ return result;
+}
+
+/* after init, the net device should be enabled */
+int prism_cmd_enable(UINT16 macport)
+{
+ int result = 0;
+ UINT16 cmd;
+
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_ENABLE)|PRISM_CMD_MACPORT_SET(macport);
+ result = prism_docmd_wait(cmd, 0,0,0);
+ return result;
+}
+
+/* the net device disable function */
+int prism_cmd_disable(UINT16 macport)
+{
+ int result = 0;
+ UINT16 cmd;
+
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_DISABLE)| PRISM_CMD_MACPORT_SET(macport);
+ result = prism_docmd_wait(cmd, 0,0,0);
+ return result;
+}
+
+/* when status register need us to diagnose, do it */
+int prism_cmd_diagnose()
+{
+ int result = 0;
+ UINT16 cmd;
+
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_DIAG);
+ result = prism_docmd_wait(cmd, DIAG_PATTERNA, DIAG_PATTERNB, 0);
+ return result;
+}
+
+/* copy data to buffer access path */
+/* Note: only accept the buf which address is align 2 in our arm7 system */
+int prism_copy_to_bap(UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT32 len)
+{
+ int result = 0;
+ UINT8 *d = (UINT8*)buf;
+ UINT16 *dw = buf;
+ UINT32 selectreg;
+ UINT32 offsetreg;
+ UINT32 datareg;
+ UINT32 i;
+ volatile UINT16 reg;
+ UINT16 savereg;
+ int k = 0;
+
+ selectreg = bap ? PRISM_SELECT1 : PRISM_SELECT0;
+ offsetreg = bap ? PRISM_OFFSET1 : PRISM_OFFSET0;
+ datareg = bap ? PRISM_DATA1 : PRISM_DATA0;
+
+
+ k = BAP_BUSY_TIMEOUT;
+ /* Write id to select reg */
+ reg = READREG(offsetreg);
+ while(PRISM_OFFSET_ISBUSY(reg) && k) {
+ k--;
+ udelay(5);
+ reg = READREG(offsetreg);
+ }
+
+ if(!k) {
+ result = -1;
+ LOGPRINT;
+ goto failed;
+ }
+ if (PRISM_OFFSET_ISERR(reg)) {
+ result = -1;
+ LOGPRINT;
+ return result;
+ }
+
+ WRITEREG(selectreg, id);
+
+ k = BAP_BUSY_TIMEOUT;
+ /* Write offset to offset reg */
+ reg = READREG(offsetreg);
+ while (PRISM_OFFSET_ISBUSY(reg) && k) {
+ k--;
+ udelay(5);
+ reg = READREG(offsetreg);
+ }
+ if(!k) {
+ result = -1;
+ LOGPRINT;
+ goto failed;
+ }
+ if (PRISM_OFFSET_ISERR(reg)) {
+ result = -1;
+ LOGPRINT;
+ return result;
+ }
+
+ WRITEREG(offsetreg, offset);
+
+ k = BAP_BUSY_TIMEOUT;
+ /* Wait for offset[busy] to clear */
+ reg = READREG(offsetreg);
+ while (PRISM_OFFSET_ISBUSY(reg) && k) {
+ k--;
+ udelay(5);
+ reg = READREG(offsetreg);
+ }
+ if (PRISM_OFFSET_ISERR(reg)) {
+ result = -1;
+ LOGPRINT;
+ return result;
+ }
+ /* Write even(len) buf contents to data reg */
+ for ( i = 0; i < (len>>1); i++ ) {
+ WRITEREG(datareg, *dw++);
+ }
+
+ /* If len odd, handle last byte */
+ if ( len % 2 )
+ {
+ savereg = READREG(datareg);
+ WRITEREG(offsetreg, (offset+(len&0xfffe)));
+
+ /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
+ k = BAP_BUSY_TIMEOUT;
+ reg = READREG(offsetreg);
+ while (PRISM_OFFSET_ISBUSY(reg) && k) {
+ k--;
+ udelay(5);
+ reg = READREG(offsetreg);
+ }
+ if(!k) {
+ result = -1;
+ LOGPRINT;
+ goto failed;
+ }
+ ((UINT8*)(&savereg))[0] = d[len-1];
+ WRITEREG(datareg, savereg);
+ }
+failed:
+ if (result)
+ printk("copy_to_bap failed\r\n");
+ return result;
+}
+
+
+/* Set configuration / information record */
+int Write_RID_Config(UINT16 rid, void *buf, UINT16 len)
+{
+ int result = 0;
+ prism_rec_t rec;
+
+ rec.rid = rid;
+ rec.reclen = (len/2)?((len+1)/2+1):((len/2) + 1);
+
+ /* write the record header */
+ result = prism_copy_to_bap(USER_BAP, rid, 0, &rec, 4);
+ if ( result )
+ printk("Failure writing record header\n");
+
+ /* write the record data (if there is any) */
+ if ( len > 0 )
+ {
+ result = prism_copy_to_bap(USER_BAP, rid, 4, buf, len);
+ if ( result )
+ printk("Failure writing record data\r\n");
+ }
+ result = prism_cmd_access(1, rid);
+ return result;
+}
+
+/* get configuration / information record */
+int Read_RID_Config(UINT16 rid, void *buf)
+{
+ int result = 0;
+ prism_rec_t rec;
+ short len;
+
+ result = prism_cmd_access(0, rid);
+
+ /* read the record header */
+ result = prism_copy_from_bap(IRQ_BAP, rid, 0, &rec, 4);
+ if ( result ) {
+ result = -1;
+ printk("Failure writing record header\r\n");
+ goto fail;
+ }
+
+ len = (rec.reclen-1)*2;
+#ifdef WDEBUG
+ printk("len:%d, rec.len: %d\n", len, rec.reclen);
+#endif
+
+ /* read the record data (if there is any) */
+ if(len > 0);
+ {
+ result = prism_copy_from_bap(IRQ_BAP, rid, 4, buf, len);
+ if ( result ) {
+ result = -1;
+ printk("Failure writing record data\r\n");
+ goto fail;
+ }
+ }
+ result = rec.reclen;
+fail:
+ return result;
+}
+
+/* get Communication Tallies record's type and length*/
+int Read_CT_InfoType(UINT16 Infofid, UINT16 *len)
+{
+ int result = 0;
+ prism_rec_t rec;
+
+ result = prism_copy_from_bap(IRQ_BAP, Infofid, 0, &rec, 4);
+ if ( result ) {
+ result = -1;
+ printk("Failure writing record header\r\n");
+ goto fail;
+ }
+
+ *len = (rec.reclen-1)*2;
+ result = rec.rid;
+fail:
+ return result;
+}
+
+/* get Commnication Tallies record's data */
+int Read_CT_InfoData(UINT16 Infofid, void *buf, int len)
+{
+
+ int result = 0;
+
+ /* read the record data (if there is any) */
+ if(len > 0);
+ {
+ result = prism_copy_from_bap(USER_BAP, Infofid, 4, buf, len);//??user_bap
+ if ( result ) {
+ result = -1;
+ printk("Failure writing record data\r\n");
+ goto fail;
+ }
+ }
+ result = len;
+fail:
+
+ return result;
+}
+
+
+/*------------------------------------------------------------------*/
+/* send a command to device and wait for completion */
+int prism_docmd_wait(UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2)
+{
+ volatile UINT16 reg;
+ volatile UINT16 result;
+ volatile UINT16 counter, i;
+
+ volatile UINT16 prismStatus;
+ volatile UINT16 prismResp0;
+ volatile UINT16 prismResp1;
+ volatile UINT16 prismResp2;
+
+ i = CMD_BUSY_TIMEOUT;
+ /* wait for the busy bit to clear */
+ reg = READREG(PRISM_CMD);
+ while (PRISM_CMD_ISBUSY(reg) && i) {
+ i--;
+ udelay(5);
+ reg = READREG(PRISM_CMD);
+ }
+
+ if (!PRISM_CMD_ISBUSY(reg))
+ {
+ /* busy bit clear, write command */
+ WRITEREG(PRISM_PARAM0, parm0);
+ WRITEREG(PRISM_PARAM1, parm1);
+ WRITEREG(PRISM_PARAM2, parm2);
+ WRITEREG(PRISM_CMD, cmd);
+
+ /* Now wait for completion */
+ counter = 0;
+ reg = READREG(PRISM_EVSTAT);
+ /* if is TX cmd, timout/30 */
+ if((cmd&0x1f) == PRISM_CMDCODE_TX)
+ i = CMD_COMPL_TIMEOUT/30;
+ else
+ i = CMD_COMPL_TIMEOUT;
+ while (!PRISM_EVSTAT_ISCMD(reg) && i)
+ {
+ i--;
+ udelay(10);
+ reg = READREG(PRISM_EVSTAT);
+ }
+
+ if (PRISM_EVSTAT_ISCMD(reg))
+ {
+ result = 0;
+ prismStatus = READREG(PRISM_STATUS);
+ prismResp0 = READREG(PRISM_RESP0);
+ prismResp1 = READREG(PRISM_RESP1);
+ prismResp2 = READREG(PRISM_RESP2);
+ WRITEREG(PRISM_EVACK, 0x0010);
+ result = PRISM_STATUS_RESULT_GET(prismStatus);
+ }
+ else
+ {
+ //printk("timeout:reg[%x]\n", reg);
+ result = prism_cmd_diagnose();
+ //printk("result [%x]\n", result);
+ }
+ }
+
+ return result;
+}
+
+/* send a command to device and no wait for completion */
+int prism_docmd_nowait(UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2)
+{
+ volatile UINT16 reg;
+ volatile UINT16 result;
+ volatile UINT16 counter, i;
+
+ volatile UINT16 prismStatus;
+ volatile UINT16 prismResp0;
+ volatile UINT16 prismResp1;
+ volatile UINT16 prismResp2;
+
+ i = CMD_BUSY_TIMEOUT;
+ /* wait for the busy bit to clear */
+ reg = READREG(PRISM_CMD);
+ while (PRISM_CMD_ISBUSY(reg) && i) {
+ i--;
+ udelay(5);
+ reg = READREG(PRISM_CMD);
+ }
+
+ if (!PRISM_CMD_ISBUSY(reg))
+ {
+ /* busy bit clear, write command */
+ WRITEREG(PRISM_PARAM0, parm0);
+ WRITEREG(PRISM_PARAM1, parm1);
+ WRITEREG(PRISM_PARAM2, parm2);
+ WRITEREG(PRISM_CMD, cmd);
+
+ /* Now wait for completion */
+ counter = 0;
+ reg = READREG(PRISM_EVSTAT);
+ /* if is TX cmd, timout/30 */
+ if((cmd&0x1f) == PRISM_CMDCODE_TX)
+ i = CMD_COMPL_TIMEOUT/30;
+ else
+ i = CMD_COMPL_TIMEOUT;
+ while (!PRISM_EVSTAT_ISCMD(reg) && i)
+ {
+ i--;
+ udelay(10);
+ reg = READREG(PRISM_EVSTAT);
+ }
+
+ result = 0;
+ prismStatus = READREG(PRISM_STATUS);
+ prismResp0 = READREG(PRISM_RESP0);
+ prismResp1 = READREG(PRISM_RESP1);
+ prismResp2 = READREG(PRISM_RESP2);
+ WRITEREG(PRISM_EVACK, 0x0010);
+ result = PRISM_STATUS_RESULT_GET(prismStatus);
+ }
+
+ return result;
+}
+
+
+/* prism command allocate mem */
+int prism_cmd_allocate(UINT16 len, unsigned short *txfid)
+{
+ int result = 0;
+ UINT16 cmd;
+ UINT16 reg;
+ UINT32 i;
+
+ if (len % 2)
+ result = -1;
+ else
+ {
+ cmd = PRISM_CMD_CMDCODE_SET(PRISM_CMDCODE_ALLOC);
+ result = prism_docmd_wait(cmd, len, 0, 0);
+ }
+
+ reg = READREG(PRISM_EVSTAT);
+ i = ALLOC_COMPL_TIMEOUT;
+ while (!PRISM_EVSTAT_ISALLOC(reg) && i)
+ {
+ i--;
+ udelay(10);
+ reg = READREG(PRISM_EVSTAT);
+ }
+
+ if(!PRISM_EVSTAT_ISALLOC(reg)) {
+ printk("Alloc event timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ *txfid = READREG(PRISM_ALLOCFID);
+ WRITEREG(PRISM_EVACK, PRISM_EVACK_ALLOC_SET(1));
+ return result;
+}
+
+/* prism command definition, for device initialization */
+int prism_cmd_initialize()
+{
+ int result = 0;
+
+ result = prism_docmd_wait(PRISM_CMDCODE_INIT,0,0,0);
+ return result;
+}
+
+/* this function wish the wireless device has been in slot , :P*/
+/* otherwize it will fail :(, map device register to memory, and */
+/* access memory to setup our device */
+int prism_initmac(struct net_device *dev)
+{
+ prism_cnfDesireSSID_t ssid;
+ unsigned short reg = 0;
+ volatile int i;
+ int result = 0;
+ struct w740prism_priv *priv = (struct w740prism_priv *)dev->priv;
+
+ /*---------------------------------------------------------------------------*/
+ /* should init for w90740 extern I/0 2 as programm interrupt, for tx, rx. */
+ /* But our system has inited it :) */
+ //*((volatile unsigned int *) 0xFFF83000) = 0x00054554; // config GPIO
+ //*((volatile unsigned int *) 0xFFF83000) = 0x00054554; // config GPIO
+// i = *((volatile unsigned int *) 0xFFF83000);
+// *((volatile unsigned int *) 0xFFF83000) = i & 0xffffcfff; // config GPIO
+ printk("GPIO: %x\n", *((volatile unsigned int *) 0xFFF83000));
+
+// *((volatile unsigned int *) 0xFFF83004) = 0x00100000; // GPIO20 -> output
+// *((volatile unsigned int *) 0xFFF83008) = 0x00000000; // GPIO20 -> 0
+ *((volatile unsigned int *) 0xFFF83004) = 0x00000003; // GPIO0 and GPIO1 -> output
+ *((volatile unsigned int *) 0xFFF83008) = 0x00000002; // GPIO1 -> 1
+
+ /* System memory map. map external I/O bank 2 to start address:0x80000000 */
+ /* length: 32M :P, is right no collusion */
+ *((volatile unsigned int *) EXT2CON_REG) = 0x8007bffe; //ROM2 for Mem access
+
+ // Set external click 0x00003ff8
+ *((volatile unsigned int *) 0xFFF0000c) = 0x00003fe8; // PLL OFF, 15MHz
+
+ /*--------------------------------------------------------------------------------*/
+#if 1
+ *((volatile unsigned int *) 0xFFF83008) = 0x00000000; // GPIO1 -> 0
+
+ *((volatile unsigned short *) 0xC00003e0) = 0x80; // set Configuration Option Register
+ for(i = 0; i < 500000; i++);
+ if ((reg = *((volatile unsigned short *) 0xC00003e0)) != 0x80) {
+ printk("wireless driver reset failed, %x\n", reg);
+ result= -1;
+ goto out;
+ }
+ else
+ {
+ printk("wireless memory reset to system map adress: %x, length: %dM\n" , 0xc0000000, 32);
+ }
+
+ /*be related with little endian,so value 0x4100 ??? */
+ *((volatile unsigned short *) 0xC00003e0) = 0x41; //set Configuration Option Register
+ for(i = 0; i < 30000; i++);
+ if ((reg = *((volatile unsigned short *) 0xC00003e0)) != 0x41) {
+ printk("wireless driver map to system map failed, %x\n", reg);
+ result= -1;
+ goto out;
+ }
+ else
+ {
+ printk("wireless memory map to system map adress: %x, length: %dM\n" , 0xc0000000, 32);
+ }
+ *((volatile unsigned int *) 0xfff82010) = 0x01;
+
+#if 0
+ WRITEREG(PRISM_SWSUPPORT0, HERMES_MAGIC);
+ printk("magic value: %x\n", READREG(PRISM_SWSUPPORT0));
+ printk("magic value: %x\n", READREG(PRISM_SWSUPPORT0));
+ printk("magic value: %x\n", READREG(PRISM_SWSUPPORT0));
+#endif
+ result = prism_cmd_initialize();
+ if (result != 0) {
+ printk("Initialize command failed\r\n");
+ result = -1;
+ goto out;
+ }
+ else
+ ;//printk("Initialize command sucess\r\n");
+
+ /* make sure interrupts are disabled and any layabout events cleared */
+ WRITEREG(PRISM_INTEN, PRISM_INTEN_DISABLE);
+ WRITEREG(PRISM_EVACK, PRISM_EVENT_MASK);
+
+ /* init fid queue */
+ Init_Queue();
+ Queue_dump();
+
+ /* sets 0xFC84 TxRates */
+ priv->bitratemode = DEFAULT_TXRATE_MODE;
+ prism_hw_setiwrate(priv);
+
+ /* sets Rxsthreshold */
+ priv->rts_thresh = DEFAULT_RXSTHRESHOLD;
+ prism_hw_setrts(priv);
+
+ /* set ap density */
+ priv->ap_density = DEFAULT_SENSE;
+ prism_hw_setapdensity(priv);
+
+ /* set up power */
+ priv->pm_on = DEFAULT_POWMANAGE;
+ priv->pm_mcast = DEFAULT_MULITRECEIVE;
+ priv->pm_period = DEFAULT_MAXSLEEP;
+ priv->pm_timeout = DEFAULT_PMHOLDDURATION;
+ prism_hw_setpower(priv);
+ /* sets 0xFC2A auth type */
+ reg = PRISM_Authentication;
+ Write_RID_Config(PRISM_RID_CNFAUTHENTICATION, ®, PRISM_RID_CNFAUTHENTICATION_LEN);
+
+ /* sets link type */
+ priv->iw_mode = IW_MODE_INFRA;
+ reg = priv->port_type = PRISM_MacPortType;
+ Write_RID_Config(PRISM_RID_CNFPORTTYPE, ®, PRISM_RID_CNFPORTTYPE_LEN);
+
+ /* set 0xFC02 desired SSID */
+#if 1
+ ssid.ssidLen = PRISM_SSIDLEN_DEFAULT;
+ memcpy(ssid.ssidName, PRISM_DesireSSID_DEFAULT, ssid.ssidLen);
+ Write_RID_Config(PRISM_RID_CNFOWNSSID, (UINT8 *)&ssid, PRISM_RID_CNFOWNSSID_LEN);
+ Write_RID_Config(PRISM_RID_CNFDESIREDSSID, (UINT8 *)&ssid, PRISM_RID_CNFDESIREDSSID_LEN);
+#endif
+
+ /* Retrieve the maximum frame size */
+ reg = FRAME_DATA_MAXLEN;
+ Write_RID_Config(PRISM_RID_CNFMAXDATALEN, ®, PRISM_RID_CNFMAXDATALEN_LEN);
+
+ WRITEREG(PRISM_EVSTAT, PRISM_EVENT_MASK);
+ WRITEREG(PRISM_INTEN, PRISM_INTEN_ENABLEBITS);
+
+ /* enable MAC port 0 */
+ prism_cmd_enable(0);
+ //printk("Enable the Mac port 0,?\n");
+
+
+#endif
+ result = Read_RID_Config(PRISM_RID_CNFOWNMACADDR, priv->mac_address);
+ for(i = 0; i < 6; i++)
+ printk("%x ", priv->mac_address[i]);
+ printk("\n");
+ result = Read_RID_Config(PRISM_RID_CNFDESIREDSSID, &ssid);
+
+ //printk("*************************************************\n");
+ // printk("TX Size: %d\n", sizeof(struct hermes_tx_descriptor));
+ memcpy(priv->desired_essid, ssid.ssidName, ssid.ssidLen);
+ priv->desired_essid[ssid.ssidLen] = '\0';
+
+ printk("essid: %s, addr: %x\n", priv->desired_essid, priv->desired_essid);
+ //printk("\n");
+out:
+ *((volatile unsigned int *) 0xFFF0000c) = 0x00003ff8; // 80MHz
+ return result;
+}
+
+/* real device reset, called by prism_reset() */
+int prism_reset_device(struct net_device *dev)
+{
+ prism_cnfDesireSSID_t ssid;
+ struct w740prism_priv * priv = dev->priv;
+ u16 reg;
+ volatile int i;
+ int k = CMD_BUSY_TIMEOUT;
+ int ret = 0;
+
+ priv = dev->priv;
+ *((volatile unsigned int *) 0xFFF0000c) = 0x00003fe8; // PLL OFF, 15MHz
+#if 1
+ i = *((volatile unsigned int *) 0xFFF83008);
+ *((volatile unsigned int *) 0xFFF83008) = i | 0x00000002; /* GPIO1 -> 1 */
+ for (i=0; i<10; i++);
+ i = *((volatile unsigned int *) 0xFFF83008);
+ *((volatile unsigned int *) 0xFFF83008) = i & 0xfffffffd; /* GPIO1 -> 0 */
+ //printk("<<<reset>>>\n");
+ for(i = 0; i < 30000; i++);
+ *((volatile unsigned int *) 0xfff82124) = 0x10; // add by chp; disable interrupt
+
+ *((volatile unsigned short *) 0xC00003e0) = 0x80; // set Configuration Option Register
+
+ for(i = 0; i < 500000; i++);
+ if ((reg = *((volatile unsigned short *) 0xC00003e0)) != 0x80) {
+ printk("wireless driver reset failed, %x\n", reg);
+ ret = -1;
+ goto out;
+ }
+ else
+ {
+ printk("wireless memory reset to system map adress: %x, length: %dM\n" , 0xc0000000, 32);
+ }
+
+ /*be related with little endian,so value 0x4100 ??? */
+ *((volatile unsigned short *) 0xC00003e0) = 0x41; // set Configuration Option Register
+ for(i = 0; i < 30000; i++);
+ if ((reg = *((volatile unsigned short *) 0xC00003e0)) != 0x41) {
+ printk("wireless driver map to system map failed, %x\n", reg);
+ ret = -1;
+ goto out;
+ }
+ else
+ {
+ printk("wireless memory map to system map adress: %x, length: %dM\n" , 0xc0000000, 32);
+ }
+ *((volatile unsigned int *) 0xfff82010) = 0x01;
+#endif
+ /* make sure interrupts are disabled and any layabout events cleared */
+ WRITEREG(PRISM_INTEN, PRISM_INTEN_DISABLE);
+ WRITEREG(PRISM_EVACK, PRISM_EVENT_MASK);
+
+ /* First wait for the command register to unbusy */
+ reg = READREG(PRISM_CMD);
+ while ( (PRISM_CMD_ISBUSY(reg)) && k ) {
+ k--;
+ udelay(1);
+ reg = READREG(PRISM_CMD);
+ }
+ //printk("hermes_issue_cmd: did %d retries.\n", CMD_BUSY_TIMEOUT-k);
+
+ reg = READREG(PRISM_EVSTAT);
+ WRITEREG(PRISM_EVACK, reg);
+
+
+ ret = prism_cmd_initialize();
+ if (ret != 0) {
+ printk("Initialize command failed\r\n");
+ ret = -1;
+ goto out;
+ }
+ else
+ ;//printk("Initialize command sucess\r\n");
+
+ Init_Queue();
+ Queue_dump();
+
+ /* sets link type */
+ reg = priv->port_type;
+ DEBUG("port type: %x\n", priv->port_type);
+ Write_RID_Config(PRISM_RID_CNFPORTTYPE, ®, PRISM_RID_CNFPORTTYPE_LEN);
+ DEBUG("allow ibss %x\n", priv->allow_ibss);
+#if 0
+ reg = PRISM_TxRate;
+ Write_RID_Config(PRISM_RID_TXRATECNTL, ®, PRISM_RID_TXRATECNTL_LEN);
+#else
+ prism_hw_setiwrate(priv);
+#endif
+
+ /* set RxSthread */
+ prism_hw_setrts(priv);
+
+
+ /* set ap density */
+ prism_hw_setapdensity(priv);
+
+ /* set power */
+ prism_hw_setpower(priv);
+
+ /* set 0xFC02 desired SSID */
+ ssid.ssidLen = strlen(priv->desired_essid);
+ memcpy(ssid.ssidName, priv->desired_essid, ssid.ssidLen);
+ printk("essid: %s; addr: %x\n", priv->desired_essid, priv->desired_essid);
+ Write_RID_Config(PRISM_RID_CNFOWNSSID, (UINT8 *)&ssid, PRISM_RID_CNFOWNSSID_LEN);
+ Write_RID_Config(PRISM_RID_CNFDESIREDSSID, (UINT8 *)&ssid, PRISM_RID_CNFDESIREDSSID_LEN);
+
+ /* Retrieve the maximum frame size */
+ reg = FRAME_DATA_MAXLEN;
+ Write_RID_Config(PRISM_RID_CNFMAXDATALEN, ®, PRISM_RID_CNFMAXDATALEN_LEN);
+
+ /* set the channel */
+ reg = priv->channel;
+ Write_RID_Config(PRISM_RID_CNFOWNCHANNEL, ®, PRISM_RID_CNFOWNCHANNEL_LEN);
+
+ /* Set up encryption */
+#if 1
+ ret = prism_hw_setup_wep(priv);
+ if (ret) {
+ printk(KERN_ERR "%s: Error %d activating WEP.\n",
+ dev->name, ret);
+ goto out;
+ }
+#endif
+ WRITEREG(PRISM_EVSTAT, PRISM_EVENT_MASK);
+ WRITEREG(PRISM_INTEN, PRISM_INTEN_ENABLEBITS);
+
+ /* enable MAC port 0 */
+ prism_cmd_enable(0);
+ //printk("Enable the Mac port 0,?\n");
+
+ *((volatile unsigned int *) 0xfff82120) = 0x10; // add by chp; enable interrupt
+
+out:
+ *((volatile unsigned int *) 0xFFF0000c) = 0x00003ff8; //80MHz
+ return ret;
+}
+
+/*----------------------------------------------------------------
+* prism_txexc
+*
+* Handles the TxExc event. A Transmit Exception event indicates
+* that the MAC's TX process was unsuccessful - so the packet did
+* not get transmitted.
+*
+* Arguments:
+*
+* Returns:
+* nothing
+*
+* Side effects:
+*
+* Call context:
+* interrupt
+----------------------------------------------------------------*/
+void prism_txexc()
+{
+ UINT16 status;
+ UINT16 fid;
+ int result = 0;
+
+ /* Collect the status and display */
+ fid = READREG(PRISM_TXCOMPLFID);
+ result = prism_copy_from_bap(IRQ_BAP, fid, 0, &status, sizeof(status));
+
+ //printk(" %x: [%x]\n", fid, status);
+
+ if (result)
+ printk("prism_txexc:copy_from_bap failed\r\n");
+}
+
+/* copy data from buffer access path */
+/* Note: only accept the buf which address is align 2 */
+int prism_copy_from_bap(UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT32 len)
+{
+ int result = 0;
+ UINT8 *d = (UINT8*)buf;
+ UINT16 *dw = buf;
+ UINT32 selectreg;
+ UINT32 offsetreg;
+ UINT32 datareg;
+ UINT32 i;
+ volatile UINT16 reg = 0;
+ int k = 0;
+
+
+
+ selectreg = bap ? PRISM_SELECT1 : PRISM_SELECT0;
+ offsetreg = bap ? PRISM_OFFSET1 : PRISM_OFFSET0;
+ datareg = bap ? PRISM_DATA1 : PRISM_DATA0;
+
+ k = BAP_BUSY_TIMEOUT;
+ /* Write id to select reg */
+ reg = READREG(offsetreg);
+ while (PRISM_OFFSET_ISBUSY(reg) && k) {
+ k--;
+ udelay(5);
+ reg = READREG(offsetreg);
+ }
+ if(!k) {
+ result = -1;
+ LOGPRINT;
+ goto failed;
+ }
+ WRITEREG(selectreg, id);
+
+ k = BAP_BUSY_TIMEOUT;
+ /* Write offset to offset reg */
+ reg = READREG(offsetreg);
+ while (PRISM_OFFSET_ISBUSY(reg) && k)
+ {
+ k--;
+ udelay(5);
+ reg = READREG(offsetreg);
+ }
+ if(!k) {
+ result = -1;
+ LOGPRINT;
+ goto failed;
+ }
+ WRITEREG(offsetreg, offset);
+
+ k = BAP_BUSY_TIMEOUT;
+ /* Wait for offset[busy] to clear */
+ reg=READREG(offsetreg);
+ while (PRISM_OFFSET_ISBUSY(reg) &&k )
+ {
+ k--;
+ udelay(5);
+ reg=READREG(offsetreg);
+ }
+ if (PRISM_OFFSET_ISERR(reg)) { //??
+ //result = reg;
+ LOGPRINT;
+ result = -1;
+ return result;
+ }
+ /* Read even(len) buf contents from data reg */
+ for ( i = 0; i < (len>>1); i++ ) {
+ *dw++ = READREG(datareg);
+ }
+ /* If len odd, handle last byte */
+ if ( len % 2 )
+ {
+ reg = READREG(datareg);
+ d[len-1] = ((UINT8*)(®))[0];
+ }
+
+ if (result) {
+ LOGPRINT;
+ printk("copy_from_bap failed\r\n");
+ }
+failed:
+ return result;
+
+}
+
+
+static int prism_hw_get_essid(struct w740prism_priv *priv, int *active,
+ char buf[IW_ESSID_MAX_SIZE+1])
+{
+#if 0
+ hermes_t *hw = &priv->hw;
+ int err = 0;
+ struct hermes_idstring essidbuf;
+ char *p = (char *)(&essidbuf.val);
+ int len;
+
+
+ orinoco_lock(priv);
+
+ if (strlen(priv->desired_essid) > 0) {
+ /* We read the desired SSID from the hardware rather
+ than from priv->desired_essid, just in case the
+ firmware is allowed to change it on us. I'm not
+ sure about this */
+ /* My guess is that the OWNSSID should always be whatever
+ * we set to the card, whereas CURRENT_SSID is the one that
+ * may change... - Jean II */
+ u16 rid;
+
+ *active = 1;
+
+ rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
+ HERMES_RID_CNFDESIREDSSID;
+
+ err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+ NULL, &essidbuf);
+ if (err)
+ goto fail_unlock;
+ } else {
+ *active = 0;
+
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
+ sizeof(essidbuf), NULL, &essidbuf);
+ if (err)
+ goto fail_unlock;
+ }
+
+ len = le16_to_cpu(essidbuf.len);
+
+ memset(buf, 0, IW_ESSID_MAX_SIZE+1);
+ memcpy(buf, p, len);
+ buf[len] = '\0';
+
+ fail_unlock:
+ orinoco_unlock(priv);
+
+ return err;
+#endif
+ return 0;
+}
+
+/* Get current connected AP's essid */
+int prism_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+{
+ struct w740prism_priv *priv = dev->priv;
+ char essidbuf[IW_ESSID_MAX_SIZE+1];
+ prism_cnfDesireSSID_t our_ssid;
+ int err = 0;
+
+ err = Read_RID_Config(PRISM_RID_CNFDESIREDSSID, &our_ssid);
+ DEBUG("essid len: %d\n", our_ssid.ssidLen);
+ if(our_ssid.ssidLen <= 0) {
+ erq->flags = 0;
+ return 0;
+ }
+
+ erq->flags = 1;
+ erq->length = our_ssid.ssidLen;
+ memcpy(essidbuf, our_ssid.ssidName, our_ssid.ssidLen);
+ if (erq->pointer)
+ if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
+ return -EFAULT;
+ return 0;
+}
+
+/* it should get net working freq or channel, we only get channel */
+/* if AD-Hoc mode, return OWNCHANNEL register's value */
+/* else if infrastructure mode, return CURRENT regiester's value */
+long prism_hw_get_freq(struct w740prism_priv *priv)
+{
+ int err = 0;
+ u16 channel;
+ long freq = 0;
+ prism_lock(priv);
+ DEBUG("Current Mode: %d\n", priv->iw_mode);
+ if(priv->iw_mode == IW_MODE_INFRA) {
+ err = Read_RID_Config(PRISM_RID_CURRENTCHANNEL, &channel);
+ }
+ else if(priv->iw_mode == IW_MODE_ADHOC) {
+ err = Read_RID_Config(PRISM_RID_CNFOWNCHANNEL, &channel);
+ }
+ else
+ err = -1;
+ if(err < 0)
+ {
+ printk("%s: read channel erro\n");
+ err = -EBUSY;
+ goto out;
+ }
+
+ if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
+ struct net_device *dev = priv->ndev;
+
+ printk("%s: Channel out of range (%d)!\n", dev->name, channel);
+ err = -EBUSY;
+ goto out;
+
+ }
+ freq = channel;
+ //printk("channel: %d, %d\n", channel, freq);
+ err = 0;
+out:
+ prism_unlock(priv);
+ return err ? err : freq;
+}
+
+/* Set essid */
+int prism_ioctl_setessid(struct net_device *dev, struct iw_point *essid)
+{
+ int err = 0;
+ prism_lock(dev->priv);
+ memcpy(((struct w740prism_priv *)(dev->priv))->desired_essid, (unsigned char *)essid->pointer, essid->length);
+ DEBUG("essid: %s, len: %d\n", ((struct w740prism_priv *)dev->priv)->desired_essid, essid->length);
+ prism_unlock(dev->priv);
+
+ return err;
+}
+
+/* set freq(it refers to channel here) */
+int prism_ioctl_setfreq(struct net_device *dev, struct iw_freq *freq)
+{
+ int err = 0;
+ struct w740prism_priv *priv = dev->priv;
+ u16 reg;
+
+ //printk("value: %x\n", freq->m);
+ if( (freq->m < 1) || (freq->m > NUM_CHANNELS)) {
+ printk("%s: Channel out of range (%d)!\n", dev->name, freq->m);
+ err = -EFAULT;
+ goto out;
+ }
+ priv->channel = freq->m;
+out:
+ return err;
+}
+
+/* get Wep key */
+int prism_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+{
+ struct w740prism_priv *priv = dev->priv;
+ int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+ u16 xlen = 0;
+ char keybuf[PRISM_MAX_KEY_SIZE];
+ int i, j;
+ u16 defaultkeyid, wepflags, authentication;
+
+ prism_lock(priv);
+ if ((index < 0) || (index >= PRISM_MAX_KEYS))
+ index = priv->tx_key;
+
+ erq->flags = 0;
+ if (! priv->wep_on)
+ erq->flags |= IW_ENCODE_DISABLED;
+ erq->flags |= index + 1;
+
+ xlen = le16_to_cpu(priv->keys[index].len);
+ erq->length = xlen;
+
+ if (erq->pointer) {
+ memcpy(keybuf, priv->keys[index].data, PRISM_MAX_KEY_SIZE);
+ }
+
+ prism_unlock(priv);
+
+ if (erq->pointer) {
+ if (copy_to_user(erq->pointer, keybuf, xlen))
+ return -EFAULT;
+ }
+// for(i = 0; i < xlen; i++) {
+// printk("%x", keybuf[i]);
+// }
+// printk("\n");
+ for(j = 0; j < 4; j++) {
+ Read_RID_Config(PRISM_RID_CNFDEFAULTKEY0+j, keybuf);
+// for(i = 0; i < xlen; i++) {
+// printk("%x", keybuf[i]);
+// }
+// printk("\n");
+ }
+ Read_RID_Config(PRISM_RID_CNFWEPDEFAULTKEYID, &defaultkeyid);
+ Read_RID_Config(PRISM_RID_CNFWEPFLAGS, &wepflags);
+ Read_RID_Config(PRISM_RID_CNFAUTHENTICATION, &authentication);
+// printk("defaultkeyid: %x, wepflags: %x, authentication: %x\n", defaultkeyid, wepflags, authentication);
+ return 0;
+}
+
+/* set Wep key */
+int prism_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+{
+ int i;
+ struct w740prism_priv *priv = dev->priv;
+ char buf[IW_ENCODING_TOKEN_MAX+1];
+ int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+ int setindex = priv->tx_key;
+ int enable = priv->wep_on;
+ int restricted = priv->wep_restrict;
+ int xlen = 0;
+ int err = 0;
+//printk("index: %d, len: %d, nowlen: %d\n", index, erq->length, priv->keys[index].len);
+ if (erq->length > IW_ENCODING_TOKEN_MAX)
+ {
+ printk("Too long key\n");
+ return -EFAULT;
+ }
+
+ if (erq->pointer) {
+ if(copy_from_user(buf, erq->pointer, erq->length))
+ return -EFAULT;
+ }
+ prism_lock(priv);
+ if (erq->pointer) {
+ if (erq->length > PRISM_MAX_KEY_SIZE) {
+ printk("Too long key string\n");
+ err = -E2BIG;
+ goto out;
+ }
+
+// if ( (erq->length > LARGE_KEY_SIZE)
+// || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) {
+// err = -EINVAL;
+// goto out;
+// }
+
+ if ((index < 0) || (index >= PRISM_MAX_KEYS))
+ index = priv->tx_key;
+
+ if (erq->length > SMALL_KEY_SIZE) {
+ LOGPRINT;
+ xlen = LARGE_KEY_SIZE;
+ } else if (erq->length > 0) {
+ LOGPRINT;
+ xlen = SMALL_KEY_SIZE;
+ } else
+ xlen = 0;
+
+ /* Switch on WEP if off */
+ if ((!enable) && (xlen > 0)) {
+ setindex = index;
+ enable = 1;
+ }
+ } else {
+ /* Important note : if the user do "iwconfig eth0 enc off",
+ * we will arrive there with an index of -1. This is valid
+ * but need to be taken care off... Jean II */
+ if ((index < 0) || (index >= PRISM_MAX_KEYS)) {
+ if((index != -1) || (erq->flags == 0)) {
+ err = -EINVAL;
+ goto out;
+ }
+ } else {
+ /* Set the index : Check that the key is valid */
+ if(priv->keys[index].len == 0) {
+ err = -EINVAL;
+ goto out;
+ }
+ setindex = index;
+ }
+ }
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ enable = 0;
+ /* Only for Prism2 & Symbol cards (so far) - Jean II */
+ if (erq->flags & IW_ENCODE_OPEN)
+ restricted = 0;
+ if (erq->flags & IW_ENCODE_RESTRICTED)
+ restricted = 1;
+
+ if (erq->pointer) {
+ priv->keys[index].len = cpu_to_le16(xlen);
+ memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data));
+ memcpy(priv->keys[index].data, buf, erq->length);
+ }
+ priv->tx_key = setindex;
+ priv->wep_on = enable;
+ priv->wep_restrict = restricted;
+
+ out:
+ buf[erq->length] = '\0';
+// for(i = 0; i < erq->length; i++)
+// printk("%x", buf[i]);
+// printk("\n");
+// printk("tx_key: %d, wep_on: %d, wep_restrict: %d\n", priv->tx_key, priv->wep_on, priv->wep_restrict);
+// printk("tx_key's length: %d\n", priv->keys[priv->tx_key].len);
+ prism_unlock(priv);
+ return err;
+}
+
+/* real setup the Wep key to hardware */
+int prism_hw_setup_wep(struct w740prism_priv *priv)
+{
+ int err = 0;
+ int keylen;
+ int i, j;
+ int auth_flag;
+ int master_wep_flag = 0; //is off
+
+// printk("prism_hw_setup_wep\n");
+ if (priv->wep_on) {
+ /* Write all 4 keys */
+ keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
+ for(i = 0; i < PRISM_MAX_KEYS; i++) {
+// printk("keylen: %d, reallen: %d\n", keylen, priv->keys[i].len);
+ if (keylen > LARGE_KEY_SIZE) {
+ printk("%s: Key %d has oversize length %d.\n",
+ priv->ndev->name, i, keylen);
+ return -E2BIG;
+ }
+// printk("%dkey's len: %d\n", i, keylen);
+// for( j = 0; j < keylen; j++)
+// printk("%x", priv->keys[i].data[j]);
+// printk("\n");
+ err = Write_RID_Config(PRISM_RID_CNFDEFAULTKEY0 + i, priv->keys[i].data, keylen);
+ if (err)
+ return err;
+ }
+
+ err = Write_RID_Config(PRISM_RID_CNFWEPDEFAULTKEYID, &priv->tx_key, PRISM_RID_CNFWEPDEFAULTKEYID_LEN);
+ if (err)
+ return err;
+
+ if (priv->wep_restrict) {
+ auth_flag = 2;
+ master_wep_flag = 3;
+ } else {
+ auth_flag = 1;
+ master_wep_flag = 1; /* Intersil */
+ }
+
+ err = Write_RID_Config(PRISM_RID_CNFAUTHENTICATION, &auth_flag, PRISM_RID_CNFAUTHENTICATION_LEN);
+ if (err)
+ return err;
+ }
+ Read_RID_Config(PRISM_RID_CNFAUTHENTICATION, &auth_flag);
+// printk("Auth_flag: %x\n", auth_flag);
+ /* Master WEP setting : on/off */
+ err = Write_RID_Config(PRISM_RID_CNFWEPFLAGS, &master_wep_flag, PRISM_RID_CNFWEPFLAGS_LEN);
+ if (err)
+ return err;
+ return 0;
+}
+
+int prism_ioctl_setscan(struct net_device *dev, struct iw_point *erq)
+{
+ int err = 0;
+ unsigned short len;
+ unsigned int i, j, cnt;
+ struct w740prism_priv *priv = dev->priv;
+// printk("erq->length: %d\n", erq->length);
+ prism_lock(priv);
+#if 1
+ prism_cmd_inquiry(PRISM_INQ_SCAN);
+ if(down_interruptible(&priv->sema))
+ err = -1;
+
+
+ DEBUG("erq addr: %x\n", erq);
+ prism_ioctl_getaplist(dev, erq);
+#endif
+ prism_unlock(priv);
+ return err;
+}
+
+int prism_hw_get_bssid(struct net_device *dev, char buf[ETH_ALEN])
+{
+ struct w740prism_priv *priv = dev->priv;
+ int err = 0;
+ int i = 0;
+
+ err = Read_RID_Config(PRISM_RID_CURRENTBSSID, buf);
+
+// for(i = 0; i < 6; i++)
+// printk("%x.", buf[i]);
+// printk("\n");
+ return err;
+}
+
+int prism_ioctl_getstat(struct net_device *dev, struct iw_point *erq)
+{
+ int err = 0;
+ int status = 0;
+// printk("%s: %d\n", __FILE__,__LINE__);
+ prism_cmd_inquiry(PRISM_INQ_ASSOCIATIONSTATUS);
+// printk("%s: %d\n", __FILE__,__LINE__);
+ return err;
+}
+
+
+int prism_ioctl_getlinkstat(struct net_device *dev, struct iw_point *erq)
+{
+ int err = 0;
+ int status = 0;
+ struct w740prism_priv *priv = (struct w740prism_priv *)dev->priv;
+// printk("%s: %d\n", __FILE__,__LINE__);
+ prism_lock(priv);
+ if (erq->pointer) {
+ if (copy_to_user(erq->pointer, &(priv->status), erq->length))
+ return -EFAULT;
+ }
+ prism_unlock(priv);
+ //prism_cmd_inquiry(PRISM_INQ_LINKSTATUS);
+// printk("%s: %d\n", __FILE__,__LINE__);
+ return err;
+}
+
+int prism_ioctl_getiwrate(struct net_device *dev, struct iw_param *iwp)
+{
+ int err = 0;
+ int rate = 0;
+ int i;
+ err = Read_RID_Config(PRISM_RID_CURRENTTXRATE, &rate);
+
+ for(i = 0; i < BITRATE_TABLE_SIZE; i++)
+ {
+ if (bitrate_table[i].prism_txratectrl == rate) {
+ break;
+ }
+ }
+ if(i >= BITRATE_TABLE_SIZE)
+ {
+ printk("Can't get correct rate\n");
+ i = 0;
+ }
+
+ iwp->value = bitrate_table[i].bitrate * 100000;
+// printk("Current rate: %d\n", iwp->value);
+ iwp->disabled = 0;
+ return err;
+}
+
+int prism_ioctl_setiwrate(struct net_device *dev, struct iw_param *iwp)
+{
+ struct w740prism_priv *priv = dev->priv;
+ int err = 0;
+ int ratemode = -1;
+ int bitrate; /* 100s of kilobits */
+ int i;
+//printk("rate: %d\n", iwp->value);
+ if (iwp->value == -1)
+ bitrate = 110;
+ else {
+ if (iwp->value % 100000)
+ return -EINVAL;
+ bitrate = iwp->value / 100000;
+ }
+
+ if ( (bitrate != 10) && (bitrate != 20) &&
+ (bitrate != 55) && (bitrate != 110) )
+ return -EINVAL;
+
+ for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+ if ( (bitrate_table[i].bitrate == bitrate)) {
+ ratemode = i;
+ break;
+ }
+
+ if (ratemode == -1)
+ return -EINVAL;
+
+ prism_lock(priv);
+ priv->bitratemode = ratemode;
+ prism_unlock(priv);
+
+ return err;
+}
+
+int prism_hw_setiwrate(struct w740prism_priv *priv)
+{
+ int err = 0;
+// printk("ratemode: %x\n", priv->bitratemode);
+//
+ if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
+ printk("%s: Invalid bitrate mode %d\n",
+ "wlan", priv->bitratemode);
+ return -EINVAL;
+ }
+ err = Write_RID_Config(PRISM_RID_TXRATECNTL, &bitrate_table[priv->bitratemode].prism_txratectrl, PRISM_RID_TXRATECNTL_LEN);
+ return err;
+}
+
+int prism_ioctl_setrts(struct net_device *dev, struct iw_param *iwp)
+{
+ int err = 0;
+ struct w740prism_priv *priv = dev->priv;
+ int val = iwp->value;
+
+ if (iwp->disabled)
+ val = 2347;
+
+ if ( (val < 0) || (val > 3000) )
+ return -EINVAL;
+
+ prism_lock(priv);
+ priv->rts_thresh = val;
+ prism_unlock(priv);
+
+ return err;
+}
+
+int prism_hw_setrts(struct w740prism_priv *priv)
+{
+ int err = 0;
+
+ /* Set RTS threshold */
+ err = Write_RID_Config(PRISM_RID_RTSTHRESHOLD, &priv->rts_thresh, PRISM_RID_RTSTHRESHOLD_LEN);
+
+ return err;
+}
+
+int prism_ioctl_getsens(struct net_device *dev, struct iw_param *iwp)
+{
+ int err = 0;
+ int val = 0;
+
+ Read_RID_Config(PRISM_RID_CNFSYSTEMSCALE, &val);
+// printk("Current sense: %d\n", val);
+ iwp->value = val;
+ iwp->fixed = 0; /* auto */
+
+ return 0;
+}
+
+int prism_ioctl_setsens(struct net_device *dev, struct iw_param *iwp)
+{
+ int err = 0;
+ struct w740prism_priv *priv = dev->priv;
+ int val = iwp->value;
+
+ if ((val < 1) || (val > 3))
+ return -EINVAL;
+
+ prism_lock(priv);
+ priv->ap_density = val;
+ prism_unlock(priv);
+
+ return err;
+}
+
+int prism_hw_setapdensity(struct w740prism_priv *priv)
+{
+ int err = 0;
+ err = Write_RID_Config(PRISM_RID_CNFSYSTEMSCALE, &priv->ap_density, PRISM_RID_CNFSYSTEMSCALE_LEN);
+ if (err)
+ return err;
+ return err;
+}
+
+int prism_ioctl_getpower(struct net_device *dev, struct iw_param *iwp)
+{
+ int err = 0;
+ struct w740prism_priv *priv = dev->priv;
+ u16 enable, period, timeout, mcast;
+
+ prism_lock(priv);
+
+ Read_RID_Config(PRISM_RID_CNFPMENABLED, &enable);
+ Read_RID_Config(PRISM_RID_CNFMAXSLEEPDURATION, &period);
+ Read_RID_Config(PRISM_RID_CNFPMHOLDOVERDURATION, &timeout);
+ Read_RID_Config(PRISM_RID_CNFMULTICASTRECEIVE, &mcast);
+
+ iwp->disabled = !enable;
+ /* Note : by default, display the period */
+ if ((iwp->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ iwp->flags = IW_POWER_TIMEOUT;
+ iwp->value = timeout * 1000;
+ } else {
+ iwp->flags = IW_POWER_PERIOD;
+ iwp->value = period * 1000;
+ }
+ if (mcast)
+ iwp->flags |= IW_POWER_ALL_R;
+ else
+ iwp->flags |= IW_POWER_UNICAST_R;
+
+ out:
+ prism_unlock(priv);
+ return err;
+}
+
+int prism_ioctl_setpower(struct net_device *dev, struct iw_param *iwp)
+{
+ int err = 0;
+ struct w740prism_priv *priv = dev->priv;
+
+ prism_lock(priv);
+ if (iwp->disabled) {
+ priv->pm_on = 0;
+ } else {
+ switch (iwp->flags & IW_POWER_MODE) {
+ case IW_POWER_UNICAST_R:
+ priv->pm_mcast = 0;
+ priv->pm_on = 1;
+ break;
+ case IW_POWER_ALL_R:
+ priv->pm_mcast = 1;
+ priv->pm_on = 1;
+ break;
+ case IW_POWER_ON:
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (err)
+ goto out;
+
+ if (iwp->flags & IW_POWER_TIMEOUT) {
+ priv->pm_on = 1;
+ priv->pm_timeout = iwp->value / 1000;
+ }
+ if (iwp->flags & IW_POWER_PERIOD) {
+ priv->pm_on = 1;
+ priv->pm_period = iwp->value / 1000;
+ }
+ if(!priv->pm_on) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+out:
+ prism_unlock(priv);
+ return err;
+}
+
+
+int prism_hw_setpower(struct w740prism_priv *priv)
+{
+ int err = 0;
+ err = Write_RID_Config(PRISM_RID_CNFPMENABLED, &priv->pm_on, PRISM_RID_CNFPMENABLED_LEN);
+ if (err)
+ return err;
+ err = Write_RID_Config(PRISM_RID_CNFMAXSLEEPDURATION, &priv->pm_period, PRISM_RID_CNFMAXSLEEPDURATION_LEN);
+ if (err)
+ return err;
+ err = Write_RID_Config(PRISM_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout, PRISM_RID_CNFPMHOLDOVERDURATION_LEN);
+ if (err)
+ return err;
+ err = Write_RID_Config(PRISM_RID_CNFMULTICASTRECEIVE, &priv->pm_mcast, PRISM_RID_CNFMULTICASTRECEIVE_LEN);
+ if (err)
+ return err;
+ return err;
+}
+
+int get_scan_result(UINT16 infoid, int lens, struct w740prism_priv *priv)
+{
+ int result = 0;
+ int len, j, i, cnt;
+#ifdef SCAN_ENABLE
+ struct prism_ScanResult * scan;
+ prism_lock(priv);
+
+ len = Read_CT_InfoData(infoid, &priv->scan_res, lens);
+ scan = &priv->scan_res;
+// printk("len=%d\n", len);
+ len = len/2;
+ cnt = (len - 2) / 31;
+ priv->scan_res_len = cnt;
+// printk("reason[%d], cnt: %d\n", scan->scanreason, cnt);
+ for (j=0; j<cnt; j++)
+ {
+#if 1
+ if (scan->result[j].chid > 14) {
+ LOGPRINT;
+ break;
+ }
+// printk("off: %d, j: %d\n", scan->result+j, j);
+// printk("channel[%d]\n", scan->result[j].chid);
+//
+// printk("bssid [");
+// for (i=0; i<6; i+=2)
+// printk(" %02x %02x", scan->result[j].bssid[i+1], scan->result[j].bssid[i]);
+// printk("]\n");
+// printk("ssid [");
+// len = scan->result[j].ssid.ssidLen;
+// if (len % 2)
+// {
+// for (i=0; i<len-1; i+=2)
+// printk(" %02x %02x", scan->result[j].ssid.ssidName[i+1], scan->result[j].ssid.ssidName[i]);
+// printk(" %02x", scan->result[j].ssid.ssidName[len]);
+// }
+// else
+// {
+// for (i=0; i<len; i+=2)
+// printk(" %02x %02x", scan->result[j].ssid.ssidName[i+1], scan->result[j].ssid.ssidName[i]);
+// }
+// printk("]\n");
+#endif
+ }
+ up(&priv->sema);
+ prism_unlock(priv);
+#endif
+ return result;
+}
+
+int prism_ioctl_getaplist(struct net_device *dev, struct iw_point * iwp)
+{
+ int err = 0;
+ struct w740prism_priv *priv = dev->priv;
+ int num = 0;
+ int i, len;
+#if 1
+ int j;
+#endif
+ prism_ScanResultSub_t *resultp = &(priv->scan_res.result[0]);
+DEBUG("iwp: %x, iwp->length: %d\n", iwp, iwp->length);
+ prism_lock(priv);
+
+ if(iwp->length == 0)
+ {
+ iwp->length = priv->scan_res_len;
+ DEBUG("iwp->length: %d\n", iwp->length);
+ }
+#if 1
+ else
+ {
+ len = (iwp->length > priv->scan_res_len ? priv->scan_res_len:iwp->length);
+ for(i = 0; i < len; i++)
+ {
+ if (iwp->pointer)
+ if ( copy_to_user(iwp->pointer + sizeof(prism_cnfDesireSSID_t)*i,
+ &((resultp+i)->ssid),
+ sizeof(prism_cnfDesireSSID_t) )
+ )
+ return -EFAULT;
+#if 0
+ for(j = 0; j < ((resultp+i)->ssid).ssidLen; j++)
+ {
+ printk("%c", ((resultp+i)->ssid).ssidName[j]);
+ }
+ printk("\n");
+#endif
+ }
+ }
+#endif
+ prism_unlock(priv);
+ return err;
+}
+
+void set_port_type(struct w740prism_priv *priv)
+{
+ switch (priv->iw_mode) {
+ case IW_MODE_INFRA:
+ priv->port_type = 1;
+ priv->allow_ibss = 0;
+ break;
+ case IW_MODE_ADHOC:
+ if (priv->prefer_port3) {
+ priv->port_type = 3;
+ priv->allow_ibss = 0;
+ } else {
+ priv->port_type = 0;//priv->ibss_port;
+ priv->allow_ibss = 1;
+ }
+ break;
+ default:
+ printk("%s: Invalid priv->iw_mode\n",
+ priv->ndev->name);
+ }
+}
+
+int prism_ioctl_setspy(struct net_device *dev, struct iw_point *iwp)
+{
+ int result = 0;
+ struct w740prism_priv *priv = dev->priv;
+ struct sockaddr address[IW_MAX_SPY];
+ int number = iwp->length;
+ int i;
+
+ if (number > IW_MAX_SPY)
+ return -E2BIG;
+
+ if (iwp->pointer) {
+ if (copy_from_user(address, iwp->pointer,
+ sizeof(struct sockaddr) * number))
+ return -EFAULT;
+ }
+
+ prism_lock(priv);
+ priv->spy_number = 0;
+
+ if (number > 0) {
+ for (i = 0; i < number; i++)
+ memcpy(priv->spy_address[i], address[i].sa_data,
+ ETH_ALEN);
+ memset(priv->spy_stat, 0,
+ sizeof(struct iw_quality) * IW_MAX_SPY);
+ priv->spy_number = number;
+ }
+
+ DEBUG("%s: New spy list:\n", dev->name);
+ for (i = 0; i < number; i++) {
+ DEBUG("%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, i+1,
+ priv->spy_address[i][0], priv->spy_address[i][1],
+ priv->spy_address[i][2], priv->spy_address[i][3],
+ priv->spy_address[i][4], priv->spy_address[i][5]);
+ }
+
+ prism_unlock(priv);
+ return result;
+}
+
+int prism_ioctl_getspy(struct net_device *dev, struct iw_point *iwp)
+{
+ struct w740prism_priv *priv = dev->priv;
+ struct sockaddr address[IW_MAX_SPY];
+ struct iw_quality spy_stat[IW_MAX_SPY];
+ int number;
+ int i;
+
+ prism_lock(priv);
+
+ number = priv->spy_number;
+ if ((number > 0) && (iwp->pointer)) {
+ for (i = 0; i < number; i++) {
+ memcpy(address[i].sa_data, priv->spy_address[i],
+ ETH_ALEN);
+ address[i].sa_family = AF_UNIX;
+ }
+ /* Copy stats */
+ memcpy(&spy_stat, priv->spy_stat,
+ sizeof(struct iw_quality) * IW_MAX_SPY);
+ for (i=0; i < number; i++)
+ priv->spy_stat[i].updated = 0;
+ }
+
+ prism_unlock(priv);
+
+ iwp->length = number;
+ if(copy_to_user(iwp->pointer, address,
+ sizeof(struct sockaddr) * number))
+ return -EFAULT;
+ if(copy_to_user(iwp->pointer + (sizeof(struct sockaddr)*number),
+ &spy_stat, sizeof(struct iw_quality) * number))
+ return -EFAULT;
+
+ return 0;
+}
|