diff options
Diffstat (limited to 'uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.c')
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/net/wireless/W90N745Prism.c | 998 |
1 files changed, 998 insertions, 0 deletions
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); |