/* This is part of rtl818x pci OpenSource driver - v 0.1 Copyright (C) Andrea Merello 2004-2005 Released under the terms of GPL (General Public License) Parts of this driver are based on the GPL part of the official Realtek driver. Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon. Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. Parts of BB/RF code are derived from David Young rtl8180 netbsd driver. RSSI calc function from 'The Deuce' Some ideas borrowed from the 8139too.c driver included in linux kernel. We (I?) want to thanks the Authors of those projecs and also the Ndiswrapper's project Authors. A big big thanks goes also to Realtek corp. for their help in my attempt to add RTL8185 and RTL8225 support, and to David Young also. */ #if 0 double __floatsidf (int i) { return i; } unsigned int __fixunsdfsi (double d) { return d; } double __adddf3(double a, double b) { return a+b; } double __addsf3(float a, float b) { return a+b; } double __subdf3(double a, double b) { return a-b; } double __extendsfdf2(float a) {return a;} #endif #undef DEBUG_TX_DESC2 #undef RX_DONT_PASS_UL #undef DEBUG_EPROM #undef DEBUG_RX_VERBOSE #undef DUMMY_RX #undef DEBUG_ZERO_RX #undef DEBUG_RX_SKB #undef DEBUG_TX_FRAG #undef DEBUG_RX_FRAG #undef DEBUG_TX_FILLDESC #undef DEBUG_TX #undef DEBUG_IRQ #undef DEBUG_RX #undef DEBUG_RXALLOC #undef DEBUG_REGISTERS #undef DEBUG_RING #undef DEBUG_IRQ_TASKLET #undef DEBUG_TX_ALLOC #undef DEBUG_TX_DESC //#define DEBUG_TX //#define DEBUG_TX_DESC2 //#define DEBUG_RX //#define DEBUG_RX_SKB //#define CONFIG_RTL8180_IO_MAP #include //#include //#include #include "r8180_hw.h" #include "r8180.h" #include "r8180_sa2400.h" /* PHILIPS Radio frontend */ #include "r8180_max2820.h" /* MAXIM Radio frontend */ #include "r8180_gct.h" /* GCT Radio frontend */ #include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ #include "r8180_rtl8255.h" /* RTL8255 Radio frontend */ #include "r8180_93cx6.h" /* Card EEPROM */ #include "r8180_wx.h" #include "r8180_dm.h" #ifdef CONFIG_RTL8180_PM #include "r8180_pm.h" #endif #ifdef ENABLE_DOT11D #include "dot11d.h" #endif #ifdef CONFIG_RTL8185B //#define CONFIG_RTL8180_IO_MAP #endif #ifndef PCI_VENDOR_ID_BELKIN #define PCI_VENDOR_ID_BELKIN 0x1799 #endif #ifndef PCI_VENDOR_ID_DLINK #define PCI_VENDOR_ID_DLINK 0x1186 #endif static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = { { .vendor = PCI_VENDOR_ID_REALTEK, // .device = 0x8180, .device = 0x8199, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = 0, }, #if 0 { .vendor = PCI_VENDOR_ID_BELKIN, .device = 0x6001, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = 1, }, { /* Belkin F5D6020 v3 */ .vendor = PCI_VENDOR_ID_BELKIN, .device = 0x6020, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = 2, }, { /* D-Link DWL-610 */ .vendor = PCI_VENDOR_ID_DLINK, .device = 0x3300, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = 3, }, { .vendor = PCI_VENDOR_ID_REALTEK, .device = 0x8185, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = 4, }, #endif { .vendor = 0, .device = 0, .subvendor = 0, .subdevice = 0, .driver_data = 0, } }; static char* ifname = "wlan%d"; static int hwseqnum = 0; //static char* ifname = "ath%d"; static int hwwep = 0; static int channels = 0x3fff; #define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) #define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl); MODULE_AUTHOR("Andrea Merello "); MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards"); /* MODULE_PARM(ifname, "s"); MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); MODULE_PARM(hwseqnum,"i"); MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); MODULE_PARM(hwwep,"i"); MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); MODULE_PARM(channels,"i"); MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) module_param(ifname, charp, S_IRUGO|S_IWUSR ); module_param(hwseqnum,int, S_IRUGO|S_IWUSR); module_param(hwwep,int, S_IRUGO|S_IWUSR); module_param(channels,int, S_IRUGO|S_IWUSR); #else MODULE_PARM(ifname, "s"); MODULE_PARM(hwseqnum,"i"); MODULE_PARM(hwwep,"i"); MODULE_PARM(channels,"i"); #endif MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); //MODULE_PARM_DESC(devname," Net interface name, ath%d=default"); MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void __devexit rtl8180_pci_remove(struct pci_dev *pdev); static void rtl8180_shutdown (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); dev->stop(dev); pci_disable_device(pdev); } static struct pci_driver rtl8180_pci_driver = { .name = RTL8180_MODULE_NAME, /* Driver name */ .id_table = rtl8180_pci_id_tbl, /* PCI_ID table */ .probe = rtl8180_pci_probe, /* probe fn */ .remove = __devexit_p(rtl8180_pci_remove),/* remove fn */ #ifdef CONFIG_RTL8180_PM .suspend = rtl8180_suspend, /* PM suspend fn */ .resume = rtl8180_resume, /* PM resume fn */ #else .suspend = NULL, /* PM suspend fn */ .resume = NULL, /* PM resume fn */ #endif .shutdown = rtl8180_shutdown, }; #ifdef CONFIG_RTL8180_IO_MAP u8 read_nic_byte(struct net_device *dev, int x) { return 0xff&inb(dev->base_addr +x); } u32 read_nic_dword(struct net_device *dev, int x) { return inl(dev->base_addr +x); } u16 read_nic_word(struct net_device *dev, int x) { return inw(dev->base_addr +x); } void write_nic_byte(struct net_device *dev, int x,u8 y) { outb(y&0xff,dev->base_addr +x); } void write_nic_word(struct net_device *dev, int x,u16 y) { outw(y,dev->base_addr +x); } void write_nic_dword(struct net_device *dev, int x,u32 y) { outl(y,dev->base_addr +x); } #else /* RTL_IO_MAP */ u8 read_nic_byte(struct net_device *dev, int x) { return 0xff&readb((u8*)dev->mem_start +x); } u32 read_nic_dword(struct net_device *dev, int x) { return readl((u8*)dev->mem_start +x); } u16 read_nic_word(struct net_device *dev, int x) { return readw((u8*)dev->mem_start +x); } void write_nic_byte(struct net_device *dev, int x,u8 y) { writeb(y,(u8*)dev->mem_start +x); udelay(20); } void write_nic_dword(struct net_device *dev, int x,u32 y) { writel(y,(u8*)dev->mem_start +x); udelay(20); } void write_nic_word(struct net_device *dev, int x,u16 y) { writew(y,(u8*)dev->mem_start +x); udelay(20); } #endif /* RTL_IO_MAP */ inline void force_pci_posting(struct net_device *dev) { read_nic_byte(dev,EPROM_CMD); #ifndef CONFIG_RTL8180_IO_MAP mb(); #endif } irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs); void set_nic_rxring(struct net_device *dev); void set_nic_txring(struct net_device *dev); static struct net_device_stats *rtl8180_stats(struct net_device *dev); void rtl8180_commit(struct net_device *dev); void rtl8180_start_tx_beacon(struct net_device *dev); /**************************************************************************** -----------------------------PROCFS STUFF------------------------- *****************************************************************************/ static struct proc_dir_entry *rtl8180_proc = NULL; static int proc_get_registers(char *page, char **start, off_t offset, int count, int *eof, void *data) { struct net_device *dev = data; // struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int len = 0; int i,n; int max=0xff; /* This dump the current register page */ for(n=0;n<=max;) { //printk( "\nD: %2x> ", n); len += snprintf(page + len, count - len, "\nD: %2x > ",n); for(i=0;i<16 && n<=max;i++,n++) len += snprintf(page + len, count - len, "%2x ",read_nic_byte(dev,n)); // printk("%2x ",read_nic_byte(dev,n)); } len += snprintf(page + len, count - len,"\n"); *eof = 1; return len; } int get_curr_tx_free_desc(struct net_device *dev, int priority); static int proc_get_stats_hw(char *page, char **start, off_t offset, int count, int *eof, void *data) { //struct net_device *dev = data; //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int len = 0; #ifdef CONFIG_RTL8185B #else len += snprintf(page + len, count - len, "NIC int: %lu\n" "Total int: %lu\n" "--------------------\n" "LP avail desc %d\n" "NP avail desc %d\n" "--------------------\n" "LP phys dma addr %x\n" "LP NIC ptr %x\n" "LP virt 32base %x\n" "LP virt 32tail %x\n" "--------------------\n" "NP phys dma addr %x\n" "NP NIC ptr %x\n" "NP virt 32base %x\n" "NP virt 32tail %x\n" "--------------------\n" "BP phys dma addr %x\n" "BP NIC ptr %x\n" "BP virt 32base %x\n" "BP virt 32tail %x\n", priv->stats.ints, priv->stats.shints, get_curr_tx_free_desc(dev,LOW_PRIORITY), get_curr_tx_free_desc(dev,NORM_PRIORITY), (u32)priv->txvipringdma, read_nic_dword(dev,TLPDA), (u32)priv->txvipring, (u32)priv->txvipringtail, (u32)priv->txvopringdma, read_nic_dword(dev,TNPDA), (u32)priv->txvopring, (u32)priv->txvopringtail, (u32)priv->txbeaconringdma, read_nic_dword(dev,TBDA), (u32)priv->txbeaconring, (u32)priv->txbeaconringtail); #endif *eof = 1; return len; } static int proc_get_stats_rx(char *page, char **start, off_t offset, int count, int *eof, void *data) { struct net_device *dev = data; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int len = 0; len += snprintf(page + len, count - len, /* "RX descriptor not available: %lu\n" "RX incomplete (missing last descriptor): %lu\n" "RX not data: %lu\n" //"RX descriptor pointer reset: %lu\n" "RX descriptor pointer lost: %lu\n" //"RX pointer workaround: %lu\n" "RX error int: %lu\n" "RX fifo overflow: %lu\n" "RX int: %lu\n" "RX packet: %lu\n" "RX bytes: %lu\n" "RX DMA fail: %lu\n", priv->stats.rxrdu, priv->stats.rxnolast, priv->stats.rxnodata, //priv->stats.rxreset, priv->stats.rxnopointer, //priv->stats.rxwrkaround, priv->stats.rxerr, priv->stats.rxoverflow, priv->stats.rxint, priv->ieee80211->stats.rx_packets, priv->ieee80211->stats.rx_bytes, priv->stats.rxdmafail */ "RX OK: %lu\n" "RX Retry: %lu\n" "RX CRC Error(0-500): %lu\n" "RX CRC Error(500-1000): %lu\n" "RX CRC Error(>1000): %lu\n" "RX ICV Error: %lu\n", priv->stats.rxint, priv->stats.rxerr, priv->stats.rxcrcerrmin, priv->stats.rxcrcerrmid, priv->stats.rxcrcerrmax, priv->stats.rxicverr ); *eof = 1; return len; } #if 0 static int proc_get_stats_ieee(char *page, char **start, off_t offset, int count, int *eof, void *data) { struct net_device *dev = data; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int len = 0; len += snprintf(page + len, count - len, "TXed association requests: %u\n" "TXed authentication requests: %u\n" "RXed successful association response: %u\n" "RXed failed association response: %u\n" "RXed successful authentication response: %u\n" "RXed failed authentication response: %u\n" "Association requests without response: %u\n" "Authentication requests without response: %u\n" "TX probe response: %u\n" "RX probe request: %u\n" "TX probe request: %lu\n" "RX authentication requests: %lu\n" "RX association requests: %lu\n" "Reassociations: %lu\n", priv->ieee80211->ieee_stats.tx_ass, priv->ieee80211->ieee_stats.tx_aut, priv->ieee80211->ieee_stats.rx_ass_ok, priv->ieee80211->ieee_stats.rx_ass_err, priv->ieee80211->ieee_stats.rx_aut_ok, priv->ieee80211->ieee_stats.rx_aut_err, priv->ieee80211->ieee_stats.ass_noresp, priv->ieee80211->ieee_stats.aut_noresp, priv->ieee80211->ieee_stats.tx_probe, priv->ieee80211->ieee_stats.rx_probe, priv->ieee80211->ieee_stats.tx_probe_rq, priv->ieee80211->ieee_stats.rx_auth_rq, priv->ieee80211->ieee_stats.rx_assoc_rq, priv->ieee80211->ieee_stats.reassoc); *eof = 1; return len; } #endif #if 0 static int proc_get_stats_ap(char *page, char **start, off_t offset, int count, int *eof, void *data) { struct net_device *dev = data; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct mac_htable_t *list; int i; int len = 0; if(priv->ieee80211->iw_mode != IW_MODE_MASTER){ len += snprintf(page + len, count - len, "Card is not acting as AP...\n" ); }else{ len += snprintf(page + len, count - len, "List of associated STA:\n" ); for(i=0;iieee80211->assoc_htable[i]; list!=NULL; list = list->next){ len += snprintf(page + len, count - len, MACSTR"\n",MAC2STR(list->adr)); } } *eof = 1; return len; } #endif static int proc_get_stats_tx(char *page, char **start, off_t offset, int count, int *eof, void *data) { struct net_device *dev = data; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int len = 0; unsigned long totalOK; totalOK=priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint; len += snprintf(page + len, count - len, /* "TX normal priority ok int: %lu\n" "TX normal priority error int: %lu\n" "TX high priority ok int: %lu\n" "TX high priority failed error int: %lu\n" "TX low priority ok int: %lu\n" "TX low priority failed error int: %lu\n" "TX bytes: %lu\n" "TX packets: %lu\n" "TX queue resume: %lu\n" "TX queue stopped?: %d\n" "TX fifo overflow: %lu\n" //"SW TX stop: %lu\n" //"SW TX wake: %lu\n" "TX beacon: %lu\n" "TX beacon aborted: %lu\n", priv->stats.txnpokint, priv->stats.txnperr, priv->stats.txhpokint, priv->stats.txhperr, priv->stats.txlpokint, priv->stats.txlperr, priv->ieee80211->stats.tx_bytes, priv->ieee80211->stats.tx_packets, priv->stats.txresumed, netif_queue_stopped(dev), priv->stats.txoverflow, //priv->ieee80211->ieee_stats.swtxstop, //priv->ieee80211->ieee_stats.swtxawake, priv->stats.txbeacon, priv->stats.txbeaconerr */ "TX OK: %lu\n" "TX Error: %lu\n" "TX Retry: %lu\n" "TX beacon OK: %lu\n" "TX beacon error: %lu\n", totalOK, priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr, priv->stats.txretry, priv->stats.txbeacon, priv->stats.txbeaconerr ); *eof = 1; return len; } #if WIRELESS_EXT < 17 static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); return &priv->wstats; } #endif void rtl8180_proc_module_init(void) { DMESG("Initializing proc filesystem"); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, proc_net); #else rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, init_net.proc_net); #endif } void rtl8180_proc_module_remove(void) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) remove_proc_entry(RTL8180_MODULE_NAME, proc_net); #else remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net); #endif } void rtl8180_proc_remove_one(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); if (priv->dir_dev) { remove_proc_entry("stats-hw", priv->dir_dev); remove_proc_entry("stats-tx", priv->dir_dev); remove_proc_entry("stats-rx", priv->dir_dev); // remove_proc_entry("stats-ieee", priv->dir_dev); // remove_proc_entry("stats-ap", priv->dir_dev); remove_proc_entry("registers", priv->dir_dev); remove_proc_entry(dev->name, rtl8180_proc); priv->dir_dev = NULL; } } void rtl8180_proc_init_one(struct net_device *dev) { struct proc_dir_entry *e; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO, rtl8180_proc); if (!priv->dir_dev) { DMESGE("Unable to initialize /proc/net/rtl8180/%s\n", dev->name); return; } e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO, priv->dir_dev, proc_get_stats_hw, dev); if (!e) { DMESGE("Unable to initialize " "/proc/net/rtl8180/%s/stats-hw\n", dev->name); } e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO, priv->dir_dev, proc_get_stats_rx, dev); if (!e) { DMESGE("Unable to initialize " "/proc/net/rtl8180/%s/stats-rx\n", dev->name); } e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO, priv->dir_dev, proc_get_stats_tx, dev); if (!e) { DMESGE("Unable to initialize " "/proc/net/rtl8180/%s/stats-tx\n", dev->name); } #if 0 e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO, priv->dir_dev, proc_get_stats_ieee, dev); if (!e) { DMESGE("Unable to initialize " "/proc/net/rtl8180/%s/stats-ieee\n", dev->name); } #endif #if 0 e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO, priv->dir_dev, proc_get_stats_ap, dev); if (!e) { DMESGE("Unable to initialize " "/proc/net/rtl8180/%s/stats-ap\n", dev->name); } #endif e = create_proc_read_entry("registers", S_IFREG | S_IRUGO, priv->dir_dev, proc_get_registers, dev); if (!e) { DMESGE("Unable to initialize " "/proc/net/rtl8180/%s/registers\n", dev->name); } } /**************************************************************************** -----------------------------MISC STUFF------------------------- *****************************************************************************/ /* FIXME: check if we can use some standard already-existent data type+functions in kernel */ short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma, struct buffer **bufferhead) { #ifdef DEBUG_RING DMESG("adding buffer to TX/RX struct"); #endif struct buffer *tmp; if(! *buffer){ *buffer = kmalloc(sizeof(struct buffer),GFP_KERNEL); if (*buffer == NULL) { DMESGE("Failed to kmalloc head of TX/RX struct"); return -1; } (*buffer)->next=*buffer; (*buffer)->buf=buf; (*buffer)->dma=dma; if(bufferhead !=NULL) (*bufferhead) = (*buffer); return 0; } tmp=*buffer; while(tmp->next!=(*buffer)) tmp=tmp->next; if ((tmp->next= kmalloc(sizeof(struct buffer),GFP_KERNEL)) == NULL){ DMESGE("Failed to kmalloc TX/RX struct"); return -1; } tmp->next->buf=buf; tmp->next->dma=dma; tmp->next->next=*buffer; return 0; } void buffer_free(struct net_device *dev,struct buffer **buffer,int len,short consistent) { struct buffer *tmp,*next; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct pci_dev *pdev=priv->pdev; //int i; if(! *buffer) return; /*for(tmp=*buffer; tmp->next != *buffer; tmp=tmp->next) */ tmp=*buffer; do{ next=tmp->next; if(consistent){ pci_free_consistent(pdev,len, tmp->buf,tmp->dma); }else{ pci_unmap_single(pdev, tmp->dma, len,PCI_DMA_FROMDEVICE); kfree(tmp->buf); } kfree(tmp); tmp = next; } while(next != *buffer); *buffer=NULL; } void print_buffer(u32 *buffer, int len) { int i; u8 *buf =(u8*)buffer; printk("ASCII BUFFER DUMP (len: %x):\n",len); for(i=0;itxmapringhead; tail = priv->txmapringtail; break; case BK_PRIORITY: head = priv->txbkpringhead; tail = priv->txbkpringtail; break; case BE_PRIORITY: head = priv->txbepringhead; tail = priv->txbepringtail; break; case VI_PRIORITY: head = priv->txvipringhead; tail = priv->txvipringtail; break; case VO_PRIORITY: head = priv->txvopringhead; tail = priv->txvopringtail; break; case HI_PRIORITY: head = priv->txhpringhead; tail = priv->txhpringtail; break; default: return -1; } //DMESG("%x %x", head, tail); /* FIXME FIXME FIXME FIXME */ #if 0 if( head <= tail ) return priv->txringcount-1 - (tail - head)/8; return (head - tail)/8/4; #else if( head <= tail ) ret = priv->txringcount - (tail - head)/8; else ret = (head - tail)/8; if(ret > priv->txringcount ) DMESG("BUG"); return ret; #endif } short check_nic_enought_desc(struct net_device *dev, int priority) { struct r8180_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = netdev_priv(dev); int requiredbyte, required; requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data); if(ieee->current_network.QoS_Enable) { requiredbyte += 2; }; required = requiredbyte / (priv->txbuffsize-4); if (requiredbyte % priv->txbuffsize) required++; /* for now we keep two free descriptor as a safety boundary * between the tail and the head */ return (required+2 < get_curr_tx_free_desc(dev,priority)); } /* This function is only for debuging purpose */ void check_tx_ring(struct net_device *dev, int pri) { static int maxlog =3; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u32* tmp; struct buffer *buf; int i; int nic; u32* tail; u32* head; u32* begin; u32 nicbegin; struct buffer* buffer; maxlog --; if (maxlog <0 ) return; switch(pri) { case MANAGE_PRIORITY: tail = priv->txmapringtail; begin = priv->txmapring; head = priv->txmapringhead; nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR); buffer = priv->txmapbufs; nicbegin = priv->txmapringdma; break; case BK_PRIORITY: tail = priv->txbkpringtail; begin = priv->txbkpring; head = priv->txbkpringhead; nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR); buffer = priv->txbkpbufs; nicbegin = priv->txbkpringdma; break; case BE_PRIORITY: tail = priv->txbepringtail; begin = priv->txbepring; head = priv->txbepringhead; nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR); buffer = priv->txbepbufs; nicbegin = priv->txbepringdma; break; case VI_PRIORITY: tail = priv->txvipringtail; begin = priv->txvipring; head = priv->txvipringhead; nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR); buffer = priv->txvipbufs; nicbegin = priv->txvipringdma; break; case VO_PRIORITY: tail = priv->txvopringtail; begin = priv->txvopring; head = priv->txvopringhead; nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR); buffer = priv->txvopbufs; nicbegin = priv->txvopringdma; break; case HI_PRIORITY: tail = priv->txhpringtail; begin = priv->txhpring; head = priv->txhpringhead; nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR); buffer = priv->txhpbufs; nicbegin = priv->txhpringdma; break; default: return ; break; } if(!priv->txvopbufs) DMESGE ("NIC TX ack, but TX queue corrupted!"); else{ for(i=0,buf=buffer, tmp=begin; tmptxringcount)*8; tmp+=8,buf=buf->next,i++) DMESG("BUF%d %s %x %s. Next : %x",i, *tmp & (1<<31) ? "filled" : "empty", *(buf->buf), *tmp & (1<<15)? "ok": "err", *(tmp+4)); } DMESG("nic at %d", (nic-nicbegin) / 8 /4); DMESG("tail at %d", ((int)tail - (int)begin) /8 /4); DMESG("head at %d", ((int)head - (int)begin) /8 /4); DMESG("check free desc returns %d", check_nic_enought_desc(dev,pri)); DMESG("free desc is %d\n", get_curr_tx_free_desc(dev,pri)); //rtl8180_reset(dev); return; } /* this function is only for debugging purpose */ void check_rxbuf(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u32* tmp; struct buffer *buf; u8 rx_desc_size; #ifdef CONFIG_RTL8185B rx_desc_size = 8; #else rx_desc_size = 4; #endif if(!priv->rxbuffer) DMESGE ("NIC RX ack, but RX queue corrupted!"); else{ for(buf=priv->rxbuffer, tmp=priv->rxring; tmp < priv->rxring+(priv->rxringcount)*rx_desc_size; tmp+=rx_desc_size, buf=buf->next) DMESG("BUF %s %x", *tmp & (1<<31) ? "empty" : "filled", *(buf->buf)); } return; } void dump_eprom(struct net_device *dev) { int i; for(i=0; i<63; i++) DMESG("EEPROM addr %x : %x", i, eprom_read(dev,i)); } void rtl8180_dump_reg(struct net_device *dev) { int i; int n; int max=0xff; DMESG("Dumping NIC register map"); for(n=0;n<=max;) { printk( "\nD: %2x> ", n); for(i=0;i<16 && n<=max;i++,n++) printk("%2x ",read_nic_byte(dev,n)); } printk("\n"); } void fix_tx_fifo(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u32 *tmp; int i; #ifdef DEBUG_TX_ALLOC DMESG("FIXING TX FIFOs"); #endif for (tmp=priv->txmapring, i=0; i < priv->txringcount; tmp+=8, i++){ *tmp = *tmp &~ (1<<31); } for (tmp=priv->txbkpring, i=0; i < priv->txringcount; tmp+=8, i++) { *tmp = *tmp &~ (1<<31); } for (tmp=priv->txbepring, i=0; i < priv->txringcount; tmp+=8, i++){ *tmp = *tmp &~ (1<<31); } for (tmp=priv->txvipring, i=0; i < priv->txringcount; tmp+=8, i++) { *tmp = *tmp &~ (1<<31); } for (tmp=priv->txvopring, i=0; i < priv->txringcount; tmp+=8, i++){ *tmp = *tmp &~ (1<<31); } for (tmp=priv->txhpring, i=0; i < priv->txringcount; tmp+=8,i++){ *tmp = *tmp &~ (1<<31); } for (tmp=priv->txbeaconring, i=0; i < priv->txbeaconcount; tmp+=8, i++){ *tmp = *tmp &~ (1<<31); } #ifdef DEBUG_TX_ALLOC DMESG("TX FIFOs FIXED"); #endif priv->txmapringtail = priv->txmapring; priv->txmapringhead = priv->txmapring; priv->txmapbufstail = priv->txmapbufs; priv->txbkpringtail = priv->txbkpring; priv->txbkpringhead = priv->txbkpring; priv->txbkpbufstail = priv->txbkpbufs; priv->txbepringtail = priv->txbepring; priv->txbepringhead = priv->txbepring; priv->txbepbufstail = priv->txbepbufs; priv->txvipringtail = priv->txvipring; priv->txvipringhead = priv->txvipring; priv->txvipbufstail = priv->txvipbufs; priv->txvopringtail = priv->txvopring; priv->txvopringhead = priv->txvopring; priv->txvopbufstail = priv->txvopbufs; priv->txhpringtail = priv->txhpring; priv->txhpringhead = priv->txhpring; priv->txhpbufstail = priv->txhpbufs; priv->txbeaconringtail = priv->txbeaconring; priv->txbeaconbufstail = priv->txbeaconbufs; set_nic_txring(dev); ieee80211_reset_queue(priv->ieee80211); priv->ack_tx_to_ieee = 0; } void fix_rx_fifo(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u32 *tmp; struct buffer *rxbuf; u8 rx_desc_size; #ifdef CONFIG_RTL8185B rx_desc_size = 8; // 4*8 = 32 bytes #else rx_desc_size = 4; #endif #ifdef DEBUG_RXALLOC DMESG("FIXING RX FIFO"); check_rxbuf(dev); #endif for (tmp=priv->rxring, rxbuf=priv->rxbufferhead; (tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size); tmp+=rx_desc_size,rxbuf=rxbuf->next){ *(tmp+2) = rxbuf->dma; *tmp=*tmp &~ 0xfff; *tmp=*tmp | priv->rxbuffersize; *tmp |= (1<<31); } #ifdef DEBUG_RXALLOC DMESG("RX FIFO FIXED"); check_rxbuf(dev); #endif priv->rxringtail=priv->rxring; priv->rxbuffer=priv->rxbufferhead; priv->rx_skb_complete=1; set_nic_rxring(dev); } /**************************************************************************** ------------------------------HW STUFF--------------------------- *****************************************************************************/ unsigned char QUALITY_MAP[] = { 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61, 0x61, 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x57, 0x56, 0x54, 0x52, 0x4f, 0x4c, 0x49, 0x45, 0x41, 0x3c, 0x37, 0x31, 0x29, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x01, 0x00 }; unsigned char STRENGTH_MAP[] = { 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f, 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x00 }; void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual){ //void Mlme_UpdateRssiSQ(struct net_device *dev, u8 *rssi, u8 *qual){ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u32 temp; u32 temp2; u32 temp3; u32 lsb; u32 q; u32 orig_qual; u8 _rssi; q = *qual; orig_qual = *qual; _rssi = 0; // avoid gcc complains.. if (q <= 0x4e) { temp = QUALITY_MAP[q]; } else { if( q & 0x80 ) { temp = 0x32; } else { temp = 1; } } *qual = temp; temp2 = *rssi; switch(priv->rf_chip){ case RFCHIPID_RFMD: lsb = temp2 & 1; temp2 &= 0x7e; if ( !lsb || !(temp2 <= 0x3c) ) { temp2 = 0x64; } else { temp2 = 100 * temp2 / 0x3c; } *rssi = temp2 & 0xff; _rssi = temp2 & 0xff; break; case RFCHIPID_INTERSIL: lsb = temp2; temp2 &= 0xfffffffe; temp2 *= 251; temp3 = temp2; temp2 <<= 6; temp3 += temp2; temp3 <<= 1; temp2 = 0x4950df; temp2 -= temp3; lsb &= 1; if ( temp2 <= 0x3e0000 ) { if ( temp2 < 0xffef0000 ) temp2 = 0xffef0000; } else { temp2 = 0x3e0000; } if ( !lsb ) { temp2 -= 0xf0000; } else { temp2 += 0xf0000; } temp3 = 0x4d0000; temp3 -= temp2; temp3 *= 100; temp3 = temp3 / 0x6d; temp3 >>= 0x10; _rssi = temp3 & 0xff; *rssi = temp3 & 0xff; break; case RFCHIPID_GCT: lsb = temp2 & 1; temp2 &= 0x7e; if ( ! lsb || !(temp2 <= 0x3c) ){ temp2 = 0x64; } else { temp2 = (100 * temp2) / 0x3c; } *rssi = temp2 & 0xff; _rssi = temp2 & 0xff; break; case RFCHIPID_PHILIPS: if( orig_qual <= 0x4e ){ _rssi = STRENGTH_MAP[orig_qual]; *rssi = _rssi; } else { orig_qual -= 0x80; if ( !orig_qual ){ _rssi = 1; *rssi = 1; } else { _rssi = 0x32; *rssi = 0x32; } } break; /* case 4 */ case RFCHIPID_MAXIM: lsb = temp2 & 1; temp2 &= 0x7e; temp2 >>= 1; temp2 += 0x42; if( lsb != 0 ){ temp2 += 0xa; } *rssi = temp2 & 0xff; _rssi = temp2 & 0xff; break; } if ( _rssi < 0x64 ){ if ( _rssi == 0 ) { *rssi = 1; } } else { *rssi = 0x64; } return; } void rtl8180_irq_enable(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); priv->irq_enabled = 1; /* write_nic_word(dev,INTA_MASK,INTA_RXOK | INTA_RXDESCERR | INTA_RXOVERFLOW |\ INTA_TXOVERFLOW | INTA_HIPRIORITYDESCERR | INTA_HIPRIORITYDESCOK |\ INTA_NORMPRIORITYDESCERR | INTA_NORMPRIORITYDESCOK |\ INTA_LOWPRIORITYDESCERR | INTA_LOWPRIORITYDESCOK | INTA_TIMEOUT); */ write_nic_word(dev,INTA_MASK, priv->irq_mask); } void rtl8180_irq_disable(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); #ifdef CONFIG_RTL8185B write_nic_dword(dev,IMR,0); #else write_nic_word(dev,INTA_MASK,0); #endif force_pci_posting(dev); priv->irq_enabled = 0; } void rtl8180_set_mode(struct net_device *dev,int mode) { u8 ecmd; ecmd=read_nic_byte(dev, EPROM_CMD); ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK; ecmd=ecmd | (mode<ieee80211->state == IEEE80211_LINKED) { if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) msr |= (MSR_LINK_ADHOC<ieee80211->iw_mode == IW_MODE_MASTER) msr |= (MSR_LINK_MASTER<ieee80211->iw_mode == IW_MODE_INFRA) msr |= (MSR_LINK_MANAGED< 14) || (ch < 1)) { printk("In %s: Invalid chnanel %d\n", __func__, ch); return; } priv->chan=ch; //printk("in %s:channel is %d\n",__func__,ch); priv->rf_set_chan(dev,priv->chan); } void rtl8180_rx_enable(struct net_device *dev) { u8 cmd; u32 rxconf; /* for now we accept data, management & ctl frame*/ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); rxconf=read_nic_dword(dev,RX_CONF); rxconf = rxconf &~ MAC_FILTER_MASK; rxconf = rxconf | (1<flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ dev->flags & IFF_PROMISC){ rxconf = rxconf | (1<card_8185 == 0) rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MASTER){ rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MONITOR){ rxconf = rxconf | (1<crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) rxconf = rxconf | (1<card_8185){ rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<card_8185) rxconf = rxconf | RCR_ONLYERLPKT; rxconf = rxconf &~ RCR_CS_MASK; if(!priv->card_8185) rxconf |= (priv->rcr_csense<txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma); // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma); // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma); // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma); // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma); // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma); // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma); } void rtl8180_conttx_enable(struct net_device *dev) { u32 txconf; txconf = read_nic_dword(dev,TX_CONF); txconf = txconf &~ TX_LOOPBACK_MASK; txconf = txconf | (TX_LOOPBACK_CONTINUE <card_8185){ byte = read_nic_byte(dev,CW_CONF); byte &= ~(1<card_8185){ txconf = txconf &~ (1<retry_data<retry_rts<card_8185){ if(priv->hw_plcp_len) txconf = txconf &~ TCR_PLCP_LEN; else txconf = txconf | TCR_PLCP_LEN; }else{ txconf = txconf &~ TCR_SAT; } txconf = txconf &~ TCR_MXDMA_MASK; txconf = txconf | (TCR_MXDMA_2048<ieee80211->hw_wep) // txconf=txconf &~ (1<dma_poll_mask); rtl8180_set_mode(dev,EPROM_CMD_NORMAL); */ } void rtl8180_beacon_tx_enable(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); rtl8180_set_mode(dev,EPROM_CMD_CONFIG); #ifdef CONFIG_RTL8185B priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ); write_nic_byte(dev,TPPollStop, priv->dma_poll_mask); #else priv->dma_poll_mask &=~(1<dma_poll_mask); #endif rtl8180_set_mode(dev,EPROM_CMD_NORMAL); } void rtl8180_beacon_tx_disable(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); rtl8180_set_mode(dev,EPROM_CMD_CONFIG); #ifdef CONFIG_RTL8185B priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ; write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); #else priv->dma_poll_mask |= (1<dma_poll_mask); #endif rtl8180_set_mode(dev,EPROM_CMD_NORMAL); } void rtl8180_rtx_disable(struct net_device *dev) { u8 cmd; struct r8180_priv *priv = ieee80211_priv(dev); cmd=read_nic_byte(dev,CMD); write_nic_byte(dev, CMD, cmd &~ \ ((1<rx_skb_complete) dev_kfree_skb_any(priv->rx_skb); } #if 0 int alloc_tx_beacon_desc_ring(struct net_device *dev, int count) { int i; u32 *tmp; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); priv->txbeaconring = (u32*)pci_alloc_consistent(priv->pdev, sizeof(u32)*8*count, &priv->txbeaconringdma); if (!priv->txbeaconring) return -1; for (tmp=priv->txbeaconring,i=0;itxbeaconringdma+((i+1)*8*4); else *(tmp+4) = (u32)priv->txbeaconringdma; tmp=tmp+8; } return 0; } #endif short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count, int addr) { int i; u32 *desc; u32 *tmp; dma_addr_t dma_desc, dma_tmp; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct pci_dev *pdev = priv->pdev; void *buf; if((bufsize & 0xfff) != bufsize) { DMESGE ("TX buffer allocation too large"); return 0; } desc = (u32*)pci_alloc_consistent(pdev, sizeof(u32)*8*count+256, &dma_desc); if(desc==NULL) return -1; if(dma_desc & 0xff){ /* * descriptor's buffer must be 256 byte aligned * we shouldn't be here, since we set DMA mask ! */ DMESGW("Fixing TX alignment"); desc = (u32*)((u8*)desc + 256); #if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR)) desc = (u32*)((u64)desc &~ 0xff); dma_desc = (dma_addr_t)((u8*)dma_desc + 256); dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff); #else desc = (u32*)((u32)desc &~ 0xff); dma_desc = (dma_addr_t)((u8*)dma_desc + 256); dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff); #endif } tmp=desc; for (i=0;itxnpbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; case TX_LOWPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txlpbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer LP"); return -ENOMEM; } break; case TX_HIGHPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer HP"); return -ENOMEM; } break; #else case TX_MANAGEPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txmapbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; case TX_BKPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txbkpbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer LP"); return -ENOMEM; } break; case TX_BEPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txbepbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; case TX_VIPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txvipbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer LP"); return -ENOMEM; } break; case TX_VOPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txvopbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; #endif case TX_HIGHPRIORITY_RING_ADDR: if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer HP"); return -ENOMEM; } break; case TX_BEACON_RING_ADDR: if(-1 == buffer_add(&(priv->txbeaconbufs),buf,dma_tmp,NULL)){ DMESGE("Unable to allocate mem for buffer BP"); return -ENOMEM; } break; } *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv *(tmp+2) = (u32)dma_tmp; *(tmp+3) = bufsize; if(i+1txmapringdma=dma_desc; priv->txmapring=desc; break; case TX_BKPRIORITY_RING_ADDR: priv->txbkpringdma=dma_desc; priv->txbkpring=desc; break; case TX_BEPRIORITY_RING_ADDR: priv->txbepringdma=dma_desc; priv->txbepring=desc; break; case TX_VIPRIORITY_RING_ADDR: priv->txvipringdma=dma_desc; priv->txvipring=desc; break; case TX_VOPRIORITY_RING_ADDR: priv->txvopringdma=dma_desc; priv->txvopring=desc; break; case TX_HIGHPRIORITY_RING_ADDR: priv->txhpringdma=dma_desc; priv->txhpring=desc; break; case TX_BEACON_RING_ADDR: priv->txbeaconringdma=dma_desc; priv->txbeaconring=desc; break; } #ifdef DEBUG_TX DMESG("Tx dma physical address: %x",dma_desc); #endif return 0; } void free_tx_desc_rings(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct pci_dev *pdev=priv->pdev; int count = priv->txringcount; pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txmapring, priv->txmapringdma); buffer_free(dev,&(priv->txmapbufs),priv->txbuffsize,1); pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txbkpring, priv->txbkpringdma); buffer_free(dev,&(priv->txbkpbufs),priv->txbuffsize,1); pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txbepring, priv->txbepringdma); buffer_free(dev,&(priv->txbepbufs),priv->txbuffsize,1); pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txvipring, priv->txvipringdma); buffer_free(dev,&(priv->txvipbufs),priv->txbuffsize,1); pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txvopring, priv->txvopringdma); buffer_free(dev,&(priv->txvopbufs),priv->txbuffsize,1); pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txhpring, priv->txhpringdma); buffer_free(dev,&(priv->txhpbufs),priv->txbuffsize,1); count = priv->txbeaconcount; pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txbeaconring, priv->txbeaconringdma); buffer_free(dev,&(priv->txbeaconbufs),priv->txbuffsize,1); } #if 0 void free_beacon_desc_ring(struct net_device *dev,int count) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct pci_dev *pdev=priv->pdev; pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->txbeaconring, priv->txbeaconringdma); if (priv->beacon_buf) pci_free_consistent(priv->pdev, priv->master_beaconsize,priv->beacon_buf,priv->beacondmabuf); } #endif void free_rx_desc_ring(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct pci_dev *pdev = priv->pdev; int count = priv->rxringcount; #ifdef CONFIG_RTL8185B pci_free_consistent(pdev, sizeof(u32)*8*count+256, priv->rxring, priv->rxringdma); #else pci_free_consistent(pdev, sizeof(u32)*4*count+256, priv->rxring, priv->rxringdma); #endif buffer_free(dev,&(priv->rxbuffer),priv->rxbuffersize,0); } short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) { int i; u32 *desc; u32 *tmp; dma_addr_t dma_desc,dma_tmp; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct pci_dev *pdev=priv->pdev; void *buf; u8 rx_desc_size; #ifdef CONFIG_RTL8185B rx_desc_size = 8; // 4*8 = 32 bytes #else rx_desc_size = 4; #endif if((bufsize & 0xfff) != bufsize){ DMESGE ("RX buffer allocation too large"); return -1; } desc = (u32*)pci_alloc_consistent(pdev,sizeof(u32)*rx_desc_size*count+256, &dma_desc); if(dma_desc & 0xff){ /* * descriptor's buffer must be 256 byte aligned * should never happen since we specify the DMA mask */ DMESGW("Fixing RX alignment"); desc = (u32*)((u8*)desc + 256); #if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR)) desc = (u32*)((u64)desc &~ 0xff); dma_desc = (dma_addr_t)((u8*)dma_desc + 256); dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff); #else desc = (u32*)((u32)desc &~ 0xff); dma_desc = (dma_addr_t)((u8*)dma_desc + 256); dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff); #endif } priv->rxring=desc; priv->rxringdma=dma_desc; tmp=desc; for (i=0;irxbuffer), buf,dma_tmp, &(priv->rxbufferhead))){ DMESGE("Unable to allocate mem RX buf"); return -1; } *tmp = 0; //zero pads the header of the descriptor *tmp = *tmp |( bufsize&0xfff); *(tmp+2) = (u32)dma_tmp; *tmp = *tmp |(1<<31); // descriptor void, owned by the NIC #ifdef DEBUG_RXALLOC DMESG("Alloc %x size buffer, DMA mem @ %x, virtual mem @ %x", (u32)(bufsize&0xfff), (u32)dma_tmp, (u32)buf); #endif tmp=tmp+rx_desc_size; } *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); // this is the last descriptor #ifdef DEBUG_RXALLOC DMESG("RX DMA physical address: %x",dma_desc); #endif return 0; } void set_nic_rxring(struct net_device *dev) { u8 pgreg; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); //rtl8180_set_mode(dev, EPROM_CMD_CONFIG); pgreg=read_nic_byte(dev, PGSELECT); write_nic_byte(dev, PGSELECT, pgreg &~ (1<rxringdma); } void rtl8180_reset(struct net_device *dev) { //u32 txconf = 0x80e00707; //FIXME: Make me understandable u8 cr; //write_nic_dword(dev,TX_CONF,txconf); rtl8180_irq_disable(dev); cr=read_nic_byte(dev,CMD); cr = cr & 2; cr = cr | (1<12) return 10; return rtl_rate[rate]; } inline u8 rtl8180_IsWirelessBMode(u16 rate) { if( ((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220) ) return 1; else return 0; } u16 N_DBPSOfRate(u16 DataRate); u16 ComputeTxTime( u16 FrameLength, u16 DataRate, u8 bManagementFrame, u8 bShortPreamble ) { u16 FrameTime; u16 N_DBPS; u16 Ceiling; if( rtl8180_IsWirelessBMode(DataRate) ) { if( bManagementFrame || !bShortPreamble || DataRate == 10 ) { // long preamble FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10))); } else { // Short preamble FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10))); } if( ( FrameLength*8 % (DataRate/10) ) != 0 ) //Get the Ceilling FrameTime ++; } else { //802.11g DSSS-OFDM PLCP length field calculation. N_DBPS = N_DBPSOfRate(DataRate); Ceiling = (16 + 8*FrameLength + 6) / N_DBPS + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0); FrameTime = (u16)(16 + 4 + 4*Ceiling + 6); } return FrameTime; } u16 N_DBPSOfRate(u16 DataRate) { u16 N_DBPS = 24; switch(DataRate) { case 60: N_DBPS = 24; break; case 90: N_DBPS = 36; break; case 120: N_DBPS = 48; break; case 180: N_DBPS = 72; break; case 240: N_DBPS = 96; break; case 360: N_DBPS = 144; break; case 480: N_DBPS = 192; break; case 540: N_DBPS = 216; break; default: break; } return N_DBPS; } //{by amy 080312 // // Description: // For Netgear case, they want good-looking singal strength. // 2004.12.05, by rcnjko. // long NetgearSignalStrengthTranslate( long LastSS, long CurrSS ) { long RetSS; // Step 1. Scale mapping. if(CurrSS >= 71 && CurrSS <= 100) { RetSS = 90 + ((CurrSS - 70) / 3); } else if(CurrSS >= 41 && CurrSS <= 70) { RetSS = 78 + ((CurrSS - 40) / 3); } else if(CurrSS >= 31 && CurrSS <= 40) { RetSS = 66 + (CurrSS - 30); } else if(CurrSS >= 21 && CurrSS <= 30) { RetSS = 54 + (CurrSS - 20); } else if(CurrSS >= 5 && CurrSS <= 20) { RetSS = 42 + (((CurrSS - 5) * 2) / 3); } else if(CurrSS == 4) { RetSS = 36; } else if(CurrSS == 3) { RetSS = 27; } else if(CurrSS == 2) { RetSS = 18; } else if(CurrSS == 1) { RetSS = 9; } else { RetSS = CurrSS; } //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); // Step 2. Smoothing. if(LastSS > 0) { RetSS = ((LastSS * 5) + (RetSS)+ 5) / 6; } //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); return RetSS; } // // Description: // Translate 0-100 signal strength index into dBm. // long TranslateToDbm8185( u8 SignalStrengthIndex // 0-100 index. ) { long SignalPower; // in dBm. // Translate to dBm (x=0.5y-95). SignalPower = (long)((SignalStrengthIndex + 1) >> 1); SignalPower -= 95; return SignalPower; } // // Description: // Perform signal smoothing for dynamic mechanism. // This is different with PerformSignalSmoothing8185 in smoothing fomula. // No dramatic adjustion is apply because dynamic mechanism need some degree // of correctness. Ported from 8187B. // 2007-02-26, by Bruce. // void PerformUndecoratedSignalSmoothing8185( struct r8180_priv *priv, bool bCckRate ) { // Determin the current packet is CCK rate. priv->bCurCCKPkt = bCckRate; if(priv->UndecoratedSmoothedSS >= 0) { priv->UndecoratedSmoothedSS = ( (priv->UndecoratedSmoothedSS * 5) + (priv->SignalStrength * 10) ) / 6; } else { priv->UndecoratedSmoothedSS = priv->SignalStrength * 10; } priv->UndercorateSmoothedRxPower = ( (priv->UndercorateSmoothedRxPower * 50) + (priv->RxPower* 11)) / 60; // printk("Sommthing SignalSterngth (%d) => UndecoratedSmoothedSS (%d)\n", priv->SignalStrength, priv->UndecoratedSmoothedSS); // printk("Sommthing RxPower (%d) => UndecoratedRxPower (%d)\n", priv->RxPower, priv->UndercorateSmoothedRxPower); //if(priv->CurCCKRSSI >= 0 && bCckRate) if(bCckRate) { priv->CurCCKRSSI = priv->RSSI; } else { priv->CurCCKRSSI = 0; } // Boundary checking. // TODO: The overflow condition does happen, if we want to fix, // we shall recalculate thresholds first. if(priv->UndecoratedSmoothedSS > 100) { // printk("UndecoratedSmoothedSS(%d) overflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength); } if(priv->UndecoratedSmoothedSS < 0) { // printk("UndecoratedSmoothedSS(%d) underflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength); } } //by amy 080312} /* This is rough RX isr handling routine*/ void rtl8180_rx(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct sk_buff *tmp_skb; //struct sk_buff *skb; short first,last; u32 len; int lastlen; unsigned char quality, signal; u8 rate; //u32 *prism_hdr; u32 *tmp,*tmp2; u8 rx_desc_size; u8 padding; //u32 count=0; char rxpower = 0; u32 RXAGC = 0; long RxAGC_dBm = 0; u8 LNA=0, BB=0; u8 LNA_gain[4]={02, 17, 29, 39}; u8 Antenna = 0; struct ieee80211_hdr *hdr;//by amy u16 fc,type; u8 bHwError = 0,bCRC = 0,bICV = 0; //bHwError = 0; //bCRC = 0; //bICV = 0; bool bCckRate = false; u8 RSSI = 0; long SignalStrengthIndex = 0;//+by amy 080312 // u8 SignalStrength = 0; struct ieee80211_rx_stats stats = { .signal = 0, .noise = -98, .rate = 0, // .mac_time = jiffies, .freq = IEEE80211_24GHZ_BAND, }; #ifdef CONFIG_RTL8185B stats.nic_type = NIC_8185B; rx_desc_size = 8; #else stats.nic_type = NIC_8185; rx_desc_size = 4; #endif //printk("receive frame!%d\n",count++); //if (!priv->rxbuffer) DMESG ("EE: NIC RX ack, but RX queue corrupted!"); //else { if ((*(priv->rxringtail)) & (1<<31)) { /* we have got an RX int, but the descriptor * we are pointing is empty*/ priv->stats.rxnodata++; priv->ieee80211->stats.rx_errors++; /* if (! *(priv->rxring) & (1<<31)) { priv->stats.rxreset++; priv->rxringtail=priv->rxring; priv->rxbuffer=priv->rxbufferhead; }else{*/ #if 0 /* Maybe it is possible that the NIC has skipped some descriptors or * it has reset its internal pointer to the beginning of the ring * we search for the first filled descriptor in the ring, or we break * putting again the pointer in the old location if we do not found any. * This is quite dangerous, what does happen if the nic writes * two descriptor (say A and B) when we have just checked the descriptor * A and we are going to check the descriptor B..This might happen if the * interrupt was dummy, there was not really filled descriptors and * the NIC didn't lose pointer */ //priv->stats.rxwrkaround++; tmp = priv->rxringtail; while (*(priv->rxringtail) & (1<<31)){ priv->rxringtail+=4; if(priv->rxringtail >= (priv->rxring)+(priv->rxringcount )*4) priv->rxringtail=priv->rxring; priv->rxbuffer=(priv->rxbuffer->next); if(priv->rxringtail == tmp ){ //DMESG("EE: Could not find RX pointer"); priv->stats.rxnopointer++; break; } } #else tmp2 = NULL; tmp = priv->rxringtail; do{ if(tmp == priv->rxring) //tmp = priv->rxring + (priv->rxringcount )*rx_desc_size; xiong-2006-11-15 tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size; else tmp -= rx_desc_size; if(! (*tmp & (1<<31))) tmp2 = tmp; }while(tmp != priv->rxring); if(tmp2) priv->rxringtail = tmp2; #endif //} } /* while there are filled descriptors */ while(!(*(priv->rxringtail) & (1<<31))){ if(*(priv->rxringtail) & (1<<26)) DMESGW("RX buffer overflow"); if(*(priv->rxringtail) & (1<<12)) priv->stats.rxicverr++; if(*(priv->rxringtail) & (1<<27)){ priv->stats.rxdmafail++; //DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); goto drop; } pci_dma_sync_single_for_cpu(priv->pdev, priv->rxbuffer->dma, priv->rxbuffersize * \ sizeof(u8), PCI_DMA_FROMDEVICE); first = *(priv->rxringtail) & (1<<29) ? 1:0; if(first) priv->rx_prevlen=0; last = *(priv->rxringtail) & (1<<28) ? 1:0; if(last){ lastlen=((*priv->rxringtail) &0xfff); /* if the last descriptor (that should * tell us the total packet len) tell * us something less than the descriptors * len we had until now, then there is some * problem.. * workaround to prevent kernel panic */ if(lastlen < priv->rx_prevlen) len=0; else len=lastlen-priv->rx_prevlen; if(*(priv->rxringtail) & (1<<13)) { //lastlen=((*priv->rxringtail) &0xfff); if ((*(priv->rxringtail) & 0xfff) <500) priv->stats.rxcrcerrmin++; else if ((*(priv->rxringtail) & 0x0fff) >1000) priv->stats.rxcrcerrmax++; else priv->stats.rxcrcerrmid++; } }else{ len = priv->rxbuffersize; } #ifdef CONFIG_RTL8185B if(first && last) { padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; }else if(first) { padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; if(padding) { len -= 2; } }else { padding = 0; } #ifdef CONFIG_RTL818X_S padding = 0; #endif #endif priv->rx_prevlen+=len; if(priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100){ /* HW is probably passing several buggy frames * without FD or LD flag set. * Throw this garbage away to prevent skb * memory exausting */ if(!priv->rx_skb_complete) dev_kfree_skb_any(priv->rx_skb); priv->rx_skb_complete = 1; } #ifdef DEBUG_RX_FRAG DMESG("Iteration.. len %x",len); if(first) DMESG ("First descriptor"); if(last) DMESG("Last descriptor"); #endif #ifdef DEBUG_RX_VERBOSE print_buffer( priv->rxbuffer->buf, len); #endif #ifdef CONFIG_RTL8185B signal=(unsigned char)(((*(priv->rxringtail+3))& (0x00ff0000))>>16); signal=(signal&0xfe)>>1; // Modify by hikaru 6.6 quality=(unsigned char)((*(priv->rxringtail+3)) & (0xff)); stats.mac_time[0] = *(priv->rxringtail+1); stats.mac_time[1] = *(priv->rxringtail+2); rxpower =((char)(((*(priv->rxringtail+4))& (0x00ff0000))>>16))/2 - 42; RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>> 8)) & (0x7f); #else signal=((*(priv->rxringtail+1))& (0xff0000))>>16; signal=(signal&0xfe)>>1; // Modify by hikaru 6.6 quality=((*(priv->rxringtail+1)) & (0xff)); stats.mac_time[0] = *(priv->rxringtail+2); stats.mac_time[1] = *(priv->rxringtail+3); #endif rate=((*(priv->rxringtail)) & ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20; stats.rate = rtl8180_rate2rate(rate); //DMESG("%d",rate); Antenna = (((*(priv->rxringtail +3))& (0x00008000)) == 0 )? 0:1 ; // printk("in rtl8180_rx():Antenna is %d\n",Antenna); //by amy for antenna if(!rtl8180_IsWirelessBMode(stats.rate)) { // OFDM rate. RxAGC_dBm = rxpower+1; //bias } else { // CCK rate. RxAGC_dBm = signal;//bit 0 discard LNA = (u8) (RxAGC_dBm & 0x60 ) >> 5 ; //bit 6~ bit 5 BB = (u8) (RxAGC_dBm & 0x1F); // bit 4 ~ bit 0 RxAGC_dBm = -( LNA_gain[LNA] + (BB *2) ); //Pin_11b=-(LNA_gain+BB_gain) (dBm) RxAGC_dBm +=4; //bias } if(RxAGC_dBm & 0x80) //absolute value RXAGC= ~(RxAGC_dBm)+1; bCckRate = rtl8180_IsWirelessBMode(stats.rate); // Translate RXAGC into 1-100. if(!rtl8180_IsWirelessBMode(stats.rate)) { // OFDM rate. if(RXAGC>90) RXAGC=90; else if(RXAGC<25) RXAGC=25; RXAGC=(90-RXAGC)*100/65; } else { // CCK rate. if(RXAGC>95) RXAGC=95; else if(RXAGC<30) RXAGC=30; RXAGC=(95-RXAGC)*100/65; } priv->SignalStrength = (u8)RXAGC; priv->RecvSignalPower = RxAGC_dBm ; // It can use directly by SD3 CMLin priv->RxPower = rxpower; priv->RSSI = RSSI; //{by amy 080312 // SQ translation formular is provided by SD3 DZ. 2006.06.27, by rcnjko. if(quality >= 127) quality = 1;//0; //0 will cause epc to show signal zero , walk aroud now; else if(quality < 27) quality = 100; else quality = 127 - quality; priv->SignalQuality = quality; if(!priv->card_8185) printk("check your card type\n"); stats.signal = (u8)quality;//priv->wstats.qual.level = priv->SignalStrength; stats.signalstrength = RXAGC; if(stats.signalstrength > 100) stats.signalstrength = 100; stats.signalstrength = (stats.signalstrength * 70)/100 + 30; // printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); stats.rssi = priv->wstats.qual.qual = priv->SignalQuality; stats.noise = priv->wstats.qual.noise = 100 - priv ->wstats.qual.qual; //by amy 080312} bHwError = (((*(priv->rxringtail))& (0x00000fff)) == 4080)| (((*(priv->rxringtail))& (0x04000000)) != 0 ) | (((*(priv->rxringtail))& (0x08000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x10000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x20000000)) != 0 ); bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13; bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12; hdr = (struct ieee80211_hdr *)priv->rxbuffer->buf; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); if((IEEE80211_FTYPE_CTL != type) && (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) && (!bHwError) && (!bCRC)&& (!bICV)) { //by amy 080312 // Perform signal smoothing for dynamic mechanism on demand. // This is different with PerformSignalSmoothing8185 in smoothing fomula. // No dramatic adjustion is apply because dynamic mechanism need some degree // of correctness. 2007.01.23, by shien chang. PerformUndecoratedSignalSmoothing8185(priv,bCckRate); // // For good-looking singal strength. // SignalStrengthIndex = NetgearSignalStrengthTranslate( priv->LastSignalStrengthInPercent, priv->SignalStrength); priv->LastSignalStrengthInPercent = SignalStrengthIndex; priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex); // // We need more correct power of received packets and the "SignalStrength" of RxStats is beautified, // so we record the correct power here. // priv->Stats_SignalQuality =(long) (priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6; priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower -1) / 6; // Figure out which antenna that received the lasted packet. priv->LastRxPktAntenna = Antenna ? 1 : 0; // 0: aux, 1: main. //by amy 080312 SwAntennaDiversityRxOk8185(dev, priv->SignalStrength); } //by amy for antenna #ifndef DUMMY_RX if(first){ if(!priv->rx_skb_complete){ /* seems that HW sometimes fails to reiceve and doesn't provide the last descriptor */ #ifdef DEBUG_RX_SKB DMESG("going to free incomplete skb"); #endif dev_kfree_skb_any(priv->rx_skb); priv->stats.rxnolast++; #ifdef DEBUG_RX_SKB DMESG("free incomplete skb OK"); #endif } /* support for prism header has been originally added by Christian */ if(priv->prism_hdr && priv->ieee80211->iw_mode == IW_MODE_MONITOR){ #if 0 priv->rx_skb = dev_alloc_skb(len+2+PRISM_HDR_SIZE); if(! priv->rx_skb) goto drop; prism_hdr = (u32*) skb_put(priv->rx_skb,PRISM_HDR_SIZE); prism_hdr[0]=htonl(0x80211001); //version prism_hdr[1]=htonl(0x40); //length prism_hdr[2]=htonl(stats.mac_time[1]); //mactime (HIGH) prism_hdr[3]=htonl(stats.mac_time[0]); //mactime (LOW) rdtsc(prism_hdr[5], prism_hdr[4]); //hostime (LOW+HIGH) prism_hdr[4]=htonl(prism_hdr[4]); //Byte-Order aendern prism_hdr[5]=htonl(prism_hdr[5]); //Byte-Order aendern prism_hdr[6]=0x00; //phytype prism_hdr[7]=htonl(priv->chan); //channel prism_hdr[8]=htonl(stats.rate); //datarate prism_hdr[9]=0x00; //antenna prism_hdr[10]=0x00; //priority prism_hdr[11]=0x00; //ssi_type prism_hdr[12]=htonl(stats.signal); //ssi_signal prism_hdr[13]=htonl(stats.noise); //ssi_noise prism_hdr[14]=0x00; //preamble prism_hdr[15]=0x00; //encoding #endif }else{ priv->rx_skb = dev_alloc_skb(len+2); if( !priv->rx_skb) goto drop; #ifdef DEBUG_RX_SKB DMESG("Alloc initial skb %x",len+2); #endif } priv->rx_skb_complete=0; priv->rx_skb->dev=dev; }else{ /* if we are here we should have already RXed * the first frame. * If we get here and the skb is not allocated then * we have just throw out garbage (skb not allocated) * and we are still rxing garbage.... */ if(!priv->rx_skb_complete){ tmp_skb= dev_alloc_skb(priv->rx_skb->len +len+2); if(!tmp_skb) goto drop; tmp_skb->dev=dev; #ifdef DEBUG_RX_SKB DMESG("Realloc skb %x",len+2); #endif #ifdef DEBUG_RX_SKB DMESG("going copy prev frag %x",priv->rx_skb->len); #endif memcpy(skb_put(tmp_skb,priv->rx_skb->len), priv->rx_skb->data, priv->rx_skb->len); #ifdef DEBUG_RX_SKB DMESG("skb copy prev frag complete"); #endif dev_kfree_skb_any(priv->rx_skb); #ifdef DEBUG_RX_SKB DMESG("prev skb free ok"); #endif priv->rx_skb=tmp_skb; } } #ifdef DEBUG_RX_SKB DMESG("going to copy current payload %x",len); #endif if(!priv->rx_skb_complete) { #ifdef CONFIG_RTL8185B if(padding) { memcpy(skb_put(priv->rx_skb,len), (((unsigned char *)priv->rxbuffer->buf) + 2),len); } else { #endif memcpy(skb_put(priv->rx_skb,len), priv->rxbuffer->buf,len); #ifdef CONFIG_RTL8185B } #endif } #ifdef DEBUG_RX_SKB DMESG("current fragment skb copy complete"); #endif if(last && !priv->rx_skb_complete){ #ifdef DEBUG_RX_SKB DMESG("Got last fragment"); #endif if(priv->rx_skb->len > 4) skb_trim(priv->rx_skb,priv->rx_skb->len-4); #ifdef DEBUG_RX_SKB DMESG("yanked out crc, passing to the upper layer"); #endif #ifndef RX_DONT_PASS_UL if(!ieee80211_rx(priv->ieee80211, priv->rx_skb, &stats)){ #ifdef DEBUG_RX DMESGW("Packet not consumed"); #endif #endif // RX_DONT_PASS_UL dev_kfree_skb_any(priv->rx_skb); #ifndef RX_DONT_PASS_UL } #endif #ifdef DEBUG_RX else{ DMESG("Rcv frag"); } #endif priv->rx_skb_complete=1; } #endif //DUMMY_RX pci_dma_sync_single_for_device(priv->pdev, priv->rxbuffer->dma, priv->rxbuffersize * \ sizeof(u8), PCI_DMA_FROMDEVICE); drop: // this is used when we have not enought mem /* restore the descriptor */ *(priv->rxringtail+2)=priv->rxbuffer->dma; *(priv->rxringtail)=*(priv->rxringtail) &~ 0xfff; *(priv->rxringtail)= *(priv->rxringtail) | priv->rxbuffersize; *(priv->rxringtail)= *(priv->rxringtail) | (1<<31); //^empty descriptor //wmb(); #ifdef DEBUG_RX DMESG("Current descriptor: %x",(u32)priv->rxringtail); #endif //unsigned long flags; //spin_lock_irqsave(&priv->irq_lock,flags); priv->rxringtail+=rx_desc_size; if(priv->rxringtail >= (priv->rxring)+(priv->rxringcount )*rx_desc_size) priv->rxringtail=priv->rxring; //spin_unlock_irqrestore(&priv->irq_lock,flags); priv->rxbuffer=(priv->rxbuffer->next); } // if(get_curr_tx_free_desc(dev,priority)) // ieee80211_sta_ps_sleep(priv->ieee80211, &tmp, &tmp2); } void rtl8180_dma_kick(struct net_device *dev, int priority) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); rtl8180_set_mode(dev,EPROM_CMD_CONFIG); /* switch(priority){ case LOW_PRIORITY: write_nic_byte(dev,TX_DMA_POLLING, (1<< TX_DMA_POLLING_LOWPRIORITY_SHIFT) | priv->dma_poll_mask); break; case NORM_PRIORITY: write_nic_byte(dev,TX_DMA_POLLING, (1<< TX_DMA_POLLING_NORMPRIORITY_SHIFT) | priv->dma_poll_mask); break; case HI_PRIORITY: write_nic_byte(dev,TX_DMA_POLLING, (1<< TX_DMA_POLLING_HIPRIORITY_SHIFT) | priv->dma_poll_mask); break; } */ write_nic_byte(dev, TX_DMA_POLLING, (1 << (priority + 1)) | priv->dma_poll_mask); rtl8180_set_mode(dev,EPROM_CMD_NORMAL); force_pci_posting(dev); } #if 0 void rtl8180_tx_queues_stop(struct net_device *dev) { //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u8 dma_poll_mask = (1<dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ; write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); #else priv->dma_poll_mask |= (1<dma_poll_mask); #endif rtl8180_set_mode(dev,EPROM_CMD_NORMAL); } void rtl8180_data_hard_resume(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); rtl8180_set_mode(dev,EPROM_CMD_CONFIG); #ifdef CONFIG_RTL8185B priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ); write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); #else priv->dma_poll_mask &= ~(1<dma_poll_mask); #endif rtl8180_set_mode(dev,EPROM_CMD_NORMAL); } /* this function TX data frames when the ieee80211 stack requires this. * It checks also if we need to stop the ieee tx queue, eventually do it */ void rtl8180_hard_data_xmit(struct sk_buff *skb,struct net_device *dev, int rate) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int mode; struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS; unsigned long flags; int priority; //static int count = 0; mode = priv->ieee80211->iw_mode; rate = ieeerate2rtlrate(rate); /* * This function doesn't require lock because we make * sure it's called with the tx_lock already acquired. * this come from the kernel's hard_xmit callback (trought * the ieee stack, or from the try_wake_queue (again trought * the ieee stack. */ #ifdef CONFIG_RTL8185B priority = AC2Q(skb->priority); #else priority = LOW_PRIORITY; #endif spin_lock_irqsave(&priv->tx_lock,flags); if(priv->ieee80211->bHwRadioOff) { spin_unlock_irqrestore(&priv->tx_lock,flags); return; } //printk(KERN_WARNING "priority = %d@%d\n", priority, count++); if (!check_nic_enought_desc(dev, priority)){ //DMESG("Error: no descriptor left by previous TX (avail %d) ", // get_curr_tx_free_desc(dev, priority)); DMESGW("Error: no descriptor left by previous TX (avail %d) ", get_curr_tx_free_desc(dev, priority)); //printk(KERN_WARNING "==============================================================> \n"); ieee80211_stop_queue(priv->ieee80211); } rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate); if (!check_nic_enought_desc(dev, priority)) ieee80211_stop_queue(priv->ieee80211); //dev_kfree_skb_any(skb); spin_unlock_irqrestore(&priv->tx_lock,flags); } /* This is a rough attempt to TX a frame * This is called by the ieee 80211 stack to TX management frames. * If the ring is full packet are dropped (for data frame the queue * is stopped before this can happen). For this reason it is better * if the descriptors are larger than the largest management frame * we intend to TX: i'm unsure what the HW does if it will not found * the last fragment of a frame because it has been dropped... * Since queues for Management and Data frames are different we * might use a different lock than tx_lock (for example mgmt_tx_lock) */ /* these function may loops if invoked with 0 descriptors or 0 len buffer*/ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); unsigned long flags; int priority; #ifdef CONFIG_RTL8185B priority = MANAGE_PRIORITY; #else priority = NORM_PRIORITY; #endif spin_lock_irqsave(&priv->tx_lock,flags); if(priv->ieee80211->bHwRadioOff) { spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); return 0; } rtl8180_tx(dev, skb->data, skb->len, priority, 0, 0,ieeerate2rtlrate(priv->ieee80211->basic_rate)); priv->ieee80211->stats.tx_bytes+=skb->len; priv->ieee80211->stats.tx_packets++; spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); return 0; } // longpre 144+48 shortpre 72+24 u16 rtl8180_len2duration(u32 len, short rate,short* ext) { u16 duration; u16 drift; *ext=0; switch(rate){ case 0://1mbps *ext=0; duration = ((len+4)<<4) /0x2; drift = ((len+4)<<4) % 0x2; if(drift ==0 ) break; duration++; break; case 1://2mbps *ext=0; duration = ((len+4)<<4) /0x4; drift = ((len+4)<<4) % 0x4; if(drift ==0 ) break; duration++; break; case 2: //5.5mbps *ext=0; duration = ((len+4)<<4) /0xb; drift = ((len+4)<<4) % 0xb; if(drift ==0 ) break; duration++; break; default: case 3://11mbps *ext=0; duration = ((len+4)<<4) /0x16; drift = ((len+4)<<4) % 0x16; if(drift ==0 ) break; duration++; if(drift > 6) break; *ext=1; break; } return duration; } void rtl8180_prepare_beacon(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct sk_buff *skb; u16 word = read_nic_word(dev, BcnItv); word &= ~BcnItv_BcnItv; // clear Bcn_Itv word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval);//0x64; write_nic_word(dev, BcnItv, word); skb = ieee80211_get_beacon(priv->ieee80211); if(skb){ rtl8180_tx(dev,skb->data,skb->len,BEACON_PRIORITY, 0,0,ieeerate2rtlrate(priv->ieee80211->basic_rate)); dev_kfree_skb_any(skb); } #if 0 //DMESG("size %x",len); if(*tail & (1<<31)){ //DMESG("No more beacon TX desc"); return ; } //while(! *tail & (1<<31)){ *tail= 0; // zeroes header *tail = *tail| (1<<29) ; //fist segment of the packet *tail = (*tail) | (1<<28); // last segment // *tail = *tail | (1<<18); // this is a beacon frame *(tail+3)=*(tail+3) &~ 0xfff; *(tail+3)=*(tail+3) | len; // buffer lenght *tail = *tail |len; // zeroes the second 32-bits dword of the descriptor *(tail+1)= 0; *tail = *tail | (rate << 24); duration = rtl8180_len2duration(len,rate,&ext); *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16); *tail = *tail | (1<<31); //^ descriptor ready to be txed if((tail - begin)/8 == priv->txbeaconcount-1) tail=begin; else tail=tail+8; //} #endif } /* This function do the real dirty work: it enqueues a TX command * descriptor in the ring buffer, copyes the frame in a TX buffer * and kicks the NIC to ensure it does the DMA transfer. */ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, short morefrag, short descfrag, int rate) { struct r8180_priv *priv = ieee80211_priv(dev); u32 *tail,*temp_tail; u32 *begin; u32 *buf; int i; int remain; int buflen; int count; //u16 AckCtsTime; //u16 FrameTime; u16 duration; short ext; struct buffer* buflist; //unsigned long flags; #ifdef CONFIG_RTL8185B struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf; u8 dest[ETH_ALEN]; u8 bUseShortPreamble = 0; u8 bCTSEnable = 0; u8 bRTSEnable = 0; //u16 RTSRate = 22; //u8 RetryLimit = 0; u16 Duration = 0; u16 RtsDur = 0; u16 ThisFrameTime = 0; u16 TxDescDuration = 0; u8 ownbit_flag = false; //added by david woo for sync Tx, 2007.12.14 #endif switch(priority) { case MANAGE_PRIORITY: tail=priv->txmapringtail; begin=priv->txmapring; buflist = priv->txmapbufstail; count = priv->txringcount; break; case BK_PRIORITY: tail=priv->txbkpringtail; begin=priv->txbkpring; buflist = priv->txbkpbufstail; count = priv->txringcount; break; case BE_PRIORITY: tail=priv->txbepringtail; begin=priv->txbepring; buflist = priv->txbepbufstail; count = priv->txringcount; break; case VI_PRIORITY: tail=priv->txvipringtail; begin=priv->txvipring; buflist = priv->txvipbufstail; count = priv->txringcount; break; case VO_PRIORITY: tail=priv->txvopringtail; begin=priv->txvopring; buflist = priv->txvopbufstail; count = priv->txringcount; break; case HI_PRIORITY: tail=priv->txhpringtail; begin=priv->txhpring; buflist = priv->txhpbufstail; count = priv->txringcount; break; case BEACON_PRIORITY: tail=priv->txbeaconringtail; begin=priv->txbeaconring; buflist = priv->txbeaconbufstail; count = priv->txbeaconcount; break; default: return -1; break; } //printk("in rtl8180_tx(): rate is %d\n",priv->ieee80211->rate); #if 1 memcpy(&dest, frag_hdr->addr1, ETH_ALEN); if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) { Duration = 0; RtsDur = 0; bRTSEnable = 0; bCTSEnable = 0; ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); TxDescDuration = ThisFrameTime; } else {// Unicast packet //u8 AckRate; u16 AckTime; //YJ,add,080828,for Keep alive priv->NumTxUnicast++; // Figure out ACK rate according to BSS basic rate and Tx rate, 2006.03.08 by rcnjko. //AckRate = ComputeAckRate( pMgntInfo->mBrates, (u1Byte)(pTcb->DataRate) ); // Figure out ACK time according to the AckRate and assume long preamble is used on receiver, 2006.03.08, by rcnjko. //AckTime = ComputeTxTime( sAckCtsLng/8, AckRate, FALSE, FALSE); //For simplicity, just use the 1M basic rate //AckTime = ComputeTxTime(14, 540,0, 0); // AckCTSLng = 14 use 1M bps send AckTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send //AckTime = ComputeTxTime(14, 2,false, false); // AckCTSLng = 14 use 1M bps send if ( ((len + sCrcLng) > priv->rts) && priv->rts ) { // RTS/CTS. u16 RtsTime, CtsTime; //u16 CtsRate; bRTSEnable = 1; bCTSEnable = 0; // Rate and time required for RTS. RtsTime = ComputeTxTime( sAckCtsLng/8,priv->ieee80211->basic_rate, 0, 0); // Rate and time required for CTS. CtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send // Figure out time required to transmit this frame. ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); // RTS-CTS-ThisFrame-ACK. RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime; TxDescDuration = RtsTime + RtsDur; } else {// Normal case. bCTSEnable = 0; bRTSEnable = 0; RtsDur = 0; ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); TxDescDuration = ThisFrameTime + aSifsTime + AckTime; } if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment // ThisFrame-ACK. Duration = aSifsTime + AckTime; } else { // One or more fragments remained. u16 NextFragTime; NextFragTime = ComputeTxTime( len + sCrcLng, //pretend following packet length equal current packet rtl8180_rate2rate(rate), 0, bUseShortPreamble ); //ThisFrag-ACk-NextFrag-ACK. Duration = NextFragTime + 3*aSifsTime + 2*AckTime; } } // End of Unicast packet frag_hdr->duration_id = Duration; #endif buflen=priv->txbuffsize; remain=len; temp_tail = tail; //printk("================================>buflen = %d, remain = %d!\n", buflen,remain); while(remain!=0){ #ifdef DEBUG_TX_FRAG DMESG("TX iteration"); #endif #ifdef DEBUG_TX DMESG("TX: filling descriptor %x",(u32)tail); #endif mb(); if(!buflist){ DMESGE("TX buffer error, cannot TX frames. pri %d.", priority); //spin_unlock_irqrestore(&priv->tx_lock,flags); return -1; } buf=buflist->buf; if( (*tail & (1<<31)) && (priority != BEACON_PRIORITY)){ DMESGW("No more TX desc, returning %x of %x", remain,len); priv->stats.txrdu++; #ifdef DEBUG_TX_DESC check_tx_ring(dev,priority); // netif_stop_queue(dev); // netif_carrier_off(dev); #endif // spin_unlock_irqrestore(&priv->tx_lock,flags); return remain; } *tail= 0; // zeroes header *(tail+1) = 0; *(tail+3) = 0; *(tail+5) = 0; *(tail+6) = 0; *(tail+7) = 0; if(priv->card_8185){ //FIXME: this should be triggered by HW encryption parameters. *tail |= (1<<15); //no encrypt // *tail |= (1<<30); //raise int when completed } // *tail = *tail | (1<<16); if(remain==len && !descfrag) { ownbit_flag = false; //added by david woo,2007.12.14 #ifdef DEBUG_TX_FRAG DMESG("First descriptor"); #endif *tail = *tail| (1<<29) ; //fist segment of the packet *tail = *tail |(len); } else { ownbit_flag = true; } for(i=0;i0;i++,remain--){ ((u8*)buf)[i]=txbuf[i]; //copy data into descriptor pointed DMAble buffer if(remain == 4 && i+4 >= buflen) break; /* ensure the last desc has at least 4 bytes payload */ } txbuf = txbuf + i; *(tail+3)=*(tail+3) &~ 0xfff; *(tail+3)=*(tail+3) | i; // buffer lenght // Use short preamble or not if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE) if (priv->plcp_preamble_mode==1 && rate!=0) // short mode now, not long! // *tail |= (1<<16); // enable short preamble mode. #ifdef CONFIG_RTL8185B if(bCTSEnable) { *tail |= (1<<18); } if(bRTSEnable) //rts enable { *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19);//RTS RATE *tail |= (1<<23);//rts enable *(tail+1) |=(RtsDur&0xffff);//RTS Duration } *(tail+3) |= ((TxDescDuration&0xffff)<<16); //DURATION // *(tail+3) |= (0xe6<<16); *(tail+5) |= (11<<8);//(priv->retry_data<<8); //retry lim ; #else //Use RTS or not #ifdef CONFIG_RTL8187B if ( (len>priv->rts) && priv->rts && priority!=MANAGE_PRIORITY){ #else if ( (len>priv->rts) && priv->rts && priority==LOW_PRIORITY){ #endif *tail |= (1<<23); //enalbe RTS function *tail |= (0<<19); //use 1M bps send RTS packet AckCtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send FrameTime = ComputeTxTime(len + 4, rtl8180_rate2rate(rate), 0, *tail&(1<<16)); // RTS/CTS time is calculate as follow duration = FrameTime + 3*10 + 2*AckCtsTime; //10us is the SifsTime; *(tail+1) |= duration; //Need to edit here! ----hikaru }else{ *(tail+1)= 0; // zeroes the second 32-bits dword of the descriptor } #endif *tail = *tail | ((rate&0xf) << 24); //DMESG("rate %d",rate); if(priv->card_8185){ #if 0 *(tail+5)&= ~(1<<24); /* tx ant 0 */ *(tail+5) &= ~(1<<23); /* random tx agc 23-16 */ *(tail+5) |= (1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16); *(tail+5) &= ~((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)); *(tail+5) |= (7<<8); // Max retry limit *(tail+5) &= ~((1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0)); *(tail+5) |= (8<<4); // Max contention window *(tail+6) |= 4; // Min contention window #endif // *(tail+5) = 0; } /* hw_plcp_len is not used for rtl8180 chip */ /* FIXME */ if(priv->card_8185 == 0 || !priv->hw_plcp_len){ duration = rtl8180_len2duration(len, rate,&ext); #ifdef DEBUG_TX DMESG("PLCP duration %d",duration ); //DMESG("drift %d",drift); DMESG("extension %s", (ext==1) ? "on":"off"); #endif *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16); if(ext) *(tail+1) = *(tail+1) |(1<<31); //plcp length extension } if(morefrag) *tail = (*tail) | (1<<17); // more fragment if(!remain) *tail = (*tail) | (1<<28); // last segment of frame #ifdef DEBUG_TX_FRAG if(!remain)DMESG("Last descriptor"); if(morefrag)DMESG("More frag"); #endif *(tail+5) = *(tail+5)|(2<<27); *(tail+7) = *(tail+7)|(1<<4); wmb(); if(ownbit_flag) { *tail = *tail | (1<<31); // descriptor ready to be txed } #ifdef DEBUG_TX_DESC2 printk("tx desc is:\n"); DMESG("%8x %8x %8x %8x %8x %8x %8x %8x", tail[0], tail[1], tail[2], tail[3], tail[4], tail[5], tail[6], tail[7]); #endif if((tail - begin)/8 == count-1) tail=begin; else tail=tail+8; buflist=buflist->next; mb(); switch(priority) { case MANAGE_PRIORITY: priv->txmapringtail=tail; priv->txmapbufstail=buflist; break; case BK_PRIORITY: priv->txbkpringtail=tail; priv->txbkpbufstail=buflist; break; case BE_PRIORITY: priv->txbepringtail=tail; priv->txbepbufstail=buflist; break; case VI_PRIORITY: priv->txvipringtail=tail; priv->txvipbufstail=buflist; break; case VO_PRIORITY: priv->txvopringtail=tail; priv->txvopbufstail=buflist; break; case HI_PRIORITY: priv->txhpringtail=tail; priv->txhpbufstail = buflist; break; case BEACON_PRIORITY: /* the HW seems to be happy with the 1st * descriptor filled and the 2nd empty... * So always update descriptor 1 and never * touch 2nd */ // priv->txbeaconringtail=tail; // priv->txbeaconbufstail=buflist; break; } //rtl8180_dma_kick(dev,priority); } *temp_tail = *temp_tail | (1<<31); // descriptor ready to be txed rtl8180_dma_kick(dev,priority); //spin_unlock_irqrestore(&priv->tx_lock,flags); return 0; } void rtl8180_irq_rx_tasklet(struct r8180_priv * priv); void rtl8180_link_change(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); u16 beacon_interval; struct ieee80211_network *net = &priv->ieee80211->current_network; // rtl8180_adapter_start(dev); rtl8180_update_msr(dev); rtl8180_set_mode(dev,EPROM_CMD_CONFIG); write_nic_dword(dev,BSSID,((u32*)net->bssid)[0]); write_nic_word(dev,BSSID+4,((u16*)net->bssid)[2]); beacon_interval = read_nic_dword(dev,BEACON_INTERVAL); beacon_interval &= ~ BEACON_INTERVAL_MASK; beacon_interval |= net->beacon_interval; write_nic_dword(dev, BEACON_INTERVAL, beacon_interval); rtl8180_set_mode(dev, EPROM_CMD_NORMAL); /* u16 atim = read_nic_dword(dev,ATIM); u16 = u16 &~ ATIM_MASK; u16 = u16 | beacon->atim; */ #if 0 if (net->capability & WLAN_CAPABILITY_PRIVACY) { if (priv->hw_wep) { DMESG("Enabling hardware WEP support"); rtl8180_set_hw_wep(dev); priv->ieee80211->host_encrypt=0; priv->ieee80211->host_decrypt=0; } #ifndef CONFIG_IEEE80211_NOWEP else { priv->ieee80211->host_encrypt=1; priv->ieee80211->host_decrypt=1; } #endif } #ifndef CONFIG_IEEE80211_NOWEP else{ priv->ieee80211->host_encrypt=0; priv->ieee80211->host_decrypt=0; } #endif #endif if(priv->card_8185) rtl8180_set_chan(dev, priv->chan); } void rtl8180_rq_tx_ack(struct net_device *dev){ struct r8180_priv *priv = ieee80211_priv(dev); // printk("====================>%s\n",__func__); write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)|CONFIG4_PWRMGT); priv->ack_tx_to_ieee = 1; } short rtl8180_is_tx_queue_empty(struct net_device *dev){ struct r8180_priv *priv = ieee80211_priv(dev); u32* d; for (d = priv->txmapring; d < priv->txmapring + priv->txringcount;d+=8) if(*d & (1<<31)) return 0; for (d = priv->txbkpring; d < priv->txbkpring + priv->txringcount;d+=8) if(*d & (1<<31)) return 0; for (d = priv->txbepring; d < priv->txbepring + priv->txringcount;d+=8) if(*d & (1<<31)) return 0; for (d = priv->txvipring; d < priv->txvipring + priv->txringcount;d+=8) if(*d & (1<<31)) return 0; for (d = priv->txvopring; d < priv->txvopring + priv->txringcount;d+=8) if(*d & (1<<31)) return 0; for (d = priv->txhpring; d < priv->txhpring + priv->txringcount;d+=8) if(*d & (1<<31)) return 0; return 1; } /* FIXME FIXME 5msecs is random */ #define HW_WAKE_DELAY 5 void rtl8180_hw_wakeup(struct net_device *dev) { unsigned long flags; struct r8180_priv *priv = ieee80211_priv(dev); spin_lock_irqsave(&priv->ps_lock,flags); //DMESG("Waken up!"); write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)&~CONFIG4_PWRMGT); if(priv->rf_wakeup) priv->rf_wakeup(dev); // mdelay(HW_WAKE_DELAY); spin_unlock_irqrestore(&priv->ps_lock,flags); } void rtl8180_hw_sleep_down(struct net_device *dev) { unsigned long flags; struct r8180_priv *priv = ieee80211_priv(dev); spin_lock_irqsave(&priv->ps_lock,flags); //DMESG("Sleep!"); if(priv->rf_sleep) priv->rf_sleep(dev); spin_unlock_irqrestore(&priv->ps_lock,flags); } void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) { struct r8180_priv *priv = ieee80211_priv(dev); u32 rb = jiffies; unsigned long flags; spin_lock_irqsave(&priv->ps_lock,flags); /* Writing HW register with 0 equals to disable * the timer, that is not really what we want */ tl -= MSECS(4+16+7); //if(tl == 0) tl = 1; /* FIXME HACK FIXME HACK */ // force_pci_posting(dev); //mdelay(1); // rb = read_nic_dword(dev, TSFTR); /* If the interval in witch we are requested to sleep is too * short then give up and remain awake */ if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME)) ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) { spin_unlock_irqrestore(&priv->ps_lock,flags); printk("too short to sleep\n"); return; } // write_nic_dword(dev, TimerInt, tl); // rb = read_nic_dword(dev, TSFTR); { u32 tmp = (tl>rb)?(tl-rb):(rb-tl); // if (tlDozePeriodInPast2Sec += jiffies_to_msecs(tmp); queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb } /* if we suspect the TimerInt is gone beyond tl * while setting it, then give up */ #if 1 if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))|| ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) { spin_unlock_irqrestore(&priv->ps_lock,flags); return; } #endif // if(priv->rf_sleep) // priv->rf_sleep(dev); queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq); spin_unlock_irqrestore(&priv->ps_lock,flags); } //void rtl8180_wmm_param_update(struct net_device *dev,u8 *ac_param) #if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) void rtl8180_wmm_param_update(struct work_struct * work) { struct ieee80211_device * ieee = container_of(work, struct ieee80211_device,wmm_param_update_wq); //struct r8180_priv *priv = (struct r8180_priv*)(ieee->priv); struct net_device *dev = ieee->dev; #else void rtl8180_wmm_param_update(struct ieee80211_device *ieee) { struct net_device *dev = ieee->dev; struct r8180_priv *priv = ieee80211_priv(dev); #endif u8 *ac_param = (u8 *)(ieee->current_network.wmm_param); u8 mode = ieee->current_network.mode; AC_CODING eACI; AC_PARAM AcParam; PAC_PARAM pAcParam; u8 i; #ifndef CONFIG_RTL8185B //for legacy 8185 keep the PARAM unchange. return; #else if(!ieee->current_network.QoS_Enable){ //legacy ac_xx_param update AcParam.longData = 0; AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. AcParam.f.AciAifsn.f.ACM = 0; AcParam.f.Ecw.f.ECWmin = 3; // Follow 802.11 CWmin. AcParam.f.Ecw.f.ECWmax = 7; // Follow 802.11 CWmax. AcParam.f.TXOPLimit = 0; for(eACI = 0; eACI < AC_MAX; eACI++){ AcParam.f.AciAifsn.f.ACI = (u8)eACI; { u8 u1bAIFS; u32 u4bAcParam; pAcParam = (PAC_PARAM)(&AcParam); // Retrive paramters to udpate. u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN *(((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<f.Ecw.f.ECWmax))<f.Ecw.f.ECWmin))<f.AciAifsn.f.ACI; //Mode G/A: slotTimeTimer = 9; Mode B: 20 u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); switch(eACI){ case AC1_BK: write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); break; case AC0_BE: write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); break; case AC2_VI: write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); break; case AC3_VO: write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); break; default: printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI); break; } } ac_param += (sizeof(AC_PARAM)); } #endif } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_tx_irq_wq(struct work_struct *work); #else void rtl8180_tx_irq_wq(struct net_device *dev); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_restart_wq(struct work_struct *work); //void rtl8180_rq_tx_ack(struct work_struct *work); #else void rtl8180_restart_wq(struct net_device *dev); //void rtl8180_rq_tx_ack(struct net_device *dev); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_watch_dog_wq(struct work_struct *work); #else void rtl8180_watch_dog_wq(struct net_device *dev); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_hw_wakeup_wq(struct work_struct *work); #else void rtl8180_hw_wakeup_wq(struct net_device *dev); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_hw_sleep_wq(struct work_struct *work); #else void rtl8180_hw_sleep_wq(struct net_device *dev); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_sw_antenna_wq(struct work_struct *work); #else void rtl8180_sw_antenna_wq(struct net_device *dev); #endif void rtl8180_watch_dog(struct net_device *dev); void watch_dog_adaptive(unsigned long data) { struct r8180_priv* priv = ieee80211_priv((struct net_device *)data); // DMESG("---->watch_dog_adaptive()\n"); if(!priv->up) { DMESG("<----watch_dog_adaptive():driver is not up!\n"); return; } // queue_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq); //{by amy 080312 #if 1 // Tx High Power Mechanism. #ifdef HIGH_POWER if(CheckHighPower((struct net_device *)data)) { queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq); } #endif #ifdef CONFIG_RTL818X_S // Tx Power Tracking on 87SE. #ifdef TX_TRACK //if( priv->bTxPowerTrack ) //lzm mod 080826 if( CheckTxPwrTracking((struct net_device *)data)); TxPwrTracking87SE((struct net_device *)data); #endif #endif // Perform DIG immediately. #ifdef SW_DIG if(CheckDig((struct net_device *)data) == true) { queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq); } #endif #endif //by amy 080312} rtl8180_watch_dog((struct net_device *)data); queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem); priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME); add_timer(&priv->watch_dog_timer); // DMESG("<----watch_dog_adaptive()\n"); } #ifdef ENABLE_DOT11D static CHANNEL_LIST ChannelPlan[] = { {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI. {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI. {{14,36,40,44,48,52,56,60,64},9}, //MKK {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel. {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} //world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 }; static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee) { int i; //lzm add 080826 ieee->MinPassiveChnlNum=MAX_CHANNEL_NUMBER+1; ieee->IbssStartChnl=0; switch (channel_plan) { case COUNTRY_CODE_FCC: case COUNTRY_CODE_IC: case COUNTRY_CODE_ETSI: case COUNTRY_CODE_SPAIN: case COUNTRY_CODE_FRANCE: case COUNTRY_CODE_MKK: case COUNTRY_CODE_MKK1: case COUNTRY_CODE_ISRAEL: case COUNTRY_CODE_TELEC: { Dot11d_Init(ieee); ieee->bGlobalDomain = false; if (ChannelPlan[channel_plan].Len != 0){ // Clear old channel map memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); // Set new channel map for (i=0;ichannel_map[ChannelPlan[channel_plan].Channel[i]] = 1; } } break; } case COUNTRY_CODE_GLOBAL_DOMAIN: { GET_DOT11D_INFO(ieee)->bEnabled = 0; Dot11d_Reset(ieee); ieee->bGlobalDomain = true; break; } case COUNTRY_CODE_WORLD_WIDE_13_INDEX://lzm add 080826 { ieee->MinPassiveChnlNum=12; ieee->IbssStartChnl= 10; break; } default: { Dot11d_Init(ieee); ieee->bGlobalDomain = false; memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); for (i=1;i<=14;i++) { GET_DOT11D_INFO(ieee)->channel_map[i] = 1; } break; } } } #endif //Add for RF power on power off by lizhaoming 080512 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void GPIOChangeRFWorkItemCallBack(struct work_struct *work); #else void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee); #endif //YJ,add,080828 static void rtl8180_statistics_init(struct Stats *pstats) { memset(pstats, 0, sizeof(struct Stats)); } static void rtl8180_link_detect_init(plink_detect_t plink_detect) { memset(plink_detect, 0, sizeof(link_detect_t)); plink_detect->SlotNum = DEFAULT_SLOT_NUM; } //YJ,add,080828,end short rtl8180_init(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); u16 word; u16 version; u8 hw_version; //u8 config3; u32 usValue; u16 tmpu16; int i, j; #ifdef ENABLE_DOT11D #if 0 for(i=0;i<0xFF;i++) { if(i%16 == 0) printk("\n[%x]: ", i/16); printk("\t%4.4x", eprom_read(dev,i)); } #endif priv->channel_plan = eprom_read(dev, EEPROM_COUNTRY_CODE>>1) & 0xFF; if(priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN){ printk("rtl8180_init:Error channel plan! Set to default.\n"); priv->channel_plan = 0; } //priv->channel_plan = 9; //Global Domain DMESG("Channel plan is %d\n",priv->channel_plan); rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211); #else int ch; //Set Default Channel Plan if(!channels){ DMESG("No channels, aborting"); return -1; } ch=channels; priv->channel_plan = 0;//hikaru // set channels 1..14 allowed in given locale for (i=1; i<=14; i++) { (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); ch >>= 1; } #endif //memcpy(priv->stats,0,sizeof(struct Stats)); //FIXME: these constants are placed in a bad pleace. priv->txbuffsize = 2048;//1024; priv->txringcount = 32;//32; priv->rxbuffersize = 2048;//1024; priv->rxringcount = 64;//32; priv->txbeaconcount = 2; priv->rx_skb_complete = 1; //priv->txnp_pending.ispending=0; /* ^^ the SKB does not containt a partial RXed * packet (is empty) */ #ifdef CONFIG_RTL8185B #ifdef CONFIG_RTL818X_S priv->RegThreeWireMode = HW_THREE_WIRE_SI; #else priv->RegThreeWireMode = SW_THREE_WIRE; #endif #endif //Add for RF power on power off by lizhaoming 080512 priv->RFChangeInProgress = false; priv->SetRFPowerStateInProgress = false; priv->RFProgType = 0; priv->bInHctTest = false; priv->irq_enabled=0; //YJ,modified,080828 #if 0 priv->stats.rxdmafail=0; priv->stats.txrdu=0; priv->stats.rxrdu=0; priv->stats.rxnolast=0; priv->stats.rxnodata=0; //priv->stats.rxreset=0; //priv->stats.rxwrkaround=0; priv->stats.rxnopointer=0; priv->stats.txnperr=0; priv->stats.txresumed=0; priv->stats.rxerr=0; priv->stats.rxoverflow=0; priv->stats.rxint=0; priv->stats.txnpokint=0; priv->stats.txhpokint=0; priv->stats.txhperr=0; priv->stats.ints=0; priv->stats.shints=0; priv->stats.txoverflow=0; priv->stats.txbeacon=0; priv->stats.txbeaconerr=0; priv->stats.txlperr=0; priv->stats.txlpokint=0; priv->stats.txretry=0;//tony 20060601 priv->stats.rxcrcerrmin=0; priv->stats.rxcrcerrmid=0; priv->stats.rxcrcerrmax=0; priv->stats.rxicverr=0; #else rtl8180_statistics_init(&priv->stats); rtl8180_link_detect_init(&priv->link_detect); #endif //YJ,modified,080828,end priv->ack_tx_to_ieee = 0; priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; priv->ieee80211->iw_mode = IW_MODE_INFRA; priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; priv->ieee80211->active_scan = 1; priv->ieee80211->rate = 110; //11 mbps priv->ieee80211->modulation = IEEE80211_CCK_MODULATION; priv->ieee80211->host_encrypt = 1; priv->ieee80211->host_decrypt = 1; priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup; priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack; priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep; priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty; priv->hw_wep = hwwep; priv->prism_hdr=0; priv->dev=dev; priv->retry_rts = DEFAULT_RETRY_RTS; priv->retry_data = DEFAULT_RETRY_DATA; priv->RFChangeInProgress = false; priv->SetRFPowerStateInProgress = false; priv->RFProgType = 0; priv->bInHctTest = false; priv->bInactivePs = true;//false; priv->ieee80211->bInactivePs = priv->bInactivePs; priv->bSwRfProcessing = false; priv->eRFPowerState = eRfOff; priv->RfOffReason = 0; priv->LedStrategy = SW_LED_MODE0; //priv->NumRxOkInPeriod = 0; //YJ,del,080828 //priv->NumTxOkInPeriod = 0; //YJ,del,080828 priv->TxPollingTimes = 0;//lzm add 080826 priv->bLeisurePs = true; priv->dot11PowerSaveMode = eActive; //by amy for antenna priv->AdMinCheckPeriod = 5; priv->AdMaxCheckPeriod = 10; // Lower signal strength threshold to fit the HW participation in antenna diversity. +by amy 080312 priv->AdMaxRxSsThreshold = 30;//60->30 priv->AdRxSsThreshold = 20;//50->20 priv->AdCheckPeriod = priv->AdMinCheckPeriod; priv->AdTickCount = 0; priv->AdRxSignalStrength = -1; priv->RegSwAntennaDiversityMechanism = 0; priv->RegDefaultAntenna = 0; priv->SignalStrength = 0; priv->AdRxOkCnt = 0; priv->CurrAntennaIndex = 0; priv->AdRxSsBeforeSwitched = 0; init_timer(&priv->SwAntennaDiversityTimer); priv->SwAntennaDiversityTimer.data = (unsigned long)dev; priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback; //by amy for antenna //{by amy 080312 priv->bDigMechanism = 1; priv->InitialGain = 6; priv->bXtalCalibration = false; priv->XtalCal_Xin = 0; priv->XtalCal_Xout = 0; priv->bTxPowerTrack = false; priv->ThermalMeter = 0; priv->FalseAlarmRegValue = 0; priv->RegDigOfdmFaUpTh = 0xc; // Upper threhold of OFDM false alarm, which is used in DIG. priv->DIG_NumberFallbackVote = 0; priv->DIG_NumberUpgradeVote = 0; priv->LastSignalStrengthInPercent = 0; priv->Stats_SignalStrength = 0; priv->LastRxPktAntenna = 0; priv->SignalQuality = 0; // in 0-100 index. priv->Stats_SignalQuality = 0; priv->RecvSignalPower = 0; // in dBm. priv->Stats_RecvSignalPower = 0; priv->AdMainAntennaRxOkCnt = 0; priv->AdAuxAntennaRxOkCnt = 0; priv->bHWAdSwitched = false; priv->bRegHighPowerMechanism = true; priv->RegHiPwrUpperTh = 77; priv->RegHiPwrLowerTh = 75; priv->RegRSSIHiPwrUpperTh = 70; priv->RegRSSIHiPwrLowerTh = 20; priv->bCurCCKPkt = false; priv->UndecoratedSmoothedSS = -1; priv->bToUpdateTxPwr = false; priv->CurCCKRSSI = 0; priv->RxPower = 0; priv->RSSI = 0; //YJ,add,080828 priv->NumTxOkTotal = 0; priv->NumTxUnicast = 0; priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL; priv->PowerProfile = POWER_PROFILE_AC; //YJ,add,080828,end //by amy for rate adaptive priv->CurrRetryCnt=0; priv->LastRetryCnt=0; priv->LastTxokCnt=0; priv->LastRxokCnt=0; priv->LastRetryRate=0; priv->bTryuping=0; priv->CurrTxRate=0; priv->CurrRetryRate=0; priv->TryupingCount=0; priv->TryupingCountNoData=0; priv->TryDownCountLowData=0; priv->LastTxOKBytes=0; priv->LastFailTxRate=0; priv->LastFailTxRateSS=0; priv->FailTxRateCount=0; priv->LastTxThroughput=0; priv->NumTxOkBytesTotal=0; priv->ForcedDataRate = 0; priv->RegBModeGainStage = 1; //by amy for rate adaptive //by amy 080312} priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0; spin_lock_init(&priv->irq_lock); spin_lock_init(&priv->irq_th_lock); spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->ps_lock); spin_lock_init(&priv->rf_ps_lock); sema_init(&priv->wx_sem,1); sema_init(&priv->rf_state,1); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq); INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq); INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq); INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq); //INIT_DELAYED_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq); //INIT_DELAYED_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq); INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update); INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter);//+by amy 080312 INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq);//+by amy 080312 INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq);//+by amy 080312 //add for RF power on power off by lizhaoming 080512 INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack); #else INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev); INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq,dev); //INIT_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq,dev); INIT_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq,dev); INIT_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq,dev); //INIT_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq,dev); INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update,priv->ieee80211); INIT_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter,dev);//+by amy 080312 INIT_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq,dev);//+by amy 080312 INIT_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq,dev);//+by amy 080312 //add for RF power on power off by lizhaoming 080512 INIT_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack, priv->ieee80211); #endif //INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev); tasklet_init(&priv->irq_rx_tasklet, (void(*)(unsigned long)) rtl8180_irq_rx_tasklet, (unsigned long)priv); //by amy init_timer(&priv->watch_dog_timer); priv->watch_dog_timer.data = (unsigned long)dev; priv->watch_dog_timer.function = watch_dog_adaptive; //by amy //{by amy 080312 //by amy for rate adaptive init_timer(&priv->rateadapter_timer); priv->rateadapter_timer.data = (unsigned long)dev; priv->rateadapter_timer.function = timer_rate_adaptive; priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD; priv->bEnhanceTxPwr=false; //by amy for rate adaptive //by amy 080312} //priv->ieee80211->func = // kmalloc(sizeof(struct ieee80211_helper_functions),GFP_KERNEL); //memset(priv->ieee80211->func, 0, // sizeof(struct ieee80211_helper_functions)); priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit; priv->ieee80211->set_chan = rtl8180_set_chan; priv->ieee80211->link_change = rtl8180_link_change; priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit; priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop; priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume; priv->ieee80211->init_wmmparam_flag = 0; priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon; priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable; priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; #ifdef CONFIG_RTL8185B priv->MWIEnable = 0; priv->ShortRetryLimit = 7; priv->LongRetryLimit = 7; priv->EarlyRxThreshold = 7; priv->CSMethod = (0x01 << 29); priv->TransmitConfig = 1<ShortRetryLimit<LongRetryLimit<ReceiveConfig = #ifdef CONFIG_RTL818X_S #else priv->CSMethod | #endif // RCR_ENMARP | RCR_AMF | RCR_ADF | //accept management/data RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC //RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet (7<EarlyRxThreshold<EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0); priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER | IMR_THPDER | IMR_THPDOK | IMR_TVODER | IMR_TVODOK | IMR_TVIDER | IMR_TVIDOK | IMR_TBEDER | IMR_TBEDOK | IMR_TBKDER | IMR_TBKDOK | IMR_RDU | // To handle the defragmentation not enough Rx descriptors case. Annie, 2006-03-27. IMR_RER | IMR_ROK | IMR_RQoSOK; // ROK and RQoSOK are mutually exclusive, so, we must handle RQoSOK interrupt to receive QoS frames, 2005.12.09, by rcnjko. priv->InitialGain = 6; #endif hw_version =( read_nic_dword(dev, TCR) & TCR_HWVERID_MASK)>>TCR_HWVERID_SHIFT; switch (hw_version){ #ifdef CONFIG_RTL8185B case HW_VERID_R8185B_B: #ifdef CONFIG_RTL818X_S priv->card_8185 = VERSION_8187S_C; DMESG("MAC controller is a RTL8187SE b/g"); priv->phy_ver = 2; break; #else DMESG("MAC controller is a RTL8185B b/g"); priv->card_8185 = 3; priv->phy_ver = 2; break; #endif #endif case HW_VERID_R8185_ABC: DMESG("MAC controller is a RTL8185 b/g"); priv->card_8185 = 1; /* you should not find a card with 8225 PHY ver < C*/ priv->phy_ver = 2; break; case HW_VERID_R8185_D: DMESG("MAC controller is a RTL8185 b/g (V. D)"); priv->card_8185 = 2; /* you should not find a card with 8225 PHY ver < C*/ priv->phy_ver = 2; break; case HW_VERID_R8180_ABCD: DMESG("MAC controller is a RTL8180"); priv->card_8185 = 0; break; case HW_VERID_R8180_F: DMESG("MAC controller is a RTL8180 (v. F)"); priv->card_8185 = 0; break; default: DMESGW("MAC chip not recognized: version %x. Assuming RTL8180",hw_version); priv->card_8185 = 0; break; } if(priv->card_8185){ priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION; priv->ieee80211->short_slot = 1; } /* you should not found any 8185 Ver B Card */ priv->card_8185_Bversion = 0; #ifdef CONFIG_RTL8185B #ifdef CONFIG_RTL818X_S // just for sync 85 priv->card_type = PCI; DMESG("This is a PCI NIC"); #else config3 = read_nic_byte(dev, CONFIG3); if(config3 & 0x8){ priv->card_type = CARDBUS; DMESG("This is a CARDBUS NIC"); } else if( config3 & 0x4){ priv->card_type = MINIPCI; DMESG("This is a MINI-PCI NIC"); }else{ priv->card_type = PCI; DMESG("This is a PCI NIC"); } #endif #endif priv->enable_gpio0 = 0; //by amy for antenna #ifdef CONFIG_RTL8185B usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET); DMESG("usValue is 0x%x\n",usValue); #ifdef CONFIG_RTL818X_S //3Read AntennaDiversity // SW Antenna Diversity. if( (usValue & EEPROM_SW_AD_MASK) != EEPROM_SW_AD_ENABLE ) { priv->EEPROMSwAntennaDiversity = false; //printk("EEPROM Disable SW Antenna Diversity\n"); } else { priv->EEPROMSwAntennaDiversity = true; //printk("EEPROM Enable SW Antenna Diversity\n"); } // Default Antenna to use. if( (usValue & EEPROM_DEF_ANT_MASK) != EEPROM_DEF_ANT_1 ) { priv->EEPROMDefaultAntenna1 = false; //printk("EEPROM Default Antenna 0\n"); } else { priv->EEPROMDefaultAntenna1 = true; //printk("EEPROM Default Antenna 1\n"); } // // Antenna diversity mechanism. Added by Roger, 2007.11.05. // if( priv->RegSwAntennaDiversityMechanism == 0 ) // Auto {// 0: default from EEPROM. priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity; } else {// 1:disable antenna diversity, 2: enable antenna diversity. priv->bSwAntennaDiverity = ((priv->RegSwAntennaDiversityMechanism == 1)? false : true); } //printk("bSwAntennaDiverity = %d\n", priv->bSwAntennaDiverity); // // Default antenna settings. Added by Roger, 2007.11.05. // if( priv->RegDefaultAntenna == 0) {// 0: default from EEPROM. priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1; } else {// 1: main, 2: aux. priv->bDefaultAntenna1 = ((priv->RegDefaultAntenna== 2) ? true : false); } //printk("bDefaultAntenna1 = %d\n", priv->bDefaultAntenna1); #endif #endif //by amy for antenna /* rtl8185 can calc plcp len in HW.*/ priv->hw_plcp_len = 1; priv->plcp_preamble_mode = 2; /*the eeprom type is stored in RCR register bit #6 */ if (RCR_9356SEL & read_nic_dword(dev, RCR)){ priv->epromtype=EPROM_93c56; //DMESG("Reported EEPROM chip is a 93c56 (2Kbit)"); }else{ priv->epromtype=EPROM_93c46; //DMESG("Reported EEPROM chip is a 93c46 (1Kbit)"); } dev->get_stats = rtl8180_stats; dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff; dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8; dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff; dev->dev_addr[3]=(eprom_read(dev,MAC_ADR+1) & 0xff00)>>8; dev->dev_addr[4]=eprom_read(dev,MAC_ADR+2) & 0xff; dev->dev_addr[5]=(eprom_read(dev,MAC_ADR+2) & 0xff00)>>8; //DMESG("Card MAC address is "MAC_FMT, MAC_ARG(dev->dev_addr)); for(i=1,j=0; i<14; i+=2,j++){ word = eprom_read(dev,EPROM_TXPW_CH1_2 + j); priv->chtxpwr[i]=word & 0xff; priv->chtxpwr[i+1]=(word & 0xff00)>>8; #ifdef DEBUG_EPROM DMESG("tx word %x:%x",j,word); DMESG("ch %d pwr %x",i,priv->chtxpwr[i]); DMESG("ch %d pwr %x",i+1,priv->chtxpwr[i+1]); #endif } if(priv->card_8185){ for(i=1,j=0; i<14; i+=2,j++){ word = eprom_read(dev,EPROM_TXPW_OFDM_CH1_2 + j); priv->chtxpwr_ofdm[i]=word & 0xff; priv->chtxpwr_ofdm[i+1]=(word & 0xff00)>>8; #ifdef DEBUG_EPROM DMESG("ofdm tx word %x:%x",j,word); DMESG("ofdm ch %d pwr %x",i,priv->chtxpwr_ofdm[i]); DMESG("ofdm ch %d pwr %x",i+1,priv->chtxpwr_ofdm[i+1]); #endif } } //{by amy 080312 //3Read crystal calibtration and thermal meter indication on 87SE. // By SD3 SY's request. Added by Roger, 2007.12.11. tmpu16 = eprom_read(dev, EEPROM_RSV>>1); //printk("ReadAdapterInfo8185(): EEPROM_RSV(%04x)\n", tmpu16); // Crystal calibration for Xin and Xout resp. priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK; // 0~7.5pF priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK)>>4; // 0~7.5pF if((tmpu16 & EEPROM_XTAL_CAL_ENABLE)>>12) priv->bXtalCalibration = true; // Thermal meter reference indication. priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK)>>8); if((tmpu16 & EEPROM_THERMAL_METER_ENABLE)>>13) priv->bTxPowerTrack = true; //by amy 080312} #ifdef CONFIG_RTL8185B word = eprom_read(dev,EPROM_TXPW_BASE); priv->cck_txpwr_base = word & 0xf; priv->ofdm_txpwr_base = (word>>4) & 0xf; #endif version = eprom_read(dev,EPROM_VERSION); DMESG("EEPROM version %x",version); if( (!priv->card_8185) && version < 0x0101){ DMESG ("EEPROM version too old, assuming defaults"); DMESG ("If you see this message *plase* send your \ DMESG output to andreamrl@tiscali.it THANKS"); priv->digphy=1; priv->antb=0; priv->diversity=1; priv->cs_treshold=0xc; priv->rcr_csense=1; priv->rf_chip=RFCHIPID_PHILIPS; }else{ if(!priv->card_8185){ u8 rfparam = eprom_read(dev,RF_PARAM); DMESG("RfParam: %x",rfparam); priv->digphy = rfparam & (1<antb = rfparam & (1<rcr_csense = (rfparam & RF_PARAM_CARRIERSENSE_MASK) >> RF_PARAM_CARRIERSENSE_SHIFT; priv->diversity = (read_nic_byte(dev,CONFIG2)&(1<rcr_csense = 3; } priv->cs_treshold = (eprom_read(dev,ENERGY_TRESHOLD)&0xff00) >>8; priv->rf_chip = 0xff & eprom_read(dev,RFCHIPID); } #ifdef CONFIG_RTL8185B #ifdef CONFIG_RTL818X_S priv->rf_chip = RF_ZEBRA4; priv->rf_sleep = rtl8225z4_rf_sleep; priv->rf_wakeup = rtl8225z4_rf_wakeup; #else priv->rf_chip = RF_ZEBRA2; #endif //DMESG("Card reports RF frontend Realtek 8225z2"); //DMESGW("This driver has EXPERIMENTAL support for this chipset."); //DMESGW("use it with care and at your own risk and"); DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!"); priv->rf_close = rtl8225z2_rf_close; priv->rf_init = rtl8225z2_rf_init; priv->rf_set_chan = rtl8225z2_rf_set_chan; priv->rf_set_sens = NULL; //priv->rf_sleep = rtl8225_rf_sleep; //priv->rf_wakeup = rtl8225_rf_wakeup; #else /* check RF frontend chipset */ switch (priv->rf_chip) { case RFCHIPID_RTL8225: if(priv->card_8185){ DMESG("Card reports RF frontend Realtek 8225"); DMESGW("This driver has EXPERIMENTAL support for this chipset."); DMESGW("use it with care and at your own risk and"); DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); priv->rf_close = rtl8225_rf_close; priv->rf_init = rtl8225_rf_init; priv->rf_set_chan = rtl8225_rf_set_chan; priv->rf_set_sens = NULL; priv->rf_sleep = rtl8225_rf_sleep; priv->rf_wakeup = rtl8225_rf_wakeup; }else{ DMESGW("Detected RTL8225 radio on a card recognized as RTL8180"); DMESGW("This could not be... something went wrong...."); return -ENODEV; } break; case RFCHIPID_RTL8255: if(priv->card_8185){ DMESG("Card reports RF frontend Realtek 8255"); DMESGW("This driver has EXPERIMENTAL support for this chipset."); DMESGW("use it with care and at your own risk and"); DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); priv->rf_close = rtl8255_rf_close; priv->rf_init = rtl8255_rf_init; priv->rf_set_chan = rtl8255_rf_set_chan; priv->rf_set_sens = NULL; priv->rf_sleep = NULL; priv->rf_wakeup = NULL; }else{ DMESGW("Detected RTL8255 radio on a card recognized as RTL8180"); DMESGW("This could not be... something went wrong...."); return -ENODEV; } break; case RFCHIPID_INTERSIL: DMESGW("Card reports RF frontend by Intersil."); DMESGW("This driver has NO support for this chipset."); return -ENODEV; break; case RFCHIPID_RFMD: DMESGW("Card reports RF frontend by RFMD."); DMESGW("This driver has NO support for this chipset."); return -ENODEV; break; case RFCHIPID_GCT: DMESGW("Card reports RF frontend by GCT."); DMESGW("This driver has EXPERIMENTAL support for this chipset."); DMESGW("use it with care and at your own risk and"); DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); priv->rf_close = gct_rf_close; priv->rf_init = gct_rf_init; priv->rf_set_chan = gct_rf_set_chan; priv->rf_set_sens = NULL; priv->rf_sleep = NULL; priv->rf_wakeup = NULL; break; case RFCHIPID_MAXIM: DMESGW("Card reports RF frontend by MAXIM."); DMESGW("This driver has EXPERIMENTAL support for this chipset."); DMESGW("use it with care and at your own risk and"); DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); priv->rf_close = maxim_rf_close; priv->rf_init = maxim_rf_init; priv->rf_set_chan = maxim_rf_set_chan; priv->rf_set_sens = NULL; priv->rf_sleep = NULL; priv->rf_wakeup = NULL; break; case RFCHIPID_PHILIPS: DMESG("Card reports RF frontend by Philips."); DMESG("OK! Philips SA2400 radio chipset is supported."); priv->rf_close = sa2400_rf_close; priv->rf_init = sa2400_rf_init; priv->rf_set_chan = sa2400_rf_set_chan; priv->rf_set_sens = sa2400_rf_set_sens; priv->sens = SA2400_RF_DEF_SENS; /* default sensitivity */ priv->max_sens = SA2400_RF_MAX_SENS; /* maximum sensitivity */ priv->rf_sleep = NULL; priv->rf_wakeup = NULL; if(priv->digphy){ DMESGW("Digital PHY found"); DMESGW("Philips DIGITAL PHY is untested! *Please*\ report success/failure to "); }else{ DMESG ("Analog PHY found"); } break; default: DMESGW("Unknown RF module %x",priv->rf_chip); DMESGW("Exiting..."); return -1; } #endif if(!priv->card_8185){ if(priv->antb) DMESG ("Antenna B is default antenna"); else DMESG ("Antenna A is default antenna"); if(priv->diversity) DMESG ("Antenna diversity is enabled"); else DMESG("Antenna diversity is disabled"); DMESG("Carrier sense %d",priv->rcr_csense); } if (0!=alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, TX_MANAGEPRIORITY_RING_ADDR)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, TX_BKPRIORITY_RING_ADDR)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, TX_BEPRIORITY_RING_ADDR)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, TX_VIPRIORITY_RING_ADDR)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, TX_VOPRIORITY_RING_ADDR)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, TX_HIGHPRIORITY_RING_ADDR)) return -ENOMEM; if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount, TX_BEACON_RING_ADDR)) return -ENOMEM; //priv->beacon_buf=NULL; if(!priv->card_8185){ if(read_nic_byte(dev, CONFIG0) & (1<irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)){ #else if(request_irq(dev->irq, (void *)rtl8180_interrupt, SA_SHIRQ, dev->name, dev)){ #endif DMESGE("Error allocating IRQ %d",dev->irq); return -1; }else{ priv->irq=dev->irq; DMESG("IRQ %d",dev->irq); } #ifdef DEBUG_EPROM dump_eprom(dev); #endif return 0; } void rtl8180_no_hw_wep(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); if(!priv->card_8185) { u8 security; security = read_nic_byte(dev, SECURITY); security &=~(1<ieee80211->hw_wep=0; } void rtl8180_set_hw_wep(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); u8 pgreg; u8 security; u32 key0_word4; pgreg=read_nic_byte(dev, PGSELECT); write_nic_byte(dev, PGSELECT, pgreg &~ (1<key0[3]& 0xff; write_nic_dword(dev,KEY0,(priv->key0[0])); write_nic_dword(dev,KEY0+4,(priv->key0[1])); write_nic_dword(dev,KEY0+4+4,(priv->key0[2])); write_nic_dword(dev,KEY0+4+4+4,(key0_word4)); /* TX_CONF,read_nic_dword(dev,TX_CONF) &~(1<ieee80211->hw_wep=1; } void rtl8185_rf_pins_enable(struct net_device *dev) { // u16 tmp; // tmp = read_nic_word(dev, RFPinsEnable); write_nic_word(dev, RFPinsEnable, 0x1fff);// | tmp); // write_nic_word(dev, RFPinsEnable,7 | tmp); } void rtl8185_set_anaparam2(struct net_device *dev, u32 a) { u8 conf3; rtl8180_set_mode(dev, EPROM_CMD_CONFIG); conf3 = read_nic_byte(dev, CONFIG3); write_nic_byte(dev, CONFIG3, conf3 | (1<> 24)); write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff) )); #endif /* this is ok to fail when we write AGC table. check for AGC table might be * done by masking with 0x7f instead of 0xff */ //if(phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data,adr); } inline void write_phy_ofdm (struct net_device *dev, u8 adr, u32 data) { data = data & 0xff; rtl8185_write_phy(dev, adr, data); } void write_phy_cck (struct net_device *dev, u8 adr, u32 data) { data = data & 0xff; rtl8185_write_phy(dev, adr, data | 0x10000); } /* 70*3 = 210 ms * I hope this is enougth */ #define MAX_PHY 70 void write_phy(struct net_device *dev, u8 adr, u8 data) { u32 phy; int i; phy = 0xff0000; phy |= adr; phy |= 0x80; /* this should enable writing */ phy |= (data<<8); //PHY_ADR, PHY_R and PHY_W are contig and treated as one dword write_nic_dword(dev,PHY_ADR, phy); phy= 0xffff00; phy |= adr; write_nic_dword(dev,PHY_ADR, phy); for(i=0;i> 16; if(phy == data){ //SUCCESS! force_pci_posting(dev); mdelay(3); //random value #ifdef DEBUG_BB DMESG("Phy wr %x,%x",adr,data); #endif return; }else{ force_pci_posting(dev); mdelay(3); //random value } } DMESGW ("Phy writing %x %x failed!", adr,data); } void rtl8185_set_rate(struct net_device *dev) { int i; u16 word; int basic_rate,min_rr_rate,max_rr_rate; // struct r8180_priv *priv = ieee80211_priv(dev); //if (ieee80211_is_54g(priv->ieee80211->current_network) && // priv->ieee80211->state == IEEE80211_LINKED){ basic_rate = ieeerate2rtlrate(240); min_rr_rate = ieeerate2rtlrate(60); max_rr_rate = ieeerate2rtlrate(240); // // }else{ // basic_rate = ieeerate2rtlrate(20); // min_rr_rate = ieeerate2rtlrate(10); // max_rr_rate = ieeerate2rtlrate(110); // } write_nic_byte(dev, RESP_RATE, max_rr_rate<irq_mask = 0xafff; // priv->irq_mask = 0x4fcf; /* enable beacon timeout, beacon TX ok and err * LP tx ok and err, HP TX ok and err, NP TX ok and err, * RX ok and ERR, and GP timer */ priv->irq_mask = 0x6fcf; priv->dma_poll_mask = 0; rtl8180_beacon_tx_disable(dev); if(priv->card_type == CARDBUS ){ config3=read_nic_byte(dev, CONFIG3); write_nic_byte(dev,CONFIG3,config3 | CONFIG3_FuncRegEn); write_nic_word(dev,FEMR, FEMR_INTR | FEMR_WKUP | FEMR_GWAKE | read_nic_word(dev, FEMR)); } rtl8180_set_mode(dev, EPROM_CMD_CONFIG); write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); rtl8180_set_mode(dev, EPROM_CMD_NORMAL); rtl8180_update_msr(dev); if(!priv->card_8185){ anaparam = eprom_read(dev,EPROM_ANAPARAM_ADDRLWORD); anaparam |= eprom_read(dev,EPROM_ANAPARAM_ADDRHWORD)<<16; rtl8180_set_anaparam(dev,anaparam); } /* These might be unnecessary since we do in rx_enable / tx_enable */ fix_rx_fifo(dev); fix_tx_fifo(dev); /*set_nic_rxring(dev); set_nic_txring(dev);*/ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); /* The following is very strange. seems to be that 1 means test mode, but we need to acknolwledges the nic when a packet is ready altought we set it to 0 */ write_nic_byte(dev, CONFIG2, read_nic_byte(dev,CONFIG2) &~\ (1<card_8185) write_nic_byte(dev, CONFIG2, read_nic_byte(dev,CONFIG2)|(1<<4)); rtl8180_set_mode(dev,EPROM_CMD_NORMAL); write_nic_dword(dev,INT_TIMEOUT,0); #ifdef DEBUG_REGISTERS rtl8180_dump_reg(dev); #endif if(!priv->card_8185) { /* experimental - this might be needed to calibrate AGC, anyway it shouldn't hurt */ write_nic_byte(dev, CONFIG5, read_nic_byte(dev, CONFIG5) | (1<card_8185){ rtl8185_set_rate(dev); write_nic_byte(dev, RATE_FALLBACK, 0x81); // write_nic_byte(dev, 0xdf, 0x15); }else{ word = read_nic_word(dev, BRSR); word &= ~BRSR_MBR; word &= ~BRSR_BPLCP; word |= ieeerate2rtlrate(priv->ieee80211->basic_rate); //by amy word |= 0x0f; //by amy write_nic_word(dev, BRSR, word); } if(priv->card_8185){ write_nic_byte(dev, GP_ENABLE,read_nic_byte(dev, GP_ENABLE) & ~(1<<6)); //FIXME cfg 3 ClkRun enable - isn't it ReadOnly ? rtl8180_set_mode(dev, EPROM_CMD_CONFIG); write_nic_byte(dev,CONFIG3, read_nic_byte(dev, CONFIG3) |(1<rf_init(dev); if(priv->rf_set_sens != NULL) priv->rf_set_sens(dev,priv->sens); rtl8180_irq_enable(dev); netif_start_queue(dev); /*DMESG ("lfree %d",get_curr_tx_free_desc(dev,LOW_PRIORITY)); DMESG ("nfree %d",get_curr_tx_free_desc(dev,NORM_PRIORITY)); DMESG ("hfree %d",get_curr_tx_free_desc(dev,HI_PRIORITY)); if(check_nic_enought_desc(dev,NORM_PRIORITY)) DMESG("NORM OK"); if(check_nic_enought_desc(dev,HI_PRIORITY)) DMESG("HI OK"); if(check_nic_enought_desc(dev,LOW_PRIORITY)) DMESG("LOW OK");*/ } /* this configures registers for beacon tx and enables it via * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might * be used to stop beacon transmission */ void rtl8180_start_tx_beacon(struct net_device *dev) { // struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u16 word; // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); DMESG("Enabling beacon TX"); //write_nic_byte(dev, 0x42,0xe6);// TCR // set_nic_txring(dev); // fix_tx_fifo(dev); rtl8180_prepare_beacon(dev); rtl8180_irq_disable(dev); rtl8180_beacon_tx_enable(dev); #if 0 rtl8180_set_mode(dev,EPROM_CMD_CONFIG); //write_nic_byte(dev,0x9d,0x20); //DMA Poll //write_nic_word(dev,0x7a,0); //write_nic_word(dev,0x7a,0x8000); #if 0 word = read_nic_word(dev, BcnItv); word &= ~BcnItv_BcnItv; // clear Bcn_Itv word |= priv->ieee80211->current_network.beacon_interval;//0x64; write_nic_word(dev, BcnItv, word); #endif #endif word = read_nic_word(dev, AtimWnd) &~ AtimWnd_AtimWnd; write_nic_word(dev, AtimWnd,word);// word |= //priv->ieee80211->current_network.atim_window); word = read_nic_word(dev, BintrItv); word &= ~BintrItv_BintrItv; word |= 1000;/*priv->ieee80211->current_network.beacon_interval * ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); // FIXME: check if correct ^^ worked with 0x3e8; */ write_nic_word(dev, BintrItv, word); rtl8180_set_mode(dev, EPROM_CMD_NORMAL); // rtl8180_beacon_tx_enable(dev); #ifdef CONFIG_RTL8185B rtl8185b_irq_enable(dev); #else rtl8180_irq_enable(dev); #endif /* VV !!!!!!!!!! VV*/ /* rtl8180_set_mode(dev,EPROM_CMD_CONFIG); write_nic_byte(dev,0x9d,0x00); rtl8180_set_mode(dev,EPROM_CMD_NORMAL); */ // DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); } /*************************************************************************** -------------------------------NET STUFF--------------------------- ***************************************************************************/ static struct net_device_stats *rtl8180_stats(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); return &priv->ieee80211->stats; } // // Change current and default preamble mode. // 2005.01.06, by rcnjko. // bool MgntActSet_802_11_PowerSaveMode( struct r8180_priv *priv, RT_PS_MODE rtPsMode ) { // Currently, we do not change power save mode on IBSS mode. if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) { return false; } // // If we make HW to fill up the PwrMgt bit for us, // some AP will not response to our mgnt frames with PwrMgt bit set, // e.g. cannot associate the AP. // So I commented out it. 2005.02.16, by rcnjko. // // // Change device's power save mode. // Adapter->HalFunc.SetPSModeHandler( Adapter, rtPsMode ); // Update power save mode configured. // priv->dot11PowerSaveMode = rtPsMode; priv->ieee80211->ps = rtPsMode; // Determine ListenInterval. #if 0 if(priv->dot11PowerSaveMode == eMaxPs) { priv->ieee80211->ListenInterval = 10; } else { priv->ieee80211->ListenInterval = 2; } #endif return true; } //================================================================================ // Leisure Power Save in linked state. //================================================================================ // // Description: // Enter the leisure power save mode. // void LeisurePSEnter( struct r8180_priv *priv ) { if (priv->bLeisurePs) { if (priv->ieee80211->ps == IEEE80211_PS_DISABLED) { //printk("----Enter PS\n"); MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);//IEEE80211_PS_ENABLE } } } // // Description: // Leave the leisure power save mode. // void LeisurePSLeave( struct r8180_priv *priv ) { if (priv->bLeisurePs) { if (priv->ieee80211->ps != IEEE80211_PS_DISABLED) { //printk("----Leave PS\n"); MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED); } } } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_hw_wakeup_wq (struct work_struct *work) { // struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); // struct ieee80211_device * ieee = (struct ieee80211_device*) // container_of(work, struct ieee80211_device, watch_dog_wq); struct delayed_work *dwork = container_of(work,struct delayed_work,work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq); struct net_device *dev = ieee->dev; #else void rtl8180_hw_wakeup_wq(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); #endif // printk("dev is %d\n",dev); // printk("&*&(^*(&(&=========>%s()\n", __func__); rtl8180_hw_wakeup(dev); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_hw_sleep_wq (struct work_struct *work) { // struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); // struct ieee80211_device * ieee = (struct ieee80211_device*) // container_of(work, struct ieee80211_device, watch_dog_wq); struct delayed_work *dwork = container_of(work,struct delayed_work,work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq); struct net_device *dev = ieee->dev; #else void rtl8180_hw_sleep_wq(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); #endif rtl8180_hw_sleep_down(dev); } //YJ,add,080828,for KeepAlive static void MgntLinkKeepAlive(struct r8180_priv *priv ) { if (priv->keepAliveLevel == 0) return; if(priv->ieee80211->state == IEEE80211_LINKED) { // // Keep-Alive. // //printk("LastTx:%d Tx:%d LastRx:%d Rx:%ld Idle:%d\n",priv->link_detect.LastNumTxUnicast,priv->NumTxUnicast, priv->link_detect.LastNumRxUnicast, priv->ieee80211->NumRxUnicast, priv->link_detect.IdleCount); if ( (priv->keepAliveLevel== 2) || (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast && priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast ) ) { priv->link_detect.IdleCount++; // // Send a Keep-Alive packet packet to AP if we had been idle for a while. // if(priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1) ) { priv->link_detect.IdleCount = 0; ieee80211_sta_ps_send_null_frame(priv->ieee80211, false); } } else { priv->link_detect.IdleCount = 0; } priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast; priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast; } } //YJ,add,080828,for KeepAlive,end static u8 read_acadapter_file(char *filename); void rtl8180_watch_dog(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); bool bEnterPS = false; bool bBusyTraffic = false; u32 TotalRxNum = 0; u16 SlotIndex = 0; u16 i = 0; #ifdef ENABLE_IPS if(priv->ieee80211->actscanning == false){ if((priv->ieee80211->iw_mode != IW_MODE_ADHOC) && (priv->ieee80211->state == IEEE80211_NOLINK) && (priv->ieee80211->beinretry == false) && (priv->eRFPowerState == eRfOn)){ IPSEnter(dev); } } #endif //YJ,add,080828,for link state check if((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)){ SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum; priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod; for( i=0; ilink_detect.SlotNum; i++ ) TotalRxNum+= priv->link_detect.RxFrameNum[i]; //printk("&&&&&=== TotalRxNum = %d\n", TotalRxNum); if(TotalRxNum == 0){ priv->ieee80211->state = IEEE80211_ASSOCIATING; queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq); } } //YJ,add,080828,for KeepAlive MgntLinkKeepAlive(priv); //YJ,add,080828,for LPS #ifdef ENABLE_LPS if(priv->PowerProfile == POWER_PROFILE_BATTERY ) { //Turn on LeisurePS on battery power //printk("!!!!!On battery power\n"); priv->bLeisurePs = true; } else if(priv->PowerProfile == POWER_PROFILE_AC ) { // Turn off LeisurePS on AC power //printk("----On AC power\n"); LeisurePSLeave(priv); priv->bLeisurePs= false; } #endif #if 0 #ifndef ENABLE_LPS if(priv->ieee80211->state == IEEE80211_LINKED){ if( priv->NumRxOkInPeriod> 666 || priv->NumTxOkInPeriod > 666 ) { bBusyTraffic = true; } if((priv->ieee80211->NumRxData + priv->NumTxOkInPeriod)<8) { bEnterPS= true; } if(bEnterPS) { LeisurePSEnter(priv); } else { LeisurePSLeave(priv); } } else { LeisurePSLeave(priv); } #endif priv->NumRxOkInPeriod = 0; priv->NumTxOkInPeriod = 0; priv->ieee80211->NumRxData = 0; #else #ifdef ENABLE_LPS if(priv->ieee80211->state == IEEE80211_LINKED){ priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod; //printk("TxOk=%d RxOk=%d\n", priv->link_detect.NumTxOkInPeriod, priv->link_detect.NumRxOkInPeriod); if( priv->link_detect.NumRxOkInPeriod> 666 || priv->link_detect.NumTxOkInPeriod> 666 ) { bBusyTraffic = true; } if(((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8) || (priv->link_detect.NumRxOkInPeriod > 2)) { bEnterPS= false; } else { bEnterPS= true; } if(bEnterPS) { LeisurePSEnter(priv); } else { LeisurePSLeave(priv); } } else{ LeisurePSLeave(priv); } #endif priv->link_detect.bBusyTraffic = bBusyTraffic; priv->link_detect.NumRxOkInPeriod = 0; priv->link_detect.NumTxOkInPeriod = 0; priv->ieee80211->NumRxDataInPeriod = 0; priv->ieee80211->NumRxBcnInPeriod = 0; #endif } int _rtl8180_up(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); //int i; priv->up=1; DMESG("Bringing up iface"); #ifdef CONFIG_RTL8185B rtl8185b_adapter_start(dev); rtl8185b_rx_enable(dev); rtl8185b_tx_enable(dev); #else rtl8180_adapter_start(dev); rtl8180_rx_enable(dev); rtl8180_tx_enable(dev); #endif #ifdef ENABLE_IPS if(priv->bInactivePs){ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) IPSLeave(dev); } #endif //by amy 080312 #ifdef RATE_ADAPT timer_rate_adaptive((unsigned long)dev); #endif //by amy 080312 watch_dog_adaptive((unsigned long)dev); #ifdef SW_ANTE if(priv->bSwAntennaDiverity) SwAntennaDiversityTimerCallback(dev); #endif // IPSEnter(dev); ieee80211_softmac_start_protocol(priv->ieee80211); //Add for RF power on power off by lizhaoming 080512 // priv->eRFPowerState = eRfOn; // printk("\n--------Start queue_work:GPIOChangeRFWorkItem"); // queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->GPIOChangeRFWorkItem,1000); return 0; } int rtl8180_open(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); int ret; down(&priv->wx_sem); ret = rtl8180_up(dev); up(&priv->wx_sem); return ret; } int rtl8180_up(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); if (priv->up == 1) return -1; return _rtl8180_up(dev); } int rtl8180_close(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); int ret; down(&priv->wx_sem); ret = rtl8180_down(dev); up(&priv->wx_sem); return ret; } int rtl8180_down(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); if (priv->up == 0) return -1; priv->up=0; ieee80211_softmac_stop_protocol(priv->ieee80211); /* FIXME */ if (!netif_queue_stopped(dev)) netif_stop_queue(dev); rtl8180_rtx_disable(dev); rtl8180_irq_disable(dev); del_timer_sync(&priv->watch_dog_timer); //cancel_delayed_work(&priv->ieee80211->watch_dog_wq); //{by amy 080312 del_timer_sync(&priv->rateadapter_timer); cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); //by amy 080312} cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); cancel_delayed_work(&priv->ieee80211->hw_dig_wq); cancel_delayed_work(&priv->ieee80211->tx_pw_wq); del_timer_sync(&priv->SwAntennaDiversityTimer); SetZebraRFPowerState8185(dev,eRfOff); //ieee80211_softmac_stop_protocol(priv->ieee80211); memset(&(priv->ieee80211->current_network),0,sizeof(struct ieee80211_network)); priv->ieee80211->state = IEEE80211_NOLINK; return 0; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_restart_wq(struct work_struct *work) { struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); struct net_device *dev = priv->dev; #else void rtl8180_restart_wq(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); #endif down(&priv->wx_sem); rtl8180_commit(dev); up(&priv->wx_sem); } void rtl8180_restart(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); //rtl8180_commit(dev); schedule_work(&priv->reset_wq); //DMESG("TXTIMEOUT"); } void rtl8180_commit(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); if (priv->up == 0) return ; //+by amy 080312 del_timer_sync(&priv->watch_dog_timer); //cancel_delayed_work(&priv->ieee80211->watch_dog_wq); //{by amy 080312 //by amy for rate adaptive del_timer_sync(&priv->rateadapter_timer); cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); //by amy for rate adaptive //by amy 080312} cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); cancel_delayed_work(&priv->ieee80211->hw_dig_wq); cancel_delayed_work(&priv->ieee80211->tx_pw_wq); del_timer_sync(&priv->SwAntennaDiversityTimer); ieee80211_softmac_stop_protocol(priv->ieee80211); rtl8180_irq_disable(dev); rtl8180_rtx_disable(dev); _rtl8180_up(dev); } static void r8180_set_multicast(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); short promisc; //down(&priv->wx_sem); promisc = (dev->flags & IFF_PROMISC) ? 1:0; if (promisc != priv->promisc) rtl8180_restart(dev); priv->promisc = promisc; //up(&priv->wx_sem); } #if 0 /* this is called by the kernel when it needs to TX a 802.3 encapsulated frame*/ int rtl8180_8023_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); int ret; unsigned long flags; spin_lock_irqsave(&priv->tx_lock,flags); ret = ieee80211_r8180_8023_hardstartxmit(skb,priv->ieee80211); spin_unlock_irqrestore(&priv->tx_lock,flags); return ret; } #endif int r8180_set_mac_adr(struct net_device *dev, void *mac) { struct r8180_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = mac; down(&priv->wx_sem); memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); if(priv->ieee80211->iw_mode == IW_MODE_MASTER) memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN); if (priv->up) { rtl8180_down(dev); rtl8180_up(dev); } up(&priv->wx_sem); return 0; } /* based on ipw2200 driver */ int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); struct iwreq *wrq = (struct iwreq *) rq; int ret=-1; switch (cmd) { case RTL_IOCTL_WPA_SUPPLICANT: ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); return ret; default: return -EOPNOTSUPP; } return -EOPNOTSUPP; } /**************************************************************************** -----------------------------PCI STUFF--------------------------- *****************************************************************************/ static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { unsigned long ioaddr = 0; struct net_device *dev = NULL; struct r8180_priv *priv= NULL; //u8 *ptr; u8 unit = 0; #ifdef CONFIG_RTL8180_IO_MAP unsigned long pio_start, pio_len, pio_flags; #else unsigned long pmem_start, pmem_len, pmem_flags; #endif //end #ifdef RTL_IO_MAP DMESG("Configuring chip resources"); if( pci_enable_device (pdev) ){ DMESG("Failed to enable PCI device"); return -EIO; } pci_set_master(pdev); //pci_set_wmi(pdev); pci_set_dma_mask(pdev, 0xffffff00ULL); pci_set_consistent_dma_mask(pdev,0xffffff00ULL); dev = alloc_ieee80211(sizeof(struct r8180_priv)); if (!dev) return -ENOMEM; priv = ieee80211_priv(dev); priv->ieee80211 = netdev_priv(dev); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) SET_MODULE_OWNER(dev); #endif pci_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); priv = ieee80211_priv(dev); // memset(priv,0,sizeof(struct r8180_priv)); priv->pdev=pdev; #ifdef CONFIG_RTL8180_IO_MAP pio_start = (unsigned long)pci_resource_start (pdev, 0); pio_len = (unsigned long)pci_resource_len (pdev, 0); pio_flags = (unsigned long)pci_resource_flags (pdev, 0); if (!(pio_flags & IORESOURCE_IO)) { DMESG("region #0 not a PIO resource, aborting"); goto fail; } //DMESG("IO space @ 0x%08lx", pio_start ); if( ! request_region( pio_start, pio_len, RTL8180_MODULE_NAME ) ){ DMESG("request_region failed!"); goto fail; } ioaddr = pio_start; dev->base_addr = ioaddr; // device I/O address #else pmem_start = pci_resource_start(pdev, 1); pmem_len = pci_resource_len(pdev, 1); pmem_flags = pci_resource_flags (pdev, 1); if (!(pmem_flags & IORESOURCE_MEM)) { DMESG("region #1 not a MMIO resource, aborting"); goto fail; } //DMESG("Memory mapped space @ 0x%08lx ", pmem_start); if( ! request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) { DMESG("request_mem_region failed!"); goto fail; } ioaddr = (unsigned long)ioremap_nocache( pmem_start, pmem_len); if( ioaddr == (unsigned long)NULL ){ DMESG("ioremap failed!"); // release_mem_region( pmem_start, pmem_len ); goto fail1; } dev->mem_start = ioaddr; // shared mem start dev->mem_end = ioaddr + pci_resource_len(pdev, 0); // shared mem end #endif //end #ifdef RTL_IO_MAP #ifdef CONFIG_RTL8185B //pci_read_config_byte(pdev, 0x05, ptr); //pci_write_config_byte(pdev, 0x05, (*ptr) & (~0x04)); pci_read_config_byte(pdev, 0x05, &unit); pci_write_config_byte(pdev, 0x05, unit & (~0x04)); #endif dev->irq = pdev->irq; priv->irq = 0; dev->open = rtl8180_open; dev->stop = rtl8180_close; //dev->hard_start_xmit = ieee80211_xmit; dev->tx_timeout = rtl8180_restart; dev->wireless_handlers = &r8180_wx_handlers_def; dev->do_ioctl = rtl8180_ioctl; dev->set_multicast_list = r8180_set_multicast; dev->set_mac_address = r8180_set_mac_adr; #if WIRELESS_EXT >= 12 #if WIRELESS_EXT < 17 dev->get_wireless_stats = r8180_get_wireless_stats; #endif dev->wireless_handlers = (struct iw_handler_def *) &r8180_wx_handlers_def; #endif dev->type=ARPHRD_ETHER; dev->watchdog_timeo = HZ*3; //added by david woo, 2007.12.13 if (dev_alloc_name(dev, ifname) < 0){ DMESG("Oops: devname already taken! Trying wlan%%d...\n"); ifname = "wlan%d"; // ifname = "ath%d"; dev_alloc_name(dev, ifname); } if(rtl8180_init(dev)!=0){ DMESG("Initialization failed"); goto fail1; } netif_carrier_off(dev); register_netdev(dev); rtl8180_proc_init_one(dev); DMESG("Driver probe completed\n"); return 0; fail1: #ifdef CONFIG_RTL8180_IO_MAP if( dev->base_addr != 0 ){ release_region(dev->base_addr, pci_resource_len(pdev, 0) ); } #else if( dev->mem_start != (unsigned long)NULL ){ iounmap( (void *)dev->mem_start ); release_mem_region( pci_resource_start(pdev, 1), pci_resource_len(pdev, 1) ); } #endif //end #ifdef RTL_IO_MAP fail: if(dev){ if (priv->irq) { free_irq(dev->irq, dev); dev->irq=0; } free_ieee80211(dev); } pci_disable_device(pdev); DMESG("wlan driver load failed\n"); pci_set_drvdata(pdev, NULL); return -ENODEV; } static void __devexit rtl8180_pci_remove(struct pci_dev *pdev) { struct r8180_priv *priv; struct net_device *dev = pci_get_drvdata(pdev); if(dev){ unregister_netdev(dev); priv=ieee80211_priv(dev); rtl8180_proc_remove_one(dev); rtl8180_down(dev); priv->rf_close(dev); rtl8180_reset(dev); //rtl8180_rtx_disable(dev); //rtl8180_irq_disable(dev); mdelay(10); //write_nic_word(dev,INTA,read_nic_word(dev,INTA)); //force_pci_posting(dev); //mdelay(10); if(priv->irq){ DMESG("Freeing irq %d",dev->irq); free_irq(dev->irq, dev); priv->irq=0; } free_rx_desc_ring(dev); free_tx_desc_rings(dev); // free_beacon_desc_ring(dev,priv->txbeaconcount); #ifdef CONFIG_RTL8180_IO_MAP if( dev->base_addr != 0 ){ release_region(dev->base_addr, pci_resource_len(pdev, 0) ); } #else if( dev->mem_start != (unsigned long)NULL ){ iounmap( (void *)dev->mem_start ); release_mem_region( pci_resource_start(pdev, 1), pci_resource_len(pdev, 1) ); } #endif /*end #ifdef RTL_IO_MAP*/ free_ieee80211(dev); } pci_disable_device(pdev); DMESG("wlan driver removed\n"); } /* fun with the built-in ieee80211 stack... */ extern int ieee80211_crypto_init(void); extern void ieee80211_crypto_deinit(void); extern int ieee80211_crypto_tkip_init(void); extern void ieee80211_crypto_tkip_exit(void); extern int ieee80211_crypto_ccmp_init(void); extern void ieee80211_crypto_ccmp_exit(void); extern int ieee80211_crypto_wep_init(void); extern void ieee80211_crypto_wep_exit(void); static int __init rtl8180_pci_module_init(void) { int ret; ret = ieee80211_crypto_init(); if (ret) { printk(KERN_ERR "ieee80211_crypto_init() failed %d\n", ret); return ret; } ret = ieee80211_crypto_tkip_init(); if (ret) { printk(KERN_ERR "ieee80211_crypto_tkip_init() failed %d\n", ret); return ret; } ret = ieee80211_crypto_ccmp_init(); if (ret) { printk(KERN_ERR "ieee80211_crypto_ccmp_init() failed %d\n", ret); return ret; } ret = ieee80211_crypto_wep_init(); if (ret) { printk(KERN_ERR "ieee80211_crypto_wep_init() failed %d\n", ret); return ret; } printk(KERN_INFO "\nLinux kernel driver for RTL8180 \ / RTL8185 based WLAN cards\n"); printk(KERN_INFO "Copyright (c) 2004-2005, Andrea Merello\n"); DMESG("Initializing module"); DMESG("Wireless extensions version %d", WIRELESS_EXT); rtl8180_proc_module_init(); #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) if(0!=pci_module_init(&rtl8180_pci_driver)) #else if(0!=pci_register_driver(&rtl8180_pci_driver)) #endif //if(0!=pci_module_init(&rtl8180_pci_driver)) { DMESG("No device found"); /*pci_unregister_driver (&rtl8180_pci_driver);*/ return -ENODEV; } return 0; } static void __exit rtl8180_pci_module_exit(void) { pci_unregister_driver (&rtl8180_pci_driver); rtl8180_proc_module_remove(); ieee80211_crypto_deinit(); ieee80211_crypto_tkip_exit(); ieee80211_crypto_ccmp_exit(); ieee80211_crypto_wep_exit(); DMESG("Exiting"); } void rtl8180_try_wake_queue(struct net_device *dev, int pri) { unsigned long flags; short enough_desc; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); spin_lock_irqsave(&priv->tx_lock,flags); enough_desc = check_nic_enought_desc(dev,pri); spin_unlock_irqrestore(&priv->tx_lock,flags); if(enough_desc) ieee80211_wake_queue(priv->ieee80211); } /***************************************************************************** -----------------------------IRQ STUFF--------------------------- ******************************************************************************/ void rtl8180_tx_isr(struct net_device *dev, int pri,short error) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u32 *tail; //tail virtual addr u32 *head; //head virtual addr u32 *begin;//start of ring virtual addr u32 *nicv; //nic pointer virtual addr // u32 *txdv; //packet just TXed u32 nic; //nic pointer physical addr u32 nicbegin;// start of ring physical addr // short txed; unsigned long flag; /* physical addr are ok on 32 bits since we set DMA mask*/ int offs; int j,i; int hd; if (error) priv->stats.txretry++; //tony 20060601 spin_lock_irqsave(&priv->tx_lock,flag); switch(pri) { case MANAGE_PRIORITY: tail = priv->txmapringtail; begin = priv->txmapring; head = priv->txmapringhead; nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR); nicbegin = priv->txmapringdma; break; case BK_PRIORITY: tail = priv->txbkpringtail; begin = priv->txbkpring; head = priv->txbkpringhead; nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR); nicbegin = priv->txbkpringdma; break; case BE_PRIORITY: tail = priv->txbepringtail; begin = priv->txbepring; head = priv->txbepringhead; nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR); nicbegin = priv->txbepringdma; break; case VI_PRIORITY: tail = priv->txvipringtail; begin = priv->txvipring; head = priv->txvipringhead; nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR); nicbegin = priv->txvipringdma; break; case VO_PRIORITY: tail = priv->txvopringtail; begin = priv->txvopring; head = priv->txvopringhead; nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR); nicbegin = priv->txvopringdma; break; case HI_PRIORITY: tail = priv->txhpringtail; begin = priv->txhpring; head = priv->txhpringhead; nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR); nicbegin = priv->txhpringdma; break; default: spin_unlock_irqrestore(&priv->tx_lock,flag); return ; } /* DMESG("%x %s %x %x",((int)nic & 0xfff)/8/4, *(priv->txnpring + ((int)nic&0xfff)/4/8) & (1<<31) ? "filled" : "empty", (priv->txnpringtail - priv->txnpring)/8,(priv->txnpringhead - priv->txnpring)/8); */ //nicv = (u32*) ((nic - nicbegin) + (int)begin); nicv = (u32*) ((nic - nicbegin) + (u8*)begin); if((head <= tail && (nicv > tail || nicv < head)) || (head > tail && (nicv > tail && nicv < head))){ DMESGW("nic has lost pointer"); #ifdef DEBUG_TX_DESC //check_tx_ring(dev,NORM_PRIORITY); check_tx_ring(dev,pri); #endif spin_unlock_irqrestore(&priv->tx_lock,flag); rtl8180_restart(dev); return; } /* we check all the descriptors between the head and the nic, * but not the currenly pointed by the nic (the next to be txed) * and the previous of the pointed (might be in process ??) */ //if (head == nic) return; //DMESG("%x %x",head,nic); offs = (nic - nicbegin); //DMESG("%x %x %x",nic ,(u32)nicbegin, (int)nic -nicbegin); offs = offs / 8 /4; hd = (head - begin) /8; if(offs >= hd) j = offs - hd; else j = offs + (priv->txringcount -1 -hd); // j= priv->txringcount -1- (hd - offs); j-=2; if(j<0) j=0; for(i=0;iCurrRetryCnt += (u16)((*head) & (0x000000ff)); #if 1 if(!error) { priv->NumTxOkTotal++; // printk("NumTxOkTotal is %d\n",priv->NumTxOkTotal++); } #endif // printk("in function %s:curr_retry_count is %d\n",__func__,((*head) & (0x000000ff))); } if(!error){ priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff); } // printk("in function %s:curr_txokbyte_count is %d\n",__func__,(*(head+3)) & (0x00000fff)); *head = *head &~ (1<<31); if((head - begin)/8 == priv->txringcount-1) head=begin; else head+=8; } #if 0 if(nicv == begin) txdv = begin + (priv->txringcount -1)*8; else txdv = nicv - 8; txed = !(txdv[0] &(1<<31)); if(txed){ if(!(txdv[0] & (1<<15))) error = 1; //if(!(txdv[0] & (1<<30))) error = 1; if(error)DMESG("%x",txdv[0]); } #endif //DMESG("%x",txdv[0]); /* the head has been moved to the last certainly TXed * (or at least processed by the nic) packet. * The driver take forcefully owning of all these packets * If the packet previous of the nic pointer has been * processed this doesn't matter: it will be checked * here at the next round. Anyway if no more packet are * TXed no memory leak occour at all. */ switch(pri) { case MANAGE_PRIORITY: priv->txmapringhead = head; //printk("1==========================================> priority check!\n"); if(priv->ack_tx_to_ieee){ // try to implement power-save mode 2008.1.22 // printk("2==========================================> priority check!\n"); #if 1 if(rtl8180_is_tx_queue_empty(dev)){ // printk("tx queue empty, after send null sleep packet, try to sleep !\n"); priv->ack_tx_to_ieee = 0; ieee80211_ps_tx_ack(priv->ieee80211,!error); } #endif } break; case BK_PRIORITY: priv->txbkpringhead = head; break; case BE_PRIORITY: priv->txbepringhead = head; break; case VI_PRIORITY: priv->txvipringhead = head; break; case VO_PRIORITY: priv->txvopringhead = head; break; case HI_PRIORITY: priv->txhpringhead = head; break; } /*DMESG("%x %x %x", (priv->txnpringhead - priv->txnpring) /8 , (priv->txnpringtail - priv->txnpring) /8, offs ); */ spin_unlock_irqrestore(&priv->tx_lock,flag); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void rtl8180_tx_irq_wq(struct work_struct *work) { //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); struct delayed_work *dwork = container_of(work,struct delayed_work,work); struct ieee80211_device * ieee = (struct ieee80211_device*) container_of(dwork, struct ieee80211_device, watch_dog_wq); struct net_device *dev = ieee->dev; #else void rtl8180_tx_irq_wq(struct net_device *dev) { //struct r8180_priv *priv = ieee80211_priv(dev); #endif rtl8180_tx_isr(dev,MANAGE_PRIORITY,0); } irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) netdev; struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); unsigned long flags; u32 inta; /* We should return IRQ_NONE, but for now let me keep this */ if(priv->irq_enabled == 0) return IRQ_HANDLED; spin_lock_irqsave(&priv->irq_th_lock,flags); #ifdef CONFIG_RTL8185B //ISR: 4bytes inta = read_nic_dword(dev, ISR);// & priv->IntrMask; write_nic_dword(dev,ISR,inta); // reset int situation #else inta = read_nic_word(dev,INTA) & priv->irq_mask; write_nic_word(dev,INTA,inta); // reset int situation #endif priv->stats.shints++; //DMESG("Enter interrupt, ISR value = 0x%08x", inta); if(!inta){ spin_unlock_irqrestore(&priv->irq_th_lock,flags); return IRQ_HANDLED; /* most probably we can safely return IRQ_NONE, but for now is better to avoid problems */ } if(inta == 0xffff){ /* HW disappared */ spin_unlock_irqrestore(&priv->irq_th_lock,flags); return IRQ_HANDLED; } priv->stats.ints++; #ifdef DEBUG_IRQ DMESG("NIC irq %x",inta); #endif //priv->irqpending = inta; if(!netif_running(dev)) { spin_unlock_irqrestore(&priv->irq_th_lock,flags); return IRQ_HANDLED; } if(inta & ISR_TimeOut){ write_nic_dword(dev, TimerInt, 0); //DMESG("=================>waking up"); // rtl8180_hw_wakeup(dev); } if(inta & ISR_TBDOK){ priv->stats.txbeacon++; } if(inta & ISR_TBDER){ priv->stats.txbeaconerr++; } if(inta & IMR_TMGDOK ) { // priv->NumTxOkTotal++; rtl8180_tx_isr(dev,MANAGE_PRIORITY,0); // schedule_work(&priv->tx_irq_wq); } if(inta & ISR_THPDER){ #ifdef DEBUG_TX DMESG ("TX high priority ERR"); #endif priv->stats.txhperr++; rtl8180_tx_isr(dev,HI_PRIORITY,1); priv->ieee80211->stats.tx_errors++; } if(inta & ISR_THPDOK){ //High priority tx ok #ifdef DEBUG_TX DMESG ("TX high priority OK"); #endif // priv->NumTxOkTotal++; //priv->NumTxOkInPeriod++; //YJ,del,080828 priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 priv->stats.txhpokint++; rtl8180_tx_isr(dev,HI_PRIORITY,0); } if(inta & ISR_RER) { priv->stats.rxerr++; #ifdef DEBUG_RX DMESGW("RX error int"); #endif } #ifdef CONFIG_RTL8185B if(inta & ISR_TBKDER){ //corresponding to BK_PRIORITY priv->stats.txbkperr++; priv->ieee80211->stats.tx_errors++; #ifdef DEBUG_TX DMESGW("TX bkp error int"); #endif //tasklet_schedule(&priv->irq_tx_tasklet); rtl8180_tx_isr(dev,BK_PRIORITY,1); rtl8180_try_wake_queue(dev, BE_PRIORITY); } if(inta & ISR_TBEDER){ //corresponding to BE_PRIORITY priv->stats.txbeperr++; priv->ieee80211->stats.tx_errors++; #ifdef DEBUG_TX DMESGW("TX bep error int"); #endif rtl8180_tx_isr(dev,BE_PRIORITY,1); //tasklet_schedule(&priv->irq_tx_tasklet); rtl8180_try_wake_queue(dev, BE_PRIORITY); } #endif if(inta & ISR_TNPDER){ //corresponding to VO_PRIORITY priv->stats.txnperr++; priv->ieee80211->stats.tx_errors++; #ifdef DEBUG_TX DMESGW("TX np error int"); #endif //tasklet_schedule(&priv->irq_tx_tasklet); rtl8180_tx_isr(dev,NORM_PRIORITY,1); #ifdef CONFIG_RTL8185B rtl8180_try_wake_queue(dev, NORM_PRIORITY); #endif } if(inta & ISR_TLPDER){ //corresponding to VI_PRIORITY priv->stats.txlperr++; priv->ieee80211->stats.tx_errors++; #ifdef DEBUG_TX DMESGW("TX lp error int"); #endif rtl8180_tx_isr(dev,LOW_PRIORITY,1); //tasklet_schedule(&priv->irq_tx_tasklet); rtl8180_try_wake_queue(dev, LOW_PRIORITY); } if(inta & ISR_ROK){ #ifdef DEBUG_RX DMESG("Frame arrived !"); #endif //priv->NumRxOkInPeriod++; //YJ,del,080828 priv->stats.rxint++; tasklet_schedule(&priv->irq_rx_tasklet); } if(inta & ISR_RQoSOK ){ #ifdef DEBUG_RX DMESG("QoS Frame arrived !"); #endif //priv->NumRxOkInPeriod++; //YJ,del,080828 priv->stats.rxint++; tasklet_schedule(&priv->irq_rx_tasklet); } if(inta & ISR_BcnInt) { //DMESG("Preparing Beacons"); rtl8180_prepare_beacon(dev); } if(inta & ISR_RDU){ //#ifdef DEBUG_RX DMESGW("No RX descriptor available"); priv->stats.rxrdu++; //#endif tasklet_schedule(&priv->irq_rx_tasklet); /*queue_work(priv->workqueue ,&priv->restart_work);*/ } if(inta & ISR_RXFOVW){ #ifdef DEBUG_RX DMESGW("RX fifo overflow"); #endif priv->stats.rxoverflow++; tasklet_schedule(&priv->irq_rx_tasklet); //queue_work(priv->workqueue ,&priv->restart_work); } if(inta & ISR_TXFOVW) priv->stats.txoverflow++; if(inta & ISR_TNPDOK){ //Normal priority tx ok #ifdef DEBUG_TX DMESG ("TX normal priority OK"); #endif // priv->NumTxOkTotal++; //priv->NumTxOkInPeriod++; //YJ,del,080828 priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 // priv->ieee80211->stats.tx_packets++; priv->stats.txnpokint++; rtl8180_tx_isr(dev,NORM_PRIORITY,0); } if(inta & ISR_TLPDOK){ //Low priority tx ok #ifdef DEBUG_TX DMESG ("TX low priority OK"); #endif // priv->NumTxOkTotal++; //priv->NumTxOkInPeriod++; //YJ,del,080828 priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 // priv->ieee80211->stats.tx_packets++; priv->stats.txlpokint++; rtl8180_tx_isr(dev,LOW_PRIORITY,0); rtl8180_try_wake_queue(dev, LOW_PRIORITY); } #ifdef CONFIG_RTL8185B if(inta & ISR_TBKDOK){ //corresponding to BK_PRIORITY priv->stats.txbkpokint++; #ifdef DEBUG_TX DMESGW("TX bk priority ok"); #endif // priv->NumTxOkTotal++; //priv->NumTxOkInPeriod++; //YJ,del,080828 priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 rtl8180_tx_isr(dev,BK_PRIORITY,0); rtl8180_try_wake_queue(dev, BE_PRIORITY); } if(inta & ISR_TBEDOK){ //corresponding to BE_PRIORITY priv->stats.txbeperr++; #ifdef DEBUG_TX DMESGW("TX be priority ok"); #endif // priv->NumTxOkTotal++; //priv->NumTxOkInPeriod++; //YJ,del,080828 priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 rtl8180_tx_isr(dev,BE_PRIORITY,0); rtl8180_try_wake_queue(dev, BE_PRIORITY); } #endif force_pci_posting(dev); spin_unlock_irqrestore(&priv->irq_th_lock,flags); return IRQ_HANDLED; } void rtl8180_irq_rx_tasklet(struct r8180_priv* priv) { // unsigned long flags; /* spin_lock_irqsave(&priv->irq_lock, flags); priv->irq_mask &=~IMR_ROK; priv->irq_mask &=~IMR_RDU; rtl8180_irq_enable(priv->dev); spin_unlock_irqrestore(&priv->irq_lock, flags); */ rtl8180_rx(priv->dev); /* spin_lock_irqsave(&priv->irq_lock, flags); priv->irq_mask |= IMR_ROK; priv->irq_mask |= IMR_RDU; rtl8180_irq_enable(priv->dev); spin_unlock_irqrestore(&priv->irq_lock, flags); */ } /**************************************************************************** lizhaoming--------------------------- RF power on/power off ----------------- *****************************************************************************/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void GPIOChangeRFWorkItemCallBack(struct work_struct *work) { //struct delayed_work *dwork = container_of(work, struct delayed_work, work); struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work); struct net_device *dev = ieee->dev; struct r8180_priv *priv = ieee80211_priv(dev); #else void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee) { struct net_device *dev = ieee->dev; struct r8180_priv *priv = ieee80211_priv(dev); #endif //u16 tmp2byte; u8 btPSR; u8 btConfig0; RT_RF_POWER_STATE eRfPowerStateToSet; bool bActuallySet=false; char *argv[3]; static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh"; static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL}; static int readf_count = 0; //printk("============>%s in \n", __func__); #ifdef ENABLE_LPS if(readf_count % 10 == 0) priv->PowerProfile = read_acadapter_file("/proc/acpi/ac_adapter/AC0/state"); readf_count = (readf_count+1)%0xffff; #endif #if 0 if(priv->up == 0)//driver stopped { printk("\nDo nothing..."); goto out; } else #endif { // We should turn off LED before polling FF51[4]. //Turn off LED. btPSR = read_nic_byte(dev, PSR); write_nic_byte(dev, PSR, (btPSR & ~BIT3)); //It need to delay 4us suggested by Jong, 2008-01-16 udelay(4); //HW radio On/Off according to the value of FF51[4](config0) btConfig0 = btPSR = read_nic_byte(dev, CONFIG0); //Turn on LED. write_nic_byte(dev, PSR, btPSR| BIT3); eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff; if((priv->ieee80211->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn)) { priv->ieee80211->bHwRadioOff = false; bActuallySet = true; } else if((priv->ieee80211->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff)) { priv->ieee80211->bHwRadioOff = true; bActuallySet = true; } if(bActuallySet) { MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); /* To update the UI status for Power status changed */ if(priv->ieee80211->bHwRadioOff == true) argv[1] = "RFOFF"; else{ //if(!priv->RfOffReason) argv[1] = "RFON"; //else // argv[1] = "RFOFF"; } argv[0] = RadioPowerPath; argv[2] = NULL; call_usermodehelper(RadioPowerPath,argv,envp,1); } } } static u8 read_acadapter_file(char *filename) { //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) #if 0 int fd; char buf[1]; char ret[50]; int i = 0; int n = 0; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); fd = sys_open(filename, O_RDONLY, 0); if (fd >= 0) { while (sys_read(fd, buf, 1) == 1) { i++; if(i>10) { if(buf[0]!=' ') { ret[n]=buf[0]; n++; } } } sys_close(fd); } ret[n]='\0'; // printk("%s \n", ret); set_fs(old_fs); if(strncmp(ret, "off-line",8) == 0) { return 1; } #endif return 0; } /*************************************************************************** ------------------- module init / exit stubs ---------------- ****************************************************************************/ module_init(rtl8180_pci_module_init); module_exit(rtl8180_pci_module_exit);