diff options
Diffstat (limited to 'drivers/net/wireless')
48 files changed, 2878 insertions, 1941 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fa2399cbd5c..ae27af0141c 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -546,6 +546,18 @@ config USB_ZD1201 To compile this driver as a module, choose M here: the module will be called zd1201. +config RTL8187 + tristate "Realtek 8187 USB support" + depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL + select EEPROM_93CX6 + ---help--- + This is a driver for RTL8187 based cards. + These are USB based chips found in cards such as: + + Netgear WG111v2 + + Thanks to Realtek for their support! + source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index d2124602263..ef35bc6c4a2 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -44,3 +44,6 @@ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o obj-$(CONFIG_USB_ZD1201) += zd1201.o obj-$(CONFIG_LIBERTAS_USB) += libertas/ + +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o +obj-$(CONFIG_RTL8187) += rtl8187.o diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2d3a180dada..ee1cc14db38 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -52,6 +52,8 @@ #include "airo.h" +#define DRV_NAME "airo" + #ifdef CONFIG_PCI static struct pci_device_id card_ids[] = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, @@ -71,7 +73,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state); static int airo_pci_resume(struct pci_dev *pdev); static struct pci_driver airo_driver = { - .name = "airo", + .name = DRV_NAME, .id_table = card_ids, .probe = airo_pci_probe, .remove = __devexit_p(airo_pci_remove), @@ -1092,7 +1094,7 @@ static int get_dec_u16( char *buffer, int *start, int limit ); static void OUT4500( struct airo_info *, u16 register, u16 value ); static unsigned short IN4500( struct airo_info *, u16 register ); static u16 setup_card(struct airo_info*, u8 *mac, int lock); -static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ); +static int enable_MAC(struct airo_info *ai, int lock); static void disable_MAC(struct airo_info *ai, int lock); static void enable_interrupts(struct airo_info*); static void disable_interrupts(struct airo_info*); @@ -1250,7 +1252,7 @@ static int flashputbuf(struct airo_info *ai); static int flashrestart(struct airo_info *ai,struct net_device *dev); #define airo_print(type, name, fmt, args...) \ - { printk(type "airo(%s): " fmt "\n", name, ##args); } + printk(type DRV_NAME "(%s): " fmt "\n", name, ##args) #define airo_print_info(name, fmt, args...) \ airo_print(KERN_INFO, name, fmt, ##args) @@ -1926,28 +1928,54 @@ static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) { return rc; } +static void try_auto_wep(struct airo_info *ai) +{ + if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) { + ai->expires = RUN_AT(3*HZ); + wake_up_interruptible(&ai->thr_wait); + } +} + static int airo_open(struct net_device *dev) { - struct airo_info *info = dev->priv; - Resp rsp; + struct airo_info *ai = dev->priv; + int rc = 0; - if (test_bit(FLAG_FLASHING, &info->flags)) + if (test_bit(FLAG_FLASHING, &ai->flags)) return -EIO; /* Make sure the card is configured. * Wireless Extensions may postpone config changes until the card * is open (to pipeline changes and speed-up card setup). If * those changes are not yet commited, do it now - Jean II */ - if (test_bit (FLAG_COMMIT, &info->flags)) { - disable_MAC(info, 1); - writeConfigRid(info, 1); + if (test_bit(FLAG_COMMIT, &ai->flags)) { + disable_MAC(ai, 1); + writeConfigRid(ai, 1); } - if (info->wifidev != dev) { + if (ai->wifidev != dev) { + clear_bit(JOB_DIE, &ai->jobs); + ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name); + if (IS_ERR(ai->airo_thread_task)) + return (int)PTR_ERR(ai->airo_thread_task); + + rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED, + dev->name, dev); + if (rc) { + airo_print_err(dev->name, + "register interrupt %d failed, rc %d", + dev->irq, rc); + set_bit(JOB_DIE, &ai->jobs); + kthread_stop(ai->airo_thread_task); + return rc; + } + /* Power on the MAC controller (which may have been disabled) */ - clear_bit(FLAG_RADIO_DOWN, &info->flags); - enable_interrupts(info); + clear_bit(FLAG_RADIO_DOWN, &ai->flags); + enable_interrupts(ai); + + try_auto_wep(ai); } - enable_MAC(info, &rsp, 1); + enable_MAC(ai, 1); netif_start_queue(dev); return 0; @@ -2338,14 +2366,13 @@ static int airo_set_mac_address(struct net_device *dev, void *p) { struct airo_info *ai = dev->priv; struct sockaddr *addr = p; - Resp rsp; readConfigRid(ai, 1); memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); set_bit (FLAG_COMMIT, &ai->flags); disable_MAC(ai, 1); writeConfigRid (ai, 1); - enable_MAC(ai, &rsp, 1); + enable_MAC(ai, 1); memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len); if (ai->wifidev) memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len); @@ -2392,6 +2419,11 @@ static int airo_close(struct net_device *dev) { disable_MAC(ai, 1); #endif disable_interrupts( ai ); + + free_irq(dev->irq, dev); + + set_bit(JOB_DIE, &ai->jobs); + kthread_stop(ai->airo_thread_task); } return 0; } @@ -2403,7 +2435,6 @@ void stop_airo_card( struct net_device *dev, int freeres ) set_bit(FLAG_RADIO_DOWN, &ai->flags); disable_MAC(ai, 1); disable_interrupts(ai); - free_irq( dev->irq, dev ); takedown_proc_entry( dev, ai ); if (test_bit(FLAG_REGISTERED, &ai->flags)) { unregister_netdev( dev ); @@ -2414,9 +2445,6 @@ void stop_airo_card( struct net_device *dev, int freeres ) } clear_bit(FLAG_REGISTERED, &ai->flags); } - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); - /* * Clean out tx queue */ @@ -2554,8 +2582,7 @@ static int mpi_init_descriptors (struct airo_info *ai) * 2) Map PCI memory for issueing commands. * 3) Allocate memory (shared) to send and receive ethernet frames. */ -static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, - const char *name) +static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) { unsigned long mem_start, mem_len, aux_start, aux_len; int rc = -1; @@ -2569,35 +2596,35 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, aux_start = pci_resource_start(pci, 2); aux_len = AUXMEMSIZE; - if (!request_mem_region(mem_start, mem_len, name)) { - airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", - (int)mem_start, (int)mem_len, name); + if (!request_mem_region(mem_start, mem_len, DRV_NAME)) { + airo_print_err("", "Couldn't get region %x[%x]", + (int)mem_start, (int)mem_len); goto out; } - if (!request_mem_region(aux_start, aux_len, name)) { - airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", - (int)aux_start, (int)aux_len, name); + if (!request_mem_region(aux_start, aux_len, DRV_NAME)) { + airo_print_err("", "Couldn't get region %x[%x]", + (int)aux_start, (int)aux_len); goto free_region1; } ai->pcimem = ioremap(mem_start, mem_len); if (!ai->pcimem) { - airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", - (int)mem_start, (int)mem_len, name); + airo_print_err("", "Couldn't map region %x[%x]", + (int)mem_start, (int)mem_len); goto free_region2; } ai->pciaux = ioremap(aux_start, aux_len); if (!ai->pciaux) { - airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", - (int)aux_start, (int)aux_len, name); + airo_print_err("", "Couldn't map region %x[%x]", + (int)aux_start, (int)aux_len); goto free_memmap; } /* Reserve PKTSIZE for each fid and 2K for the Rids */ ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma); if (!ai->shared) { - airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d", - PCI_SHARED_LEN); + airo_print_err("", "Couldn't alloc_consistent %d", + PCI_SHARED_LEN); goto free_auxmap; } @@ -2742,7 +2769,7 @@ static int airo_networks_allocate(struct airo_info *ai) kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement), GFP_KERNEL); if (!ai->networks) { - airo_print_warn(ai->dev->name, "Out of memory allocating beacons"); + airo_print_warn("", "Out of memory allocating beacons"); return -ENOMEM; } @@ -2770,7 +2797,6 @@ static int airo_test_wpa_capable(struct airo_info *ai) { int status; CapabilityRid cap_rid; - const char *name = ai->dev->name; status = readCapabilityRid(ai, &cap_rid, 1); if (status != SUCCESS) return 0; @@ -2778,12 +2804,12 @@ static int airo_test_wpa_capable(struct airo_info *ai) /* Only firmware versions 5.30.17 or better can do WPA */ if ((cap_rid.softVer > 0x530) || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) { - airo_print_info(name, "WPA is supported."); + airo_print_info("", "WPA is supported."); return 1; } /* No WPA support */ - airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17" + airo_print_info("", "WPA unsupported (only firmware versions 5.30.17" " and greater support WPA. Detected %s)", cap_rid.prodVer); return 0; } @@ -2797,23 +2823,19 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, int i, rc; /* Create the network device object. */ - dev = alloc_etherdev(sizeof(*ai)); - if (!dev) { + dev = alloc_netdev(sizeof(*ai), "", ether_setup); + if (!dev) { airo_print_err("", "Couldn't alloc_etherdev"); return NULL; - } - if (dev_alloc_name(dev, dev->name) < 0) { - airo_print_err("", "Couldn't get name!"); - goto err_out_free; } ai = dev->priv; ai->wifidev = NULL; - ai->flags = 0; + ai->flags = 1 << FLAG_RADIO_DOWN; ai->jobs = 0; ai->dev = dev; if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { - airo_print_dbg(dev->name, "Found an MPI350 card"); + airo_print_dbg("", "Found an MPI350 card"); set_bit(FLAG_MPI, &ai->flags); } spin_lock_init(&ai->aux_lock); @@ -2821,14 +2843,11 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, ai->config.len = 0; ai->pci = pci; init_waitqueue_head (&ai->thr_wait); - ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name); - if (IS_ERR(ai->airo_thread_task)) - goto err_out_free; ai->tfm = NULL; add_airo_dev(ai); if (airo_networks_allocate (ai)) - goto err_out_thr; + goto err_out_free; airo_networks_initialize (ai); /* The Airo-specific entries in the device structure. */ @@ -2851,27 +2870,22 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, dev->base_addr = port; SET_NETDEV_DEV(dev, dmdev); + SET_MODULE_OWNER(dev); reset_card (dev, 1); msleep(400); - rc = request_irq( dev->irq, airo_interrupt, IRQF_SHARED, dev->name, dev ); - if (rc) { - airo_print_err(dev->name, "register interrupt %d failed, rc %d", - irq, rc); - goto err_out_nets; - } if (!is_pcmcia) { - if (!request_region( dev->base_addr, 64, dev->name )) { + if (!request_region(dev->base_addr, 64, DRV_NAME)) { rc = -EBUSY; airo_print_err(dev->name, "Couldn't request region"); - goto err_out_irq; + goto err_out_nets; } } if (test_bit(FLAG_MPI,&ai->flags)) { - if (mpi_map_card(ai, pci, dev->name)) { - airo_print_err(dev->name, "Could not map memory"); + if (mpi_map_card(ai, pci)) { + airo_print_err("", "Could not map memory"); goto err_out_res; } } @@ -2899,6 +2913,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra); } + strcpy(dev->name, "eth%d"); rc = register_netdev(dev); if (rc) { airo_print_err(dev->name, "Couldn't register_netdev"); @@ -2921,8 +2936,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, if (setup_proc_entry(dev, dev->priv) < 0) goto err_out_wifi; - netif_start_queue(dev); - SET_MODULE_OWNER(dev); return dev; err_out_wifi: @@ -2940,14 +2953,9 @@ err_out_map: err_out_res: if (!is_pcmcia) release_region( dev->base_addr, 64 ); -err_out_irq: - free_irq(dev->irq, dev); err_out_nets: airo_networks_free(ai); -err_out_thr: del_airo_dev(ai); - set_bit(JOB_DIE, &ai->jobs); - kthread_stop(ai->airo_thread_task); err_out_free: free_netdev(dev); return NULL; @@ -3078,7 +3086,8 @@ static int airo_thread(void *data) { struct net_device *dev = data; struct airo_info *ai = dev->priv; int locked; - + + set_freezable(); while(1) { /* make swsusp happy with our thread */ try_to_freeze(); @@ -3529,9 +3538,11 @@ static u16 IN4500( struct airo_info *ai, u16 reg ) { return rc; } -static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { +static int enable_MAC(struct airo_info *ai, int lock) +{ int rc; - Cmd cmd; + Cmd cmd; + Resp rsp; /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" @@ -3547,7 +3558,7 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { if (!test_bit(FLAG_ENABLED, &ai->flags)) { memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_ENABLE; - rc = issuecommand(ai, &cmd, rsp); + rc = issuecommand(ai, &cmd, &rsp); if (rc == SUCCESS) set_bit(FLAG_ENABLED, &ai->flags); } else @@ -3557,8 +3568,12 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { up(&ai->sem); if (rc) - airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d", - __FUNCTION__, rc); + airo_print_err(ai->dev->name, "Cannot enable MAC"); + else if ((rsp.status & 0xFF00) != 0) { + airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, " + "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2); + rc = ERROR; + } return rc; } @@ -3902,12 +3917,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) if ( status != SUCCESS ) return ERROR; } - status = enable_MAC(ai, &rsp, lock); - if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { - airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x," - " offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); + status = enable_MAC(ai, lock); + if (status != SUCCESS) return ERROR; - } /* Grab the initial wep key, we gotta save it for auto_wep */ rc = readWepKeyRid(ai, &wkr, 1, lock); @@ -3919,10 +3931,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) rc = readWepKeyRid(ai, &wkr, 0, lock); } while(lastindex != wkr.kindex); - if (auto_wep) { - ai->expires = RUN_AT(3*HZ); - wake_up_interruptible(&ai->thr_wait); - } + try_auto_wep(ai); return SUCCESS; } @@ -4004,7 +4013,7 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap ) } if ( !(max_tries--) ) { airo_print_err(ai->dev->name, - "airo: BAP setup error too many retries\n"); + "BAP setup error too many retries\n"); return ERROR; } // -- PC4500 missed it, try again @@ -5152,7 +5161,6 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) { struct net_device *dev = dp->data; struct airo_info *ai = dev->priv; SsidRid SSID_rid; - Resp rsp; int i; int offset = 0; @@ -5177,7 +5185,7 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) { SSID_rid.len = sizeof(SSID_rid); disable_MAC(ai, 1); writeSsidRid(ai, &SSID_rid, 1); - enable_MAC(ai, &rsp, 1); + enable_MAC(ai, 1); } static inline u8 hexVal(char c) { @@ -5193,7 +5201,6 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) { struct net_device *dev = dp->data; struct airo_info *ai = dev->priv; APListRid APList_rid; - Resp rsp; int i; if ( !data->writelen ) return; @@ -5218,18 +5225,17 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) { } disable_MAC(ai, 1); writeAPListRid(ai, &APList_rid, 1); - enable_MAC(ai, &rsp, 1); + enable_MAC(ai, 1); } /* This function wraps PC4500_writerid with a MAC disable */ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data, int len, int dummy ) { int rc; - Resp rsp; disable_MAC(ai, 1); rc = PC4500_writerid(ai, rid, rid_data, len, 1); - enable_MAC(ai, &rsp, 1); + enable_MAC(ai, 1); return rc; } @@ -5260,7 +5266,6 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key, u16 keylen, int perm, int lock ) { static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; WepKeyRid wkr; - Resp rsp; memset(&wkr, 0, sizeof(wkr)); if (keylen == 0) { @@ -5280,7 +5285,7 @@ static int set_wep_key(struct airo_info *ai, u16 index, if (perm) disable_MAC(ai, lock); writeWepKeyRid(ai, &wkr, perm, lock); - if (perm) enable_MAC(ai, &rsp, lock); + if (perm) enable_MAC(ai, lock); return 0; } @@ -5548,7 +5553,6 @@ static int proc_close( struct inode *inode, struct file *file ) changed. */ static void timer_func( struct net_device *dev ) { struct airo_info *apriv = dev->priv; - Resp rsp; /* We don't have a link so try changing the authtype */ readConfigRid(apriv, 0); @@ -5575,7 +5579,7 @@ static void timer_func( struct net_device *dev ) { } set_bit (FLAG_COMMIT, &apriv->flags); writeConfigRid(apriv, 0); - enable_MAC(apriv, &rsp, 0); + enable_MAC(apriv, 0); up(&apriv->sem); /* Schedule check to see if the change worked */ @@ -5597,8 +5601,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); else dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); - if (!dev) + if (!dev) { + pci_disable_device(pdev); return -ENODEV; + } pci_set_drvdata(pdev, dev); return 0; @@ -5610,6 +5616,8 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev) airo_print_info(dev->name, "Unregistering..."); stop_airo_card(dev, 1); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); } static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) @@ -5646,7 +5654,6 @@ static int airo_pci_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct airo_info *ai = dev->priv; - Resp rsp; pci_power_t prev_state = pdev->current_state; pci_set_power_state(pdev, PCI_D0); @@ -5679,7 +5686,7 @@ static int airo_pci_resume(struct pci_dev *pdev) ai->APList = NULL; } writeConfigRid(ai, 0); - enable_MAC(ai, &rsp, 0); + enable_MAC(ai, 0); ai->power = PMSG_ON; netif_device_attach(dev); netif_wake_queue(dev); @@ -5903,7 +5910,6 @@ static int airo_set_essid(struct net_device *dev, char *extra) { struct airo_info *local = dev->priv; - Resp rsp; SsidRid SSID_rid; /* SSIDs */ /* Reload the list of current SSID */ @@ -5935,7 +5941,7 @@ static int airo_set_essid(struct net_device *dev, /* Write it to the card */ disable_MAC(local, 1); writeSsidRid(local, &SSID_rid, 1); - enable_MAC(local, &rsp, 1); + enable_MAC(local, 1); return 0; } @@ -6000,7 +6006,7 @@ static int airo_set_wap(struct net_device *dev, memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN); disable_MAC(local, 1); writeAPListRid(local, &APList_rid, 1); - enable_MAC(local, &rsp, 1); + enable_MAC(local, 1); } return 0; } @@ -7454,7 +7460,6 @@ static int airo_config_commit(struct net_device *dev, char *extra) /* NULL */ { struct airo_info *local = dev->priv; - Resp rsp; if (!test_bit (FLAG_COMMIT, &local->flags)) return 0; @@ -7479,7 +7484,7 @@ static int airo_config_commit(struct net_device *dev, if (down_interruptible(&local->sem)) return -ERESTARTSYS; writeConfigRid(local, 0); - enable_MAC(local, &rsp, 0); + enable_MAC(local, 0); if (test_bit (FLAG_RESET, &local->flags)) airo_set_promisc(local); else @@ -7746,7 +7751,6 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { unsigned char *iobuf; int len; struct airo_info *ai = dev->priv; - Resp rsp; if (test_bit(FLAG_FLASHING, &ai->flags)) return -EIO; @@ -7758,7 +7762,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { if (test_bit(FLAG_COMMIT, &ai->flags)) { disable_MAC (ai, 1); writeConfigRid (ai, 1); - enable_MAC (ai, &rsp, 1); + enable_MAC(ai, 1); } break; case AIROGSLIST: ridcode = RID_SSID; break; @@ -7815,7 +7819,6 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { struct airo_info *ai = dev->priv; int ridcode; int enabled; - Resp rsp; static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); unsigned char *iobuf; @@ -7849,7 +7852,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { * same with MAC off */ case AIROPMACON: - if (enable_MAC(ai, &rsp, 1) != 0) + if (enable_MAC(ai, 1) != 0) return -EIO; return 0; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index ef6b253a92c..c5d6753a55e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3741,10 +3741,8 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) &bcm->board_type); if (err) goto err_iounmap; - err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, - &bcm->board_revision); - if (err) - goto err_iounmap; + + bcm->board_revision = bcm->pci_dev->revision; err = bcm43xx_chipset_attach(bcm); if (err) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index b37f1e34870..d779199c30d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1638,7 +1638,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, return; } - if (phy->analog > 1) { + if (phy->analog == 1) { value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; value |= (baseband_attenuation << 2) & 0x003C; } else { diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 5b3abd54d0e..90900525379 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -326,7 +326,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off, char *p = page; struct ap_data *ap = (struct ap_data *) data; char *policy_txt; - struct list_head *ptr; struct mac_entry *entry; if (off != 0) { @@ -352,14 +351,12 @@ static int ap_control_proc_read(char *page, char **start, off_t off, p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries); p += sprintf(p, "MAC list:\n"); spin_lock_bh(&ap->mac_restrictions.lock); - for (ptr = ap->mac_restrictions.mac_list.next; - ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) { + list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) { if (p - page > PAGE_SIZE - 80) { p += sprintf(p, "All entries did not fit one page.\n"); break; } - entry = list_entry(ptr, struct mac_entry, list); p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); } spin_unlock_bh(&ap->mac_restrictions.lock); @@ -413,7 +410,6 @@ int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, u8 *mac) { - struct list_head *ptr; struct mac_entry *entry; int found = 0; @@ -421,10 +417,7 @@ static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, return 0; spin_lock_bh(&mac_restrictions->lock); - for (ptr = mac_restrictions->mac_list.next; - ptr != &mac_restrictions->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, list); - + list_for_each_entry(entry, &mac_restrictions->mac_list, list) { if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { found = 1; break; @@ -519,7 +512,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, { char *p = page; struct ap_data *ap = (struct ap_data *) data; - struct list_head *ptr; + struct sta_info *sta; int i; if (off > PROC_LIMIT) { @@ -529,9 +522,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); spin_lock_bh(&ap->sta_table_lock); - for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; - + list_for_each_entry(sta, &ap->sta_list, list) { if (!sta->ap) continue; @@ -861,7 +852,7 @@ void hostap_init_ap_proc(local_info_t *local) void hostap_free_data(struct ap_data *ap) { - struct list_head *n, *ptr; + struct sta_info *n, *sta; if (ap == NULL || !ap->initialized) { printk(KERN_DEBUG "hostap_free_data: ap has not yet been " @@ -875,8 +866,7 @@ void hostap_free_data(struct ap_data *ap) ap->crypt = ap->crypt_priv = NULL; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - list_for_each_safe(ptr, n, &ap->sta_list) { - struct sta_info *sta = list_entry(ptr, struct sta_info, list); + list_for_each_entry_safe(sta, n, &ap->sta_list, list) { ap_sta_hash_del(ap, sta); list_del(&sta->list); if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) @@ -2704,6 +2694,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) if (hdr->addr1[0] & 0x01) { /* broadcast/multicast frame - no AP related processing */ + if (local->ap->num_sta <= 0) + ret = AP_TX_DROP; goto out; } @@ -3198,15 +3190,14 @@ int hostap_update_rx_stats(struct ap_data *ap, void hostap_update_rates(local_info_t *local) { - struct list_head *ptr; + struct sta_info *sta; struct ap_data *ap = local->ap; if (!ap) return; spin_lock_bh(&ap->sta_table_lock); - for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { - struct sta_info *sta = (struct sta_info *) ptr; + list_for_each_entry(sta, &ap->sta_list, list) { prism2_check_tx_rates(sta); } spin_unlock_bh(&ap->sta_table_lock); @@ -3242,11 +3233,10 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, void hostap_add_wds_links(local_info_t *local) { struct ap_data *ap = local->ap; - struct list_head *ptr; + struct sta_info *sta; spin_lock_bh(&ap->sta_table_lock); - list_for_each(ptr, &ap->sta_list) { - struct sta_info *sta = list_entry(ptr, struct sta_info, list); + list_for_each_entry(sta, &ap->sta_list, list) { if (sta->ap) hostap_wds_link_oper(local, sta->addr, WDS_ADD); } diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h index c090a5aebb5..30acd39d76a 100644 --- a/drivers/net/wireless/hostap/hostap_config.h +++ b/drivers/net/wireless/hostap/hostap_config.h @@ -1,8 +1,6 @@ #ifndef HOSTAP_CONFIG_H #define HOSTAP_CONFIG_H -#define PRISM2_VERSION "0.4.4-kernel" - /* In the previous versions of Host AP driver, support for user space version * of IEEE 802.11 management (hostapd) used to be disabled in the default * configuration. From now on, support for hostapd is always included and it is diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index ee1532b62e4..30e723f6597 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -22,7 +22,6 @@ #include "hostap_wlan.h" -static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)"; static dev_info_t dev_info = "hostap_cs"; MODULE_AUTHOR("Jouni Malinen"); @@ -30,7 +29,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " "cards (PC Card)."); MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)"); MODULE_LICENSE("GPL"); -MODULE_VERSION(PRISM2_VERSION); static int ignore_cis_vcc; @@ -910,14 +908,12 @@ static struct pcmcia_driver hostap_driver = { static int __init init_prism2_pccard(void) { - printk(KERN_INFO "%s: %s\n", dev_info, version); return pcmcia_register_driver(&hostap_driver); } static void __exit exit_prism2_pccard(void) { pcmcia_unregister_driver(&hostap_driver); - printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index cdea7f71b9e..8c71077d653 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -3893,8 +3893,6 @@ static void prism2_get_drvinfo(struct net_device *dev, local = iface->local; strncpy(info->driver, "hostap", sizeof(info->driver) - 1); - strncpy(info->version, PRISM2_VERSION, - sizeof(info->version) - 1); snprintf(info->fw_version, sizeof(info->fw_version) - 1, "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, (local->sta_fw_ver >> 8) & 0xff, diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 4743426cf6a..446de51bab7 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -37,7 +37,6 @@ MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Host AP common routines"); MODULE_LICENSE("GPL"); -MODULE_VERSION(PRISM2_VERSION); #define TX_TIMEOUT (2 * HZ) diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index db4899ed4bb..7da3664b851 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -20,7 +20,6 @@ #include "hostap_wlan.h" -static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)"; static char *dev_info = "hostap_pci"; @@ -29,7 +28,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " "PCI cards."); MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards"); MODULE_LICENSE("GPL"); -MODULE_VERSION(PRISM2_VERSION); /* struct local_info::hw_priv */ @@ -455,15 +453,11 @@ static struct pci_driver prism2_pci_drv_id = { .suspend = prism2_pci_suspend, .resume = prism2_pci_resume, #endif /* CONFIG_PM */ - /* Linux 2.4.6 added save_state and enable_wake that are not used here - */ }; static int __init init_prism2_pci(void) { - printk(KERN_INFO "%s: %s\n", dev_info, version); - return pci_register_driver(&prism2_pci_drv_id); } @@ -471,7 +465,6 @@ static int __init init_prism2_pci(void) static void __exit exit_prism2_pci(void) { pci_unregister_driver(&prism2_pci_drv_id); - printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index f0fd5ecdb24..040dc3e3641 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -23,7 +23,6 @@ #include "hostap_wlan.h" -static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)"; static char *dev_info = "hostap_plx"; @@ -32,7 +31,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " "cards (PLX)."); MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)"); MODULE_LICENSE("GPL"); -MODULE_VERSION(PRISM2_VERSION); static int ignore_cis; @@ -615,16 +613,11 @@ static struct pci_driver prism2_plx_drv_id = { .id_table = prism2_plx_id_table, .probe = prism2_plx_probe, .remove = prism2_plx_remove, - .suspend = NULL, - .resume = NULL, - .enable_wake = NULL }; static int __init init_prism2_plx(void) { - printk(KERN_INFO "%s: %s\n", dev_info, version); - return pci_register_driver(&prism2_plx_drv_id); } @@ -632,7 +625,6 @@ static int __init init_prism2_plx(void) static void __exit exit_prism2_plx(void) { pci_unregister_driver(&prism2_plx_drv_id); - printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index d51daf87450..8990585bd22 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1768,7 +1768,8 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) if (priv->stop_rf_kill) { priv->stop_rf_kill = 0; - queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies(HZ)); } deferred = 1; @@ -2098,7 +2099,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) /* Make sure the RF Kill check timer is running */ priv->stop_rf_kill = 0; cancel_delayed_work(&priv->rf_kill); - queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); + queue_delayed_work(priv->workqueue, &priv->rf_kill, round_jiffies(HZ)); } static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) @@ -4233,7 +4234,8 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) /* Make sure the RF_KILL check timer is running */ priv->stop_rf_kill = 0; cancel_delayed_work(&priv->rf_kill); - queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies(HZ)); } else schedule_reset(priv); } @@ -5969,7 +5971,8 @@ static void ipw2100_rf_kill(struct work_struct *work) if (rf_kill_active(priv)) { IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); if (!priv->stop_rf_kill) - queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies(HZ)); goto exit_unlock; } @@ -7865,10 +7868,10 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, goto done; } - if ((mode < 1) || (mode > POWER_MODES)) + if ((mode < 0) || (mode > POWER_MODES)) mode = IPW_POWER_AUTO; - if (priv->power_mode != mode) + if (IPW_POWER_LEVEL(priv->power_mode) != mode) err = ipw2100_set_power_mode(priv, mode); done: mutex_unlock(&priv->action_mutex); @@ -7899,7 +7902,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev, break; case IPW_POWER_AUTO: snprintf(extra, MAX_POWER_STRING, - "Power save level: %d (Auto)", 0); + "Power save level: %d (Auto)", level); break; default: timeout = timeout_duration[level - 1] / 1000; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 7cb2052a55a..61497c46746 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -70,7 +70,7 @@ #define VQ #endif -#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ +#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" #define DRV_VERSION IPW2200_VERSION @@ -1751,7 +1751,7 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) /* Make sure the RF_KILL check timer is running */ cancel_delayed_work(&priv->rf_kill); queue_delayed_work(priv->workqueue, &priv->rf_kill, - 2 * HZ); + round_jiffies(2 * HZ)); } else queue_work(priv->workqueue, &priv->up); } @@ -2506,7 +2506,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) break; } - param = cpu_to_le32(mode); + param = cpu_to_le32(param); return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), ¶m); } @@ -4690,7 +4690,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, else if (priv->config & CFG_BACKGROUND_SCAN && priv->status & STATUS_ASSOCIATED) queue_delayed_work(priv->workqueue, - &priv->request_scan, HZ); + &priv->request_scan, + round_jiffies(HZ)); /* Send an empty event to user space. * We don't send the received data on the event because @@ -9567,6 +9568,7 @@ static int ipw_wx_set_power(struct net_device *dev, priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY; else priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; + err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); @@ -9603,22 +9605,19 @@ static int ipw_wx_set_powermode(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; int err; + mutex_lock(&priv->mutex); - if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { + if ((mode < 1) || (mode > IPW_POWER_LIMIT)) mode = IPW_POWER_AC; - priv->power_mode = mode; - } else { - priv->power_mode = IPW_POWER_ENABLED | mode; - } - if (priv->power_mode != mode) { + if (IPW_POWER_LEVEL(priv->power_mode) != mode) { err = ipw_send_power_mode(priv, mode); - if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); mutex_unlock(&priv->mutex); return err; } + priv->power_mode = IPW_POWER_ENABLED | mode; } mutex_unlock(&priv->mutex); return 0; @@ -10554,7 +10553,7 @@ static irqreturn_t ipw_isr(int irq, void *data) spin_lock(&priv->irq_lock); if (!(priv->status & STATUS_INT_ENABLED)) { - /* Shared IRQ */ + /* IRQ is disabled */ goto none; } diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index a1097f59fd4..32ed4136b0d 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -2,7 +2,7 @@ libertas-objs := main.o fw.o wext.o \ rx.o tx.o cmd.o \ cmdresp.o scan.o \ join.o 11d.o \ - ioctl.o debugfs.o \ + debugfs.o \ ethtool.o assoc.o usb8xxx-objs += if_bootcmd.o diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index 1f92f50b643..0b133ce6380 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -28,281 +28,6 @@ DRIVER LOADING insmod usb8388.ko [fw_name=usb8388.bin] -===================== -IWPRIV COMMAND -===================== - -NAME - This manual describes the usage of private commands used in Marvell WLAN - Linux Driver. All the commands available in Wlanconfig will not be available - in the iwpriv. - -SYNOPSIS - iwpriv <ethX> <command> [sub-command] ... - - iwpriv ethX setregioncode <n> - iwpriv ethX getregioncode - -Version 5 Command: - iwpriv ethX ledgpio <n> - -BT Commands: - The blinding table (BT) contains a list of mac addresses that will be, - by default, ignored by the firmware. It is also possible to invert this - behavior so that we will ignore all traffic except for the portion - coming from mac addresess in the list. It is primarily used for - debugging and testing networks. It can be edited and inspected with - the following commands: - - iwpriv ethX bt_reset - iwpriv ethX bt_add <mac_address> - iwpriv ethX bt_del <mac_address> - iwpriv ethX bt_list <id> - iwpriv ethX bt_get_invert <n> - iwpriv ethX bt_set_invert <n> - -FWT Commands: - The forwarding table (FWT) is a feature used to manage mesh network - routing in the firmware. The FWT is essentially a routing table that - associates a destination mac address (da) with a next hop receiver - address (ra). The FWT can be inspected and edited with the following - iwpriv commands, which are described in greater detail below. - Eventually, the table will be automatically maintained by a custom - routing protocol. - - NOTE: FWT commands replace the previous DFT commands. What were the DFT - commands?, you might ask. They were an earlier API to the firmware that - implemented a simple MAC-layer forwarding mechanism. In the unlikely - event that you were using these commands, you must migrate to the new - FWT commands which can be used to achieve the same functionality. - - iwpriv ethX fwt_add [parameters] - iwpriv ethX fwt_del [parameters] - iwpriv ethX fwt_lookup [parameters] - iwpriv ethX fwt_list [parameters] - iwpriv ethX fwt_list_route [parameters] - iwpriv ethX fwt_list_neigh [parameters] - iwpriv ethX fwt_reset [parameters] - iwpriv ethX fwt_cleanup - iwpriv ethX fwt_time - -MESH Commands: - - The MESH commands are used to configure various features of the mesh - routing protocol. The following commands are supported: - - iwpriv ethX mesh_get_ttl - iwpriv ethX mesh_set_ttl ttl - -DESCRIPTION - Those commands are used to send additional commands to the Marvell WLAN - card via the Linux device driver. - - The ethX parameter specifies the network device that is to be used to - perform this command on. it could be eth0, eth1 etc. - -setregioncode - This command is used to set the region code in the station. - where value is 'region code' for various regions like - USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ... - - Usage: - iwpriv ethX setregioncode 0x10: set region code to USA (0x10). - -getregioncode - This command is used to get the region code information set in the - station. - -ledgpio - This command is used to set/get LEDs. - - iwpriv ethX ledgpio <LEDs> - will set the corresponding LED for the GPIO Line. - - iwpriv ethX ledgpio - will give u which LEDs are Enabled. - - Usage: - iwpriv eth1 ledgpio 1 0 2 1 3 4 - will enable - LED 1 -> GPIO 0 - LED 2 -> GPIO 1 - LED 3 -> GPIO 4 - - iwpriv eth1 ledgpio - shows LED information in the format as mentioned above. - - Note: LED0 is invalid - Note: Maximum Number of LEDs are 16. - -fwt_add - This command is used to insert an entry into the FWT table. The list of - parameters must follow the following structure: - - iwpriv ethX fwt_add da ra [metric dir rate ssn dsn hopcount ttl expiration sleepmode snr] - - The parameters between brackets are optional, but they must appear in - the order specified. For example, if you want to specify the metric, - you must also specify the dir, ssn, and dsn but you need not specify the - hopcount, expiration, sleepmode, or snr. Any unspecified parameters - will be assigned the defaults specified below. - - The different parameters are:- - da -- DA MAC address in the form 00:11:22:33:44:55 - ra -- RA MAC address in the form 00:11:22:33:44:55 - metric -- route metric (cost: smaller-metric routes are - preferred, default is 0) - dir -- direction (1 for direct, 0 for reverse, - default is 1) - rate -- data rate used for transmission to the RA, - as specified for the rateadapt command, - default is 3 (11Mbps) - ssn -- Source Sequence Number (time at the RA for - reverse routes. Default is 0) - dsn -- Destination Sequence Number (time at the DA - for direct routes. Default is 0) - hopcount -- hop count (currently unused, default is 0) - ttl -- TTL (Only used in reverse entries) - expiration -- entry expiration (in ticks, where a tick is - 1024us, or ~ 1ms. Use 0 for an indefinite - entry, default is 0) - sleepmode -- RA's sleep mode (currently unused, default is - 0) - snr -- SNR in the link to RA (currently unused, - default is 0) - - The command does not return anything. - -fwt_del - This command is used to remove an entry to the FWT table. The list of - parameters must follow the following structure: - - iwpriv ethX fwt_del da ra [dir] - - where the different parameters are:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - ra -- RA MAC address (in the form "00:11:22:33:44:55") - dir -- direction (1 for direct, 0 for reverse, - default is 1) - - The command does not return anything. - -fwt_lookup - This command is used to get the best route in the FWT table to a given - host. The only parameter is the MAC address of the host that is being - looked for. - - iwpriv ethX fwt_lookup da - - where:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - - The command returns an output string identical to the one returned by - fwt_list described below. - - -fwt_list - This command is used to list a route from the FWT table. The only - parameter is the index into the table. If you want to list all the - routes in a table, start with index=0, and keep listing until you get a - "(null)" string. Note that the indicies may change as the fwt is - updated. It is expected that most users will not use fwt_list directly, - but that a utility similar to the traditional route command will be used - to invoke fwt_list over and over. - - iwpriv ethX fwt_list index - - The output is a string of the following form: - - da ra valid metric dir rate ssn dsn hopcount ttl expiration - sleepmode snr precursor - - where the different fields are:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - ra -- RA MAC address (in the form "00:11:22:33:44:55") - valid -- whether the route is valid (0 if not valid) - metric -- route metric (cost: smaller-metric routes are preferred) - dir -- direction (1 for direct, 0 for reverse) - rate -- data rate used for transmission to the RA, - as specified for the rateadapt command - ssn -- Source Sequence Number (time at the RA for reverse routes) - dsn -- Destination Sequence Number (time at the DA for direct routes) - hopcount -- hop count (currently unused) - ttl -- TTL (only used in reverse entries) - expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) - sleepmode -- RA's sleep mode (currently unused) - snr -- SNR in the link to RA (currently unused) - precursor -- predecessor in direct routes - -fwt_list_route - This command is equivalent to fwt_list. - -fwt_list_neigh - This command is used to list a neighbor from the FWT table. The only - parameter is the neighbor ID. If you want to list all the neighbors in a - table, start with nid=0, and keep incrementing nid until you get a - "(null)" string. Note that the nid from a fwt_list_route command can be - used as an input to this command. Also note that this command is meant - mostly for debugging. It is expected that users will use fwt_lookup. - One important reason for this is that the neighbor id may change as the - neighbor table is altered. - - iwpriv ethX fwt_list_neigh nid - - The output is a string of the following form: - - ra sleepmode snr references - - where the different fields are:- - ra -- RA MAC address (in the form "00:11:22:33:44:55") - sleepmode -- RA's sleep mode (currently unused) - snr -- SNR in the link to RA (currently unused) - references -- RA's reference counter - -fwt_reset - This command is used to reset the FWT table, getting rid of all the - entries. There are no input parameters. - - iwpriv ethX fwt_reset - - The command does not return anything. - -fwt_cleanup - This command is used to perform user-based garbage recollection. The - FWT table is checked, and all the entries that are expired or invalid - are cleaned. Note that this is exported to the driver for debugging - purposes, as garbage collection is also fired by the firmware when in - space problems. There are no input parameters. - - iwpriv ethX fwt_cleanup - - The command does returns the number of invalid/expired routes deleted. - -fwt_time - This command returns a card's internal time representation. It is this - time that is used to represent the expiration times of FWT entries. The - number is not consistent from card to card; it is simply a timer count. - The fwt_time command is used to inspect the timer so that expiration - times reported by fwt_list can be properly interpreted. - - iwpriv ethX fwt_time - -mesh_get_ttl - - The mesh ttl is the number of hops a mesh packet can traverse before it - is dropped. This parameter is used to prevent infinite loops in the - mesh network. The value returned by this function is the ttl assigned - to all mesh packets. Currently there is no way to control the ttl on a - per packet or per socket basis. - - iwpriv ethX mesh_get_ttl - -mesh_set_ttl ttl - - Set the ttl. The argument must be between 0 and 255. - - iwpriv ethX mesh_set_ttl <ttl> - ========================= ETHTOOL ========================= diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index f67efa0815f..afd5617dd92 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -323,6 +323,8 @@ static int assoc_helper_secinfo(wlan_private *priv, { wlan_adapter *adapter = priv->adapter; int ret = 0; + u32 do_wpa; + u32 rsn = 0; lbs_deb_enter(LBS_DEB_ASSOC); @@ -333,12 +335,34 @@ static int assoc_helper_secinfo(wlan_private *priv, if (ret) goto out; - /* enable/disable RSN */ + /* If RSN is already enabled, don't try to enable it again, since + * ENABLE_RSN resets internal state machines and will clobber the + * 4-way WPA handshake. + */ + + /* Get RSN enabled/disabled */ ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn, cmd_act_set, cmd_option_waitforrsp, - 0, assoc_req); + 0, &rsn); + if (ret) { + lbs_deb_assoc("Failed to get RSN status: %d", ret); + goto out; + } + + /* Don't re-enable RSN if it's already enabled */ + do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled); + if (do_wpa == rsn) + goto out; + + /* Set RSN enabled/disabled */ + rsn = do_wpa; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_enable_rsn, + cmd_act_set, + cmd_option_waitforrsp, + 0, &rsn); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 124e029f1bf..4a8f5dc7023 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -228,17 +228,19 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, void * pdata_buf) { struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn; - struct assoc_request * assoc_req = pdata_buf; + u32 * enable = pdata_buf; lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(cmd_802_11_enable_rsn); cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN); penableRSN->action = cpu_to_le16(cmd_action); - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - penableRSN->enable = cpu_to_le16(cmd_enable_rsn); - } else { - penableRSN->enable = cpu_to_le16(cmd_disable_rsn); + + if (cmd_action == cmd_act_set) { + if (*enable) + penableRSN->enable = cpu_to_le16(cmd_enable_rsn); + else + penableRSN->enable = cpu_to_le16(cmd_disable_rsn); } lbs_deb_leave(LBS_DEB_CMD); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 0c3b9a583d8..6ac0d4752fa 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -537,6 +537,24 @@ static int wlan_ret_get_log(wlan_private * priv, return 0; } +static int libertas_ret_802_11_enable_rsn(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn; + wlan_adapter *adapter = priv->adapter; + u32 * pdata_buf = adapter->cur_cmd->pdata_buf; + + lbs_deb_enter(LBS_DEB_CMD); + + if (enable_rsn->action == cpu_to_le16(cmd_act_get)) { + if (pdata_buf) + *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); + } + + lbs_deb_enter(LBS_DEB_CMD); + return 0; +} + static inline int handle_cmd_response(u16 respcmd, struct cmd_ds_command *resp, wlan_private *priv) @@ -610,7 +628,10 @@ static inline int handle_cmd_response(u16 respcmd, case cmd_ret_802_11_authenticate: case cmd_ret_802_11_radio_control: case cmd_ret_802_11_beacon_stop: + break; + case cmd_ret_802_11_enable_rsn: + ret = libertas_ret_802_11_enable_rsn(priv, resp); break; case cmd_ret_802_11_data_rate: diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 3acf9398812..09b898f6719 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -503,7 +503,7 @@ struct cmd_ds_802_11_ad_hoc_join { struct cmd_ds_802_11_enable_rsn { __le16 action; __le16 enable; -}; +} __attribute__ ((packed)); struct MrvlIEtype_keyParamSet { /* type ID */ diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c deleted file mode 100644 index f4108158556..00000000000 --- a/drivers/net/wireless/libertas/ioctl.c +++ /dev/null @@ -1,1081 +0,0 @@ -/** - * This file contains ioctl functions - */ - -#include <linux/ctype.h> -#include <linux/delay.h> -#include <linux/if.h> -#include <linux/if_arp.h> -#include <linux/wireless.h> - -#include <net/iw_handler.h> -#include <net/ieee80211.h> - -#include "host.h" -#include "radiotap.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "join.h" -#include "wext.h" - -#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ - IW_ESSID_MAX_SIZE + \ - IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ - IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ - IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ - -#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) - -static int wlan_set_region(wlan_private * priv, u16 region_code) -{ - int i; - int ret = 0; - - for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { - // use the region code to search for the index - if (region_code == libertas_region_code_to_index[i]) { - priv->adapter->regiontableindex = (u16) i; - priv->adapter->regioncode = region_code; - break; - } - } - - // if it's unidentified region code - if (i >= MRVDRV_MAX_REGION_CODE) { - lbs_deb_ioctl("region Code not identified\n"); - ret = -1; - goto done; - } - - if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { - ret = -EINVAL; - } - -done: - lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); - return ret; -} - -static inline int hex2int(char c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - if (c >= 'A' && c <= 'F') - return (c - 'A' + 10); - return -1; -} - -/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") - into binary format (6 bytes). - - This function expects that each byte is represented with 2 characters - (e.g., 11:2:11:11:11:11 is invalid) - - */ -static char *eth_str2addr(char *ethstr, u8 * addr) -{ - int i, val, val2; - char *pos = ethstr; - - /* get rid of initial blanks */ - while (*pos == ' ' || *pos == '\t') - ++pos; - - for (i = 0; i < 6; i++) { - val = hex2int(*pos++); - if (val < 0) - return NULL; - val2 = hex2int(*pos++); - if (val2 < 0) - return NULL; - addr[i] = (val * 16 + val2) & 0xff; - - if (i < 5 && *pos++ != ':') - return NULL; - } - return pos; -} - -/* this writes xx:xx:xx:xx:xx:xx into ethstr - (ethstr must have space for 18 chars) */ -static int eth_addr2str(u8 * addr, char *ethstr) -{ - int i; - char *pos = ethstr; - - for (i = 0; i < 6; i++) { - sprintf(pos, "%02x", addr[i] & 0xff); - pos += 2; - if (i < 5) - *pos++ = ':'; - } - return 17; -} - -/** - * @brief Add an entry to the BT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char ethaddrs_str[18]; - char *pos; - u8 ethaddr[ETH_ALEN]; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, - sizeof(ethaddrs_str))) - return -EFAULT; - - if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { - lbs_pr_info("BT_ADD: Invalid MAC address\n"); - return -EINVAL; - } - - lbs_deb_ioctl("BT: adding %s\n", ethaddrs_str); - ret = libertas_prepare_and_send_command(priv, cmd_bt_access, - cmd_act_bt_access_add, - cmd_option_waitforrsp, 0, ethaddr); - lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); - return ret; -} - -/** - * @brief Delete an entry from the BT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char ethaddrs_str[18]; - u8 ethaddr[ETH_ALEN]; - char *pos; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, - sizeof(ethaddrs_str))) - return -EFAULT; - - if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { - lbs_pr_info("Invalid MAC address\n"); - return -EINVAL; - } - - lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str); - - return (libertas_prepare_and_send_command(priv, - cmd_bt_access, - cmd_act_bt_access_del, - cmd_option_waitforrsp, 0, ethaddr)); - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Reset all entries from the BT table - * @param priv A pointer to wlan_private structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_reset_ioctl(wlan_private * priv) -{ - lbs_deb_enter(LBS_DEB_IOCTL); - - lbs_pr_alert( "BT: resetting\n"); - - return (libertas_prepare_and_send_command(priv, - cmd_bt_access, - cmd_act_bt_access_reset, - cmd_option_waitforrsp, 0, NULL)); - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief List an entry from the BT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) -{ - int pos; - char *addr1; - struct iwreq *wrq = (struct iwreq *)req; - /* used to pass id and store the bt entry returned by the FW */ - union { - u32 id; - char addr1addr2[2 * ETH_ALEN]; - } param; - static char outstr[64]; - char *pbuf = outstr; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { - lbs_deb_ioctl("Copy from user failed\n"); - return -1; - } - param.id = simple_strtoul(outstr, NULL, 10); - pos = sprintf(pbuf, "%d: ", param.id); - pbuf += pos; - - ret = libertas_prepare_and_send_command(priv, cmd_bt_access, - cmd_act_bt_access_list, - cmd_option_waitforrsp, 0, - (char *)¶m); - - if (ret == 0) { - addr1 = param.addr1addr2; - - pos = sprintf(pbuf, "BT includes node "); - pbuf += pos; - pos = eth_addr2str(addr1, pbuf); - pbuf += pos; - } else { - sprintf(pbuf, "(null)"); - pbuf += pos; - } - - wrq->u.data.length = strlen(outstr); - if (copy_to_user(wrq->u.data.pointer, (char *)outstr, - wrq->u.data.length)) { - lbs_deb_ioctl("BT_LIST: Copy to user failed!\n"); - return -EFAULT; - } - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0 ; -} - -/** - * @brief Sets inverted state of blacklist (non-zero if inverted) - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_set_invert_ioctl(wlan_private * priv, struct ifreq *req) -{ - int ret; - struct iwreq *wrq = (struct iwreq *)req; - union { - u32 id; - char addr1addr2[2 * ETH_ALEN]; - } param; - - lbs_deb_enter(LBS_DEB_IOCTL); - - param.id = SUBCMD_DATA(wrq) ; - ret = libertas_prepare_and_send_command(priv, cmd_bt_access, - cmd_act_bt_access_set_invert, - cmd_option_waitforrsp, 0, - (char *)¶m); - if (ret != 0) - return -EFAULT; - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Gets inverted state of blacklist (non-zero if inverted) - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_get_invert_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - int ret; - union { - u32 id; - char addr1addr2[2 * ETH_ALEN]; - } param; - - lbs_deb_enter(LBS_DEB_IOCTL); - - ret = libertas_prepare_and_send_command(priv, cmd_bt_access, - cmd_act_bt_access_get_invert, - cmd_option_waitforrsp, 0, - (char *)¶m); - - if (ret == 0) - wrq->u.param.value = le32_to_cpu(param.id); - else - return -EFAULT; - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Find the next parameter in an input string - * @param ptr A pointer to the input parameter string - * @return A pointer to the next parameter, or 0 if no parameters left. - */ -static char * next_param(char * ptr) -{ - if (!ptr) return NULL; - while (*ptr == ' ' || *ptr == '\t') ++ptr; - return (*ptr == '\0') ? NULL : ptr; -} - -/** - * @brief Add an entry to the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[128]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { - lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); - return -EINVAL; - } - - if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { - lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); - return -EINVAL; - } - - if ((ptr = next_param(ptr))) - fwt_access.metric = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.metric = cpu_to_le32(FWT_DEFAULT_METRIC); - - if ((ptr = next_param(ptr))) - fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); - else - fwt_access.dir = FWT_DEFAULT_DIR; - - if ((ptr = next_param(ptr))) - fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10); - else - fwt_access.rate = FWT_DEFAULT_RATE; - - if ((ptr = next_param(ptr))) - fwt_access.ssn = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.ssn = cpu_to_le32(FWT_DEFAULT_SSN); - - if ((ptr = next_param(ptr))) - fwt_access.dsn = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.dsn = cpu_to_le32(FWT_DEFAULT_DSN); - - if ((ptr = next_param(ptr))) - fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); - else - fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; - - if ((ptr = next_param(ptr))) - fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); - else - fwt_access.ttl = FWT_DEFAULT_TTL; - - if ((ptr = next_param(ptr))) - fwt_access.expiration = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.expiration = cpu_to_le32(FWT_DEFAULT_EXPIRATION); - - if ((ptr = next_param(ptr))) - fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); - else - fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; - - if ((ptr = next_param(ptr))) - fwt_access.snr = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.snr = cpu_to_le32(FWT_DEFAULT_SNR); - -#ifdef DEBUG - { - char ethaddr1_str[18], ethaddr2_str[18]; - eth_addr2str(fwt_access.da, ethaddr1_str); - eth_addr2str(fwt_access.ra, ethaddr2_str); - lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, - fwt_access.dir, ethaddr2_str); - lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", - fwt_access.ssn, fwt_access.dsn, fwt_access.metric, - fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, - fwt_access.sleepmode, fwt_access.snr); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_add, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); - return ret; -} - -/** - * @brief Delete an entry from the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[64]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { - lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); - return -EINVAL; - } - - if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { - lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); - return -EINVAL; - } - - if ((ptr = next_param(ptr))) - fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); - else - fwt_access.dir = FWT_DEFAULT_DIR; - -#ifdef DEBUG - { - char ethaddr1_str[18], ethaddr2_str[18]; - lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str); - eth_addr2str(fwt_access.da, ethaddr1_str); - eth_addr2str(fwt_access.ra, ethaddr2_str); - lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, - ethaddr2_str, fwt_access.dir); - } -#endif - - ret = libertas_prepare_and_send_command(priv, - cmd_fwt_access, - cmd_act_fwt_access_del, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); - return ret; -} - - -/** - * @brief Print route parameters - * @param fwt_access struct cmd_ds_fwt_access with route info - * @param buf destination buffer for route info - */ -static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) -{ - buf += sprintf(buf, " "); - buf += eth_addr2str(fwt_access.da, buf); - buf += sprintf(buf, " "); - buf += eth_addr2str(fwt_access.ra, buf); - buf += sprintf(buf, " %u", fwt_access.valid); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); - buf += sprintf(buf, " %u", fwt_access.dir); - buf += sprintf(buf, " %u", fwt_access.rate); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); - buf += sprintf(buf, " %u", fwt_access.hopcount); - buf += sprintf(buf, " %u", fwt_access.ttl); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); - buf += sprintf(buf, " %u", fwt_access.sleepmode); - buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr)); - buf += eth_addr2str(fwt_access.prec, buf); -} - -/** - * @brief Lookup an entry in the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[64]; - char *ptr; - static struct cmd_ds_fwt_access fwt_access; - static char out_str[128]; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { - lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); - return -EINVAL; - } - -#ifdef DEBUG - { - char ethaddr1_str[18]; - lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str); - eth_addr2str(fwt_access.da, ethaddr1_str); - lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); - } -#endif - - ret = libertas_prepare_and_send_command(priv, - cmd_fwt_access, - cmd_act_fwt_access_lookup, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) - print_route(fwt_access, out_str); - else - sprintf(out_str, "(null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n"); - return -EFAULT; - } - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Reset all entries from the FWT table - * @param priv A pointer to wlan_private structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_reset_ioctl(wlan_private * priv) -{ - lbs_deb_ioctl("FWT: resetting\n"); - - return (libertas_prepare_and_send_command(priv, - cmd_fwt_access, - cmd_act_fwt_access_reset, - cmd_option_waitforrsp, 0, NULL)); -} - -/** - * @brief List an entry from the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[8]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr = in_str; - static char out_str[128]; - char *pbuf = out_str; - int ret = 0; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) { - ret = -EFAULT; - goto out; - } - - fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - -#ifdef DEBUG - { - lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str); - lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_list, - cmd_option_waitforrsp, 0, (void *)&fwt_access); - - if (ret == 0) - print_route(fwt_access, pbuf); - else - pbuf += sprintf(pbuf, " (null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n"); - ret = -EFAULT; - goto out; - } - - ret = 0; - -out: - lbs_deb_leave(LBS_DEB_IOCTL); - return ret; -} - -/** - * @brief List an entry from the FRT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[64]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr = in_str; - static char out_str[128]; - char *pbuf = out_str; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - -#ifdef DEBUG - { - lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str); - lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_list_route, - cmd_option_waitforrsp, 0, (void *)&fwt_access); - - if (ret == 0) { - print_route(fwt_access, pbuf); - } else - pbuf += sprintf(pbuf, " (null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n"); - return -EFAULT; - } - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief List an entry from the FNT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[8]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr = in_str; - static char out_str[128]; - char *pbuf = out_str; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - memset(&fwt_access, 0, sizeof(fwt_access)); - fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - -#ifdef DEBUG - { - lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str); - lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_list_neighbor, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) { - pbuf += sprintf(pbuf, " ra "); - pbuf += eth_addr2str(fwt_access.ra, pbuf); - pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); - pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); - pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); - } else - pbuf += sprintf(pbuf, " (null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n"); - return -EFAULT; - } - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Cleans up the route (FRT) and neighbor (FNT) tables - * (Garbage Collection) - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - static struct cmd_ds_fwt_access fwt_access; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - lbs_deb_ioctl("FWT: cleaning up\n"); - - memset(&fwt_access, 0, sizeof(fwt_access)); - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_cleanup, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) - wrq->u.param.value = le32_to_cpu(fwt_access.references); - else - return -EFAULT; - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Gets firmware internal time (debug purposes) - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - static struct cmd_ds_fwt_access fwt_access; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - lbs_deb_ioctl("FWT: getting time\n"); - - memset(&fwt_access, 0, sizeof(fwt_access)); - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_time, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) - wrq->u.param.value = le32_to_cpu(fwt_access.references); - else - return -EFAULT; - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Gets mesh ttl from firmware - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - struct cmd_ds_mesh_access mesh_access; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - memset(&mesh_access, 0, sizeof(mesh_access)); - - ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, - cmd_act_mesh_get_ttl, - cmd_option_waitforrsp, 0, - (void *)&mesh_access); - - if (ret == 0) - wrq->u.param.value = le32_to_cpu(mesh_access.data[0]); - else - return -EFAULT; - - lbs_deb_leave(LBS_DEB_IOCTL); - return 0; -} - -/** - * @brief Gets mesh ttl from firmware - * @param priv A pointer to wlan_private structure - * @param ttl New ttl value - * @return 0 --success, otherwise fail - */ -static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl) -{ - struct cmd_ds_mesh_access mesh_access; - int ret; - - lbs_deb_enter(LBS_DEB_IOCTL); - - if( (ttl > 0xff) || (ttl < 0) ) - return -EINVAL; - - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = cpu_to_le32(ttl); - - ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, - cmd_act_mesh_set_ttl, - cmd_option_waitforrsp, 0, - (void *)&mesh_access); - - if (ret != 0) - ret = -EFAULT; - - lbs_deb_leave(LBS_DEB_IOCTL); - return ret; -} - -/** - * @brief ioctl function - entry point - * - * @param dev A pointer to net_device structure - * @param req A pointer to ifreq structure - * @param cmd command - * @return 0--success, otherwise fail - */ -int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - int subcmd = 0; - int idata = 0; - int *pdata; - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct iwreq *wrq = (struct iwreq *)req; - - lbs_deb_enter(LBS_DEB_IOCTL); - - lbs_deb_ioctl("libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); - switch (cmd) { - case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ - switch (wrq->u.data.flags) { - case WLAN_SUBCMD_BT_RESET: /* bt_reset */ - wlan_bt_reset_ioctl(priv); - break; - case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */ - wlan_fwt_reset_ioctl(priv); - break; - } /* End of switch */ - break; - - case WLAN_SETONEINT_GETNONE: - /* The first 4 bytes of req->ifr_data is sub-ioctl number - * after 4 bytes sits the payload. - */ - subcmd = wrq->u.data.flags; - if (!subcmd) - subcmd = (int)wrq->u.param.value; - - switch (subcmd) { - case WLANSETREGION: - idata = SUBCMD_DATA(wrq); - ret = wlan_set_region(priv, (u16) idata); - break; - case WLAN_SUBCMD_MESH_SET_TTL: - idata = SUBCMD_DATA(wrq); - ret = wlan_mesh_set_ttl_ioctl(priv, idata); - break; - - case WLAN_SUBCMD_BT_SET_INVERT: - ret = wlan_bt_set_invert_ioctl(priv, req); - break ; - - default: - ret = -EOPNOTSUPP; - break; - } - - break; - - case WLAN_SET128CHAR_GET128CHAR: - switch ((int)wrq->u.data.flags) { - case WLAN_SUBCMD_BT_ADD: - ret = wlan_bt_add_ioctl(priv, req); - break; - case WLAN_SUBCMD_BT_DEL: - ret = wlan_bt_del_ioctl(priv, req); - break; - case WLAN_SUBCMD_BT_LIST: - ret = wlan_bt_list_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_ADD: - ret = wlan_fwt_add_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_DEL: - ret = wlan_fwt_del_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LOOKUP: - ret = wlan_fwt_lookup_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LIST_NEIGHBOR: - ret = wlan_fwt_list_neighbor_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LIST: - ret = wlan_fwt_list_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LIST_ROUTE: - ret = wlan_fwt_list_route_ioctl(priv, req); - break; - } - break; - - case WLAN_SETNONE_GETONEINT: - switch (wrq->u.param.value) { - case WLANGETREGION: - pdata = (int *)wrq->u.name; - *pdata = (int)adapter->regioncode; - break; - case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */ - ret = wlan_fwt_cleanup_ioctl(priv, req); - break; - - case WLAN_SUBCMD_FWT_TIME: /* fwt_time */ - ret = wlan_fwt_time_ioctl(priv, req); - break; - - case WLAN_SUBCMD_MESH_GET_TTL: - ret = wlan_mesh_get_ttl_ioctl(priv, req); - break; - - case WLAN_SUBCMD_BT_GET_INVERT: - ret = wlan_bt_get_invert_ioctl(priv, req); - break ; - - default: - ret = -EOPNOTSUPP; - - } - - break; - - case WLAN_SET_GET_SIXTEEN_INT: - switch ((int)wrq->u.data.flags) { - case WLAN_LED_GPIO_CTRL: - { - int i; - int data[16]; - - struct cmd_ds_802_11_led_ctrl ctrl; - struct mrvlietypes_ledgpio *gpio = - (struct mrvlietypes_ledgpio *) ctrl.data; - - memset(&ctrl, 0, sizeof(ctrl)); - if (wrq->u.data.length > MAX_LEDS * 2) - return -ENOTSUPP; - if ((wrq->u.data.length % 2) != 0) - return -ENOTSUPP; - if (wrq->u.data.length == 0) { - ctrl.action = - cpu_to_le16 - (cmd_act_get); - } else { - if (copy_from_user - (data, wrq->u.data.pointer, - sizeof(int) * - wrq->u.data.length)) { - lbs_deb_ioctl( - "Copy from user failed\n"); - return -EFAULT; - } - - ctrl.action = - cpu_to_le16 - (cmd_act_set); - ctrl.numled = cpu_to_le16(0); - gpio->header.type = - cpu_to_le16(TLV_TYPE_LED_GPIO); - gpio->header.len = wrq->u.data.length; - for (i = 0; i < wrq->u.data.length; - i += 2) { - gpio->ledpin[i / 2].led = - data[i]; - gpio->ledpin[i / 2].pin = - data[i + 1]; - } - } - ret = - libertas_prepare_and_send_command(priv, - cmd_802_11_led_gpio_ctrl, - 0, - cmd_option_waitforrsp, - 0, (void *)&ctrl); - for (i = 0; i < gpio->header.len; i += 2) { - data[i] = gpio->ledpin[i / 2].led; - data[i + 1] = gpio->ledpin[i / 2].pin; - } - if (copy_to_user(wrq->u.data.pointer, data, - sizeof(int) * - gpio->header.len)) { - lbs_deb_ioctl("Copy to user failed\n"); - return -EFAULT; - } - - wrq->u.data.length = gpio->header.len; - } - break; - } - break; - - default: - ret = -EINVAL; - break; - } - - lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); - return ret; -} - - diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 623ab4b1697..9f366242c39 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -181,7 +181,8 @@ u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = * @brief Get function for sysfs attribute anycast_mask */ static ssize_t libertas_anycast_get(struct device * dev, - struct device_attribute *attr, char * buf) { + struct device_attribute *attr, char * buf) +{ struct cmd_ds_mesh_access mesh_access; memset(&mesh_access, 0, sizeof(mesh_access)); @@ -197,7 +198,8 @@ static ssize_t libertas_anycast_get(struct device * dev, * @brief Set function for sysfs attribute anycast_mask */ static ssize_t libertas_anycast_set(struct device * dev, - struct device_attribute *attr, const char * buf, size_t count) { + struct device_attribute *attr, const char * buf, size_t count) +{ struct cmd_ds_mesh_access mesh_access; uint32_t datum; @@ -611,6 +613,7 @@ static int wlan_service_main_thread(void *data) init_waitqueue_entry(&wait, current); + set_freezable(); for (;;) { lbs_deb_thread( "main-thread 111: intcounter=%d " "currenttxskb=%p dnld_sent=%d\n", @@ -799,7 +802,6 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) dev->open = wlan_open; dev->hard_start_xmit = wlan_pre_start_xmit; dev->stop = wlan_close; - dev->do_ioctl = libertas_do_ioctl; dev->set_mac_address = wlan_set_mac_address; dev->tx_timeout = wlan_tx_timeout; dev->get_stats = wlan_get_stats; @@ -918,7 +920,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) mesh_dev->open = mesh_open; mesh_dev->hard_start_xmit = mesh_pre_start_xmit; mesh_dev->stop = mesh_close; - mesh_dev->do_ioctl = libertas_do_ioctl; mesh_dev->get_stats = wlan_get_stats; mesh_dev->set_mac_address = wlan_set_mac_address; mesh_dev->ethtool_ops = &libertas_ethtool_ops; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 88d9d2d787d..769c86fb950 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -439,7 +439,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) ret = 0; done: - skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 606af50fa09..c3043dcb541 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -215,38 +215,6 @@ done: } /** - * @brief Post process the scan table after a new scan command has completed - * - * Inspect each entry of the scan table and try to find an entry that - * matches our current associated/joined network from the scan. If - * one is found, update the stored copy of the bssdescriptor for our - * current network. - * - * Debug dump the current scan table contents if compiled accordingly. - * - * @param priv A pointer to wlan_private structure - * - * @return void - */ -static void wlan_scan_process_results(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - struct bss_descriptor * iter_bss; - int i = 0; - - if (adapter->connect_status == libertas_connected) - return; - - mutex_lock(&adapter->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { - lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n", - i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi, - escape_essid(iter_bss->ssid, iter_bss->ssid_len)); - } - mutex_unlock(&adapter->lock); -} - -/** * @brief Create a channel list for the driver to scan based on region info * * Use the driver region/band information to construct a comprehensive list @@ -791,6 +759,10 @@ int wlan_scan_networks(wlan_private * priv, u8 scancurrentchanonly; int maxchanperscan; int ret; +#ifdef CONFIG_LIBERTAS_DEBUG + struct bss_descriptor * iter_bss; + int i = 0; +#endif lbs_deb_enter(LBS_DEB_ASSOC); @@ -832,11 +804,16 @@ int wlan_scan_networks(wlan_private * priv, puserscanin, full_scan); - /* Process the resulting scan table: - * - Remove any bad ssids - * - Update our current BSS information from scan data - */ - wlan_scan_process_results(priv); +#ifdef CONFIG_LIBERTAS_DEBUG + /* Dump the scan table */ + mutex_lock(&adapter->lock); + list_for_each_entry (iter_bss, &adapter->network_list, list) { + lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n", + i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi, + escape_essid(iter_bss->ssid, iter_bss->ssid_len)); + } + mutex_unlock(&adapter->lock); +#endif if (priv->adapter->connect_status == libertas_connected) { netif_carrier_on(priv->dev); diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h deleted file mode 100644 index 8b137891791..00000000000 --- a/drivers/net/wireless/libertas/version.h +++ /dev/null @@ -1 +0,0 @@ - diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8939251a2f4..2fcc3bf2108 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -913,148 +913,6 @@ out: return 0; } -/* - * iwpriv settable callbacks - */ - -static const iw_handler wlan_private_handler[] = { - NULL, /* SIOCIWFIRSTPRIV */ -}; - -static const struct iw_priv_args wlan_private_args[] = { - /* - * { cmd, set_args, get_args, name } - */ - /* Using iwpriv sub-command feature */ - { - WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */ - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - ""}, - { - WLANSETREGION, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setregioncode"}, - { - WLAN_SUBCMD_MESH_SET_TTL, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "mesh_set_ttl"}, - { - WLAN_SETNONE_GETONEINT, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - ""}, - { - WLANGETREGION, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getregioncode"}, - { - WLAN_SUBCMD_FWT_CLEANUP, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "fwt_cleanup"}, - { - WLAN_SUBCMD_FWT_TIME, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "fwt_time"}, - { - WLAN_SUBCMD_MESH_GET_TTL, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "mesh_get_ttl"}, - { - WLAN_SETNONE_GETNONE, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - ""}, - { - WLAN_SUBCMD_FWT_RESET, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "fwt_reset"}, - { - WLAN_SUBCMD_BT_RESET, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "bt_reset"}, - { - WLAN_SET128CHAR_GET128CHAR, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - ""}, - /* BT Management */ - { - WLAN_SUBCMD_BT_ADD, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "bt_add"}, - { - WLAN_SUBCMD_BT_DEL, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "bt_del"}, - { - WLAN_SUBCMD_BT_LIST, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "bt_list"}, - { - WLAN_SUBCMD_BT_SET_INVERT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "bt_set_invert"}, - { - WLAN_SUBCMD_BT_GET_INVERT, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "bt_get_invert"}, - /* FWT Management */ - { - WLAN_SUBCMD_FWT_ADD, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_add"}, - { - WLAN_SUBCMD_FWT_DEL, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_del"}, - { - WLAN_SUBCMD_FWT_LOOKUP, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_lookup"}, - { - WLAN_SUBCMD_FWT_LIST_NEIGHBOR, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_list_neigh"}, - { - WLAN_SUBCMD_FWT_LIST, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_list"}, - { - WLAN_SUBCMD_FWT_LIST_ROUTE, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_list_route"}, - { - WLAN_SET_GET_SIXTEEN_INT, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - ""}, - { - WLAN_LED_GPIO_CTRL, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "ledgpio"}, -}; - static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) { enum { @@ -1861,9 +1719,6 @@ static int wlan_set_encodeext(struct net_device *dev, pkey->type = KEY_TYPE_ID_TKIP; } else if (alg == IW_ENCODE_ALG_CCMP) { pkey->type = KEY_TYPE_ID_AES; - } else { - ret = -EINVAL; - goto out; } /* If WPA isn't enabled yet, do that now */ @@ -2444,22 +2299,12 @@ static const iw_handler mesh_wlan_handler[] = { }; struct iw_handler_def libertas_handler_def = { .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), - .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(wlan_private_args) / - sizeof(struct iw_priv_args), .standard = (iw_handler *) wlan_handler, - .private = (iw_handler *) wlan_private_handler, - .private_args = (struct iw_priv_args *)wlan_private_args, .get_wireless_stats = wlan_get_wireless_stats, }; struct iw_handler_def mesh_handler_def = { .num_standard = sizeof(mesh_wlan_handler) / sizeof(iw_handler), - .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(wlan_private_args) / - sizeof(struct iw_priv_args), .standard = (iw_handler *) mesh_wlan_handler, - .private = (iw_handler *) wlan_private_handler, - .private_args = (struct iw_priv_args *)wlan_private_args, .get_wireless_stats = wlan_get_wireless_stats, }; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index d555056b25b..3d5196c9553 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -7,45 +7,6 @@ #define SUBCMD_OFFSET 4 #define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) -/** PRIVATE CMD ID */ -#define WLANIOCTL SIOCIWFIRSTPRIV - -#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8) -#define WLAN_SUBCMD_BT_RESET 13 -#define WLAN_SUBCMD_FWT_RESET 14 - -#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15) -#define WLANGETREGION 1 - -#define WLAN_SUBCMD_FWT_CLEANUP 15 -#define WLAN_SUBCMD_FWT_TIME 16 -#define WLAN_SUBCMD_MESH_GET_TTL 17 -#define WLAN_SUBCMD_BT_GET_INVERT 18 - -#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24) -#define WLANSETREGION 8 -#define WLAN_SUBCMD_MESH_SET_TTL 18 -#define WLAN_SUBCMD_BT_SET_INVERT 19 - -#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25) -#define WLAN_SUBCMD_BT_ADD 18 -#define WLAN_SUBCMD_BT_DEL 19 -#define WLAN_SUBCMD_BT_LIST 20 -#define WLAN_SUBCMD_FWT_ADD 21 -#define WLAN_SUBCMD_FWT_DEL 22 -#define WLAN_SUBCMD_FWT_LOOKUP 23 -#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24 -#define WLAN_SUBCMD_FWT_LIST 25 -#define WLAN_SUBCMD_FWT_LIST_ROUTE 26 - -#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29) -#define WLAN_LED_GPIO_CTRL 5 - -#define WLAN_LINKMODE_802_3 0 -#define WLAN_LINKMODE_802_11 2 -#define WLAN_RADIOMODE_NONE 0 -#define WLAN_RADIOMODE_RADIOTAP 2 - /** wlan_ioctl_regrdwr */ struct wlan_ioctl_regrdwr { /** Which register to access */ @@ -57,9 +18,13 @@ struct wlan_ioctl_regrdwr { u32 value; }; +#define WLAN_LINKMODE_802_3 0 +#define WLAN_LINKMODE_802_11 2 +#define WLAN_RADIOMODE_NONE 0 +#define WLAN_RADIOMODE_RADIOTAP 2 + extern struct iw_handler_def libertas_handler_def; extern struct iw_handler_def mesh_handler_def; -int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i); int wlan_radio_ioctl(wlan_private * priv, u8 option); #endif /* _WLAN_WEXT_H_ */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 283be4a7052..585f5996d29 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -1853,7 +1853,6 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, islpci_private *priv = netdev_priv(ndev); struct islpci_acl *acl = &priv->acl; struct mac_entry *entry; - struct list_head *ptr; struct sockaddr *addr = (struct sockaddr *) extra; if (addr->sa_family != ARPHRD_ETHER) @@ -1861,11 +1860,9 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, if (down_interruptible(&acl->sem)) return -ERESTARTSYS; - for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, _list); - + list_for_each_entry(entry, &acl->mac_list, _list) { if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { - list_del(ptr); + list_del(&entry->_list); acl->size--; kfree(entry); up(&acl->sem); @@ -1883,7 +1880,6 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, islpci_private *priv = netdev_priv(ndev); struct islpci_acl *acl = &priv->acl; struct mac_entry *entry; - struct list_head *ptr; struct sockaddr *dst = (struct sockaddr *) extra; dwrq->length = 0; @@ -1891,9 +1887,7 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, if (down_interruptible(&acl->sem)) return -ERESTARTSYS; - for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, _list); - + list_for_each_entry(entry, &acl->mac_list, _list) { memcpy(dst->sa_data, entry->addr, ETH_ALEN); dst->sa_family = ARPHRD_ETHER; dwrq->length++; @@ -1960,7 +1954,6 @@ prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, static int prism54_mac_accept(struct islpci_acl *acl, char *mac) { - struct list_head *ptr; struct mac_entry *entry; int res = 0; @@ -1972,8 +1965,7 @@ prism54_mac_accept(struct islpci_acl *acl, char *mac) return 1; } - for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { - entry = list_entry(ptr, struct mac_entry, _list); + list_for_each_entry(entry, &acl->mac_list, _list) { if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { res = 1; break; @@ -2216,11 +2208,9 @@ prism54_wpa_bss_ie_init(islpci_private *priv) void prism54_wpa_bss_ie_clean(islpci_private *priv) { - struct list_head *ptr, *n; + struct islpci_bss_wpa_ie *bss, *n; - list_for_each_safe(ptr, n, &priv->bss_wpa_list) { - struct islpci_bss_wpa_ie *bss; - bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) { kfree(bss); } } diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 3dcb13bb7d5..af2e4f2405f 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -87,7 +87,6 @@ static struct pci_driver prism54_driver = { .remove = prism54_remove, .suspend = prism54_suspend, .resume = prism54_resume, - /* .enable_wake ; we don't support this yet */ }; /****************************************************************************** @@ -167,8 +166,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); /* enable MWI */ - if (!pci_set_mwi(pdev)) - printk(KERN_INFO "%s: pci_set_mwi(pdev) succeeded\n", DRV_NAME); + pci_try_set_mwi(pdev); /* setup the network device interface and its structure */ if (!(ndev = islpci_setup(pdev))) { diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h new file mode 100644 index 00000000000..6124e467b15 --- /dev/null +++ b/drivers/net/wireless/rtl8187.h @@ -0,0 +1,145 @@ +/* + * Definitions for RTL8187 hardware + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL8187_H +#define RTL8187_H + +#include "rtl818x.h" + +#define RTL8187_EEPROM_TXPWR_BASE 0x05 +#define RTL8187_EEPROM_MAC_ADDR 0x07 +#define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */ +#define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */ +#define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */ + +#define RTL8187_REQT_READ 0xC0 +#define RTL8187_REQT_WRITE 0x40 +#define RTL8187_REQ_GET_REG 0x05 +#define RTL8187_REQ_SET_REG 0x05 + +#define RTL8187_MAX_RX 0x9C4 + +struct rtl8187_rx_info { + struct urb *urb; + struct ieee80211_hw *dev; +}; + +struct rtl8187_rx_hdr { + __le16 len; + __le16 rate; + u8 noise; + u8 signal; + u8 agc; + u8 reserved; + __le64 mac_time; +} __attribute__((packed)); + +struct rtl8187_tx_info { + struct ieee80211_tx_control *control; + struct urb *urb; + struct ieee80211_hw *dev; +}; + +struct rtl8187_tx_hdr { + __le32 flags; +#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) +#define RTL8187_TX_FLAG_MORE_FRAG (1 << 17) +#define RTL8187_TX_FLAG_CTS (1 << 18) +#define RTL8187_TX_FLAG_RTS (1 << 23) + __le16 rts_duration; + __le16 len; + __le32 retry; +} __attribute__((packed)); + +struct rtl8187_priv { + /* common between rtl818x drivers */ + struct rtl818x_csr *map; + void (*rf_init)(struct ieee80211_hw *); + int mode; + + /* rtl8187 specific */ + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_hw_mode modes[2]; + struct usb_device *udev; + u8 *hwaddr; + u16 txpwr_base; + u8 asic_rev; + struct sk_buff_head rx_queue; +}; + +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); + +static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) +{ + u8 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + + return val; +} + +static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) +{ + __le16 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + + return le16_to_cpu(val); +} + +static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) +{ + __le32 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); + + return le32_to_cpu(val); +} + +static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, + u8 *addr, u8 val) +{ + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, 0, &val, sizeof(val), HZ / 2); +} + +static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, + __le16 *addr, u16 val) +{ + __le16 buf = cpu_to_le16(val); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2); +} + +static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, + __le32 *addr, u32 val) +{ + __le32 buf = cpu_to_le32(val); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2); +} + +#endif /* RTL8187_H */ diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c new file mode 100644 index 00000000000..cea85894b7f --- /dev/null +++ b/drivers/net/wireless/rtl8187_dev.c @@ -0,0 +1,731 @@ +/* + * Linux device driver for RTL8187 + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * Magic delays and register offsets below are taken from the original + * r8187 driver sources. Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/eeprom_93cx6.h> +#include <net/mac80211.h> + +#include "rtl8187.h" +#include "rtl8187_rtl8225.h" + +MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); +MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>"); +MODULE_DESCRIPTION("RTL8187 USB wireless driver"); +MODULE_LICENSE("GPL"); + +static struct usb_device_id rtl8187_table[] __devinitdata = { + /* Realtek */ + {USB_DEVICE(0x0bda, 0x8187)}, + /* Netgear */ + {USB_DEVICE(0x0846, 0x6100)}, + {USB_DEVICE(0x0846, 0x6a00)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, rtl8187_table); + +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8187_priv *priv = dev->priv; + + data <<= 8; + data |= addr | 0x80; + + rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); + + msleep(1); +} + +static void rtl8187_tx_cb(struct urb *urb) +{ + struct ieee80211_tx_status status = { {0} }; + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; + + usb_free_urb(info->urb); + if (info->control) + memcpy(&status.control, info->control, sizeof(status.control)); + kfree(info->control); + skb_pull(skb, sizeof(struct rtl8187_tx_hdr)); + status.flags |= IEEE80211_TX_STATUS_ACK; + ieee80211_tx_status_irqsafe(info->dev, skb, &status); +} + +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rtl8187_priv *priv = dev->priv; + struct rtl8187_tx_hdr *hdr; + struct rtl8187_tx_info *info; + struct urb *urb; + u32 tmp; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree_skb(skb); + return 0; + } + + hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); + tmp = skb->len - sizeof(*hdr); + tmp |= RTL8187_TX_FLAG_NO_ENCRYPT; + tmp |= control->rts_cts_rate << 19; + tmp |= control->tx_rate << 24; + if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb)) + tmp |= RTL8187_TX_FLAG_MORE_FRAG; + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tmp |= RTL8187_TX_FLAG_RTS; + hdr->rts_duration = + ieee80211_rts_duration(dev, skb->len, control); + } + if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + tmp |= RTL8187_TX_FLAG_CTS; + hdr->flags = cpu_to_le32(tmp); + hdr->len = 0; + tmp = control->retry_limit << 8; + hdr->retry = cpu_to_le32(tmp); + + info = (struct rtl8187_tx_info *)skb->cb; + info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC); + info->urb = urb; + info->dev = dev; + usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2), + hdr, skb->len, rtl8187_tx_cb, skb); + usb_submit_urb(urb, GFP_ATOMIC); + + return 0; +} + +static void rtl8187_rx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; + struct ieee80211_hw *dev = info->dev; + struct rtl8187_priv *priv = dev->priv; + struct rtl8187_rx_hdr *hdr; + struct ieee80211_rx_status rx_status = { 0 }; + int rate, signal; + + spin_lock(&priv->rx_queue.lock); + if (skb->next) + __skb_unlink(skb, &priv->rx_queue); + else { + spin_unlock(&priv->rx_queue.lock); + return; + } + spin_unlock(&priv->rx_queue.lock); + + if (unlikely(urb->status)) { + usb_free_urb(urb); + dev_kfree_skb_irq(skb); + return; + } + + skb_put(skb, urb->actual_length); + hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); + skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF); + + signal = hdr->agc >> 1; + rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF; + if (rate > 3) { /* OFDM rate */ + if (signal > 90) + signal = 90; + else if (signal < 25) + signal = 25; + signal = 90 - signal; + } else { /* CCK rate */ + if (signal > 95) + signal = 95; + else if (signal < 30) + signal = 30; + signal = 95 - signal; + } + + rx_status.antenna = (hdr->signal >> 7) & 1; + rx_status.signal = 64 - min(hdr->noise, (u8)64); + rx_status.ssi = signal; + rx_status.rate = rate; + rx_status.freq = dev->conf.freq; + rx_status.channel = dev->conf.channel; + rx_status.phymode = dev->conf.phymode; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + ieee80211_rx_irqsafe(dev, skb, &rx_status); + + skb = dev_alloc_skb(RTL8187_MAX_RX); + if (unlikely(!skb)) { + usb_free_urb(urb); + /* TODO check rx queue length and refill *somewhere* */ + return; + } + + info = (struct rtl8187_rx_info *)skb->cb; + info->urb = urb; + info->dev = dev; + urb->transfer_buffer = skb_tail_pointer(skb); + urb->context = skb; + skb_queue_tail(&priv->rx_queue, skb); + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int rtl8187_init_urbs(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct urb *entry; + struct sk_buff *skb; + struct rtl8187_rx_info *info; + + while (skb_queue_len(&priv->rx_queue) < 8) { + skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); + if (!skb) + break; + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) { + kfree_skb(skb); + break; + } + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, 1), + skb_tail_pointer(skb), + RTL8187_MAX_RX, rtl8187_rx_cb, skb); + info = (struct rtl8187_rx_info *)skb->cb; + info->urb = entry; + info->dev = dev; + skb_queue_tail(&priv->rx_queue, skb); + usb_submit_urb(entry, GFP_KERNEL); + } + + return 0; +} + +static int rtl8187_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u8 reg; + int i; + + /* reset */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + msleep(200); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); + msleep(200); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= (1 << 1); + reg |= RTL818X_CMD_RESET; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + i = 10; + do { + msleep(2); + if (!(rtl818x_ioread8(priv, &priv->map->CMD) & + RTL818X_CMD_RESET)) + break; + } while (--i); + + if (!i) { + printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + /* reload registers from eeprom */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); + + i = 10; + do { + msleep(4); + if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) & + RTL818X_EEPROM_CMD_CONFIG)) + break; + } while (--i); + + if (!i) { + printk(KERN_ERR "%s: eeprom reset timeout!\n", + wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + /* setup card */ + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); + rtl818x_iowrite8(priv, &priv->map->GPIO, 1); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]); + + rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); + reg &= 0x3F; + reg |= 0x80; + rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + + // TODO: set RESP_RATE and BRSR properly + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* host_usb_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + reg = rtl818x_ioread8(priv, (u8 *)0xFE53); + rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80); + msleep(100); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); + msleep(100); + + priv->rf_init(dev); + + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe; + rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1); + rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); + rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); + rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); + rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg); + + return 0; +} + +static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel) +{ + u32 reg; + struct rtl8187_priv *priv = dev->priv; + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + /* Enable TX loopback on MAC level to avoid TX during channel + * changes, as this has be seen to causes problems and the + * card will stop work until next reset + */ + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + reg | RTL818X_TX_CONF_LOOPBACK_MAC); + msleep(10); + rtl8225_rf_set_channel(dev, channel); + msleep(10); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); +} + +static int rtl8187_open(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u32 reg; + int ret; + + ret = rtl8187_init_hw(dev); + if (ret) + return ret; + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl8187_init_urbs(dev); + + reg = RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_BSSID | + RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_CTRL | + RTL818X_RX_CONF_DATA | + (7 << 13 /* RX FIFO threshold NONE */) | + (7 << 10 /* MAX RX DMA */) | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_MULTICAST | + RTL818X_RX_CONF_NICMAC; + if (priv->mode == IEEE80211_IF_TYPE_MNTR) + reg |= RTL818X_RX_CONF_MONITOR; + + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + reg = RTL818X_TX_CONF_CW_MIN | + (7 << 21 /* MAX TX DMA */) | + RTL818X_TX_CONF_NO_ICV; + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg |= RTL818X_CMD_TX_ENABLE; + reg |= RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + return 0; +} + +static int rtl8187_stop(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct rtl8187_rx_info *info; + struct sk_buff *skb; + u32 reg; + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= ~RTL818X_CMD_TX_ENABLE; + reg &= ~RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + rtl8225_rf_stop(dev); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); + rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + while ((skb = skb_dequeue(&priv->rx_queue))) { + info = (struct rtl8187_rx_info *)skb->cb; + usb_kill_urb(info->urb); + kfree_skb(skb); + } + return 0; +} + +static int rtl8187_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + + /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ + if (priv->mode != IEEE80211_IF_TYPE_MGMT) + return -1; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->hwaddr = conf->mac_addr; + + return 0; +} + +static void rtl8187_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; +} + +static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + rtl8187_set_channel(dev, conf->channel); + + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } + + rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); + rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); + return 0; +} + +static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, + struct ieee80211_if_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); + + if (is_valid_ether_addr(conf->bssid)) + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); + else + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); + + return 0; +} + +static const struct ieee80211_ops rtl8187_ops = { + .tx = rtl8187_tx, + .open = rtl8187_open, + .stop = rtl8187_stop, + .add_interface = rtl8187_add_interface, + .remove_interface = rtl8187_remove_interface, + .config = rtl8187_config, + .config_interface = rtl8187_config_interface, +}; + +static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8187_priv *priv = dev->priv; + u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + + eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; + eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; + eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; + eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; +} + +static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8187_priv *priv = dev->priv; + u8 reg = RTL818X_EEPROM_CMD_PROGRAM; + + if (eeprom->reg_data_in) + reg |= RTL818X_EEPROM_CMD_WRITE; + if (eeprom->reg_data_out) + reg |= RTL818X_EEPROM_CMD_READ; + if (eeprom->reg_data_clock) + reg |= RTL818X_EEPROM_CMD_CK; + if (eeprom->reg_chip_select) + reg |= RTL818X_EEPROM_CMD_CS; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); + udelay(10); +} + +static int __devinit rtl8187_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ieee80211_hw *dev; + struct rtl8187_priv *priv; + struct eeprom_93cx6 eeprom; + struct ieee80211_channel *channel; + u16 txpwr, reg; + int err, i; + + dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); + if (!dev) { + printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n"); + return -ENOMEM; + } + + priv = dev->priv; + + SET_IEEE80211_DEV(dev, &intf->dev); + usb_set_intfdata(intf, dev); + priv->udev = udev; + + usb_get_dev(udev); + + skb_queue_head_init(&priv->rx_queue); + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); + memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); + priv->map = (struct rtl818x_csr *)0xFF00; + priv->modes[0].mode = MODE_IEEE80211G; + priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates); + priv->modes[0].rates = priv->rates; + priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels); + priv->modes[0].channels = priv->channels; + priv->modes[1].mode = MODE_IEEE80211B; + priv->modes[1].num_rates = 4; + priv->modes[1].rates = priv->rates; + priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); + priv->modes[1].channels = priv->channels; + priv->mode = IEEE80211_IF_TYPE_MGMT; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_WEP_INCLUDE_IV | + IEEE80211_HW_DATA_NULLFUNC_ACK; + dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); + dev->queues = 1; + dev->max_rssi = 65; + dev->max_signal = 64; + + for (i = 0; i < 2; i++) + if ((err = ieee80211_register_hwmode(dev, &priv->modes[i]))) + goto err_free_dev; + + eeprom.data = dev; + eeprom.register_read = rtl8187_eeprom_register_read; + eeprom.register_write = rtl8187_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + udelay(10); + + eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR, + (__le16 __force *)dev->wiphy->perm_addr, 3); + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly " + "generated MAC address\n"); + random_ether_addr(dev->wiphy->perm_addr); + } + + channel = priv->channels; + for (i = 0; i < 3; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, + &txpwr); + (*channel++).val = txpwr & 0xFF; + (*channel++).val = txpwr >> 8; + } + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, + &txpwr); + (*channel++).val = txpwr & 0xFF; + (*channel++).val = txpwr >> 8; + } + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i, + &txpwr); + (*channel++).val = txpwr & 0xFF; + (*channel++).val = txpwr >> 8; + } + + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, + &priv->txpwr_base); + + reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1); + /* 0 means asic B-cut, we should use SW 3 wire + * bit-by-bit banging for radio. 1 means we can use + * USB specific request to write radio registers */ + priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3; + rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write(dev, 0, 0x1B7); + + if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700) + priv->rf_init = rtl8225_rf_init; + else + priv->rf_init = rtl8225z2_rf_init; + + rtl8225_write(dev, 0, 0x0B7); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "rtl8187: Cannot register device\n"); + goto err_free_dev; + } + + printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n", + wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + priv->asic_rev, priv->rf_init == rtl8225_rf_init ? + "rtl8225" : "rtl8225z2"); + + return 0; + + err_free_dev: + ieee80211_free_hw(dev); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + return err; +} + +static void __devexit rtl8187_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct rtl8187_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + usb_put_dev(interface_to_usbdev(intf)); + ieee80211_free_hw(dev); +} + +static struct usb_driver rtl8187_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8187_table, + .probe = rtl8187_probe, + .disconnect = rtl8187_disconnect, +}; + +static int __init rtl8187_init(void) +{ + return usb_register(&rtl8187_driver); +} + +static void __exit rtl8187_exit(void) +{ + usb_deregister(&rtl8187_driver); +} + +module_init(rtl8187_init); +module_exit(rtl8187_exit); diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c new file mode 100644 index 00000000000..efc41207780 --- /dev/null +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -0,0 +1,745 @@ +/* + * Radio tuning for RTL8225 on RTL8187 + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * Magic delays, register offsets, and phy value tables below are + * taken from the original r8187 driver sources. Thanks to Realtek + * for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/usb.h> +#include <net/mac80211.h> + +#include "rtl8187.h" +#include "rtl8187_rtl8225.h" + +static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg84, reg82; + u32 bangdata; + int i; + + bangdata = (data << 4) | (addr & 0xf); + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); + + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(10); + + for (i = 15; i >= 0; i--) { + u16 reg = reg80 | (bangdata & (1 << i)) >> i; + + if (i & 1) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + + if (!(i & 1)) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + msleep(2); +} + +static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg82, reg84; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + + reg80 &= ~(0x3 << 2); + reg84 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(10); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + addr, 0x8225, &data, sizeof(data), HZ / 2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + msleep(2); +} + +void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8187_priv *priv = dev->priv; + + if (priv->asic_rev) + rtl8225_write_8051(dev, addr, cpu_to_le16(data)); + else + rtl8225_write_bitbang(dev, addr, data); +} + +u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg82, reg84, out; + int i; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + + reg80 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(4); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(5); + + for (i = 4; i >= 0; i--) { + u16 reg = reg80 | ((addr >> i) & 1); + + if (!(i & 1)) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + udelay(1); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + udelay(2); + + if (i & 1) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + udelay(1); + } + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + + out = 0; + for (i = 11; i >= 0; i--) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(1); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + + if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) + out |= 1 << i; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 2)); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); + + return out; +} + +static const u16 rtl8225bcd_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb +}; + +static const u8 rtl8225_agc[] = { + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, + 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +static const u8 rtl8225_gain[] = { + 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */ + 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */ + 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */ + 0x33, 0x80, 0x79, 0xc5, /* -78dBm */ + 0x43, 0x78, 0x76, 0xc5, /* -74dBm */ + 0x53, 0x60, 0x73, 0xc5, /* -70dBm */ + 0x63, 0x58, 0x70, 0xc5, /* -66dBm */ +}; + +static const u8 rtl8225_threshold[] = { + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd +}; + +static const u8 rtl8225_tx_gain_cck_ofdm[] = { + 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e +}; + +static const u8 rtl8225_tx_power_cck[] = { + 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, + 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, + 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, + 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 +}; + +static const u8 rtl8225_tx_power_cck_ch14[] = { + 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225_tx_power_ofdm[] = { + 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 +}; + +static const u32 rtl8225_chan[] = { + 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, + 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 +}; + +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].val & 0xF; + ofdm_power = priv->channels[channel - 1].val >> 4; + + cck_power = min(cck_power, (u8)11); + ofdm_power = min(ofdm_power, (u8)35); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); + + if (channel == 14) + tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; + else + tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + msleep(1); // FIXME: optional? + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write_phy_ofdm(dev, 2, 0x42); + rtl8225_write_phy_ofdm(dev, 6, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x00); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1); + + tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; + + rtl8225_write_phy_ofdm(dev, 5, *tmp); + rtl8225_write_phy_ofdm(dev, 7, *tmp); + + msleep(1); +} + +void rtl8225_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + rtl8225_write(dev, 0x0, 0x067); msleep(1); + rtl8225_write(dev, 0x1, 0xFE0); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); msleep(1); + rtl8225_write(dev, 0x3, 0x441); msleep(1); + rtl8225_write(dev, 0x4, 0x486); msleep(1); + rtl8225_write(dev, 0x5, 0xBC0); msleep(1); + rtl8225_write(dev, 0x6, 0xAE6); msleep(1); + rtl8225_write(dev, 0x7, 0x82A); msleep(1); + rtl8225_write(dev, 0x8, 0x01F); msleep(1); + rtl8225_write(dev, 0x9, 0x334); msleep(1); + rtl8225_write(dev, 0xA, 0xFD4); msleep(1); + rtl8225_write(dev, 0xB, 0x391); msleep(1); + rtl8225_write(dev, 0xC, 0x050); msleep(1); + rtl8225_write(dev, 0xD, 0x6DB); msleep(1); + rtl8225_write(dev, 0xE, 0x029); msleep(1); + rtl8225_write(dev, 0xF, 0x914); msleep(100); + + rtl8225_write(dev, 0x2, 0xC4D); msleep(200); + rtl8225_write(dev, 0x2, 0x44D); msleep(200); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0c4d); + msleep(200); + rtl8225_write(dev, 0x02, 0x044d); + msleep(100); + if (!(rtl8225_read(dev, 6) & (1 << 7))) + printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", + wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); + } + + rtl8225_write(dev, 0x0, 0x127); + + for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x027); + rtl8225_write(dev, 0x0, 0x22F); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + msleep(1); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + msleep(1); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); + rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); + rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); + rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); + rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); + rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); + rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); + + rtl8225_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); + + /* set sensitivity */ + rtl8225_write(dev, 0x0c, 0x50); + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); + rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]); +} + +static const u8 rtl8225z2_tx_power_cck_ch14[] = { + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225z2_tx_power_cck[] = { + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 +}; + +static const u8 rtl8225z2_tx_power_ofdm[] = { + 0x42, 0x00, 0x40, 0x00, 0x40 +}; + +static const u8 rtl8225z2_tx_gain_cck_ofdm[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23 +}; + +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].val & 0xF; + ofdm_power = priv->channels[channel - 1].val >> 4; + + cck_power = min(cck_power, (u8)15); + cck_power += priv->txpwr_base & 0xF; + cck_power = min(cck_power, (u8)35); + + ofdm_power = min(ofdm_power, (u8)15); + ofdm_power += priv->txpwr_base >> 4; + ofdm_power = min(ofdm_power, (u8)35); + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else + tmp = rtl8225z2_tx_power_cck; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225z2_tx_gain_cck_ofdm[cck_power]); + msleep(1); + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write_phy_ofdm(dev, 2, 0x42); + rtl8225_write_phy_ofdm(dev, 5, 0x00); + rtl8225_write_phy_ofdm(dev, 6, 0x40); + rtl8225_write_phy_ofdm(dev, 7, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x40); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225z2_tx_gain_cck_ofdm[ofdm_power]); + msleep(1); +} + +static const u16 rtl8225z2_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb +}; + +static const u8 rtl8225z2_gain_bg[] = { + 0x23, 0x15, 0xa5, /* -82-1dBm */ + 0x23, 0x15, 0xb5, /* -82-2dBm */ + 0x23, 0x15, 0xc5, /* -82-3dBm */ + 0x33, 0x15, 0xc5, /* -78dBm */ + 0x43, 0x15, 0xc5, /* -74dBm */ + 0x53, 0x15, 0xc5, /* -70dBm */ + 0x63, 0x15, 0xc5 /* -66dBm */ +}; + +void rtl8225z2_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + rtl8225_write(dev, 0x0, 0x2BF); msleep(1); + rtl8225_write(dev, 0x1, 0xEE0); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); msleep(1); + rtl8225_write(dev, 0x3, 0x441); msleep(1); + rtl8225_write(dev, 0x4, 0x8C3); msleep(1); + rtl8225_write(dev, 0x5, 0xC72); msleep(1); + rtl8225_write(dev, 0x6, 0x0E6); msleep(1); + rtl8225_write(dev, 0x7, 0x82A); msleep(1); + rtl8225_write(dev, 0x8, 0x03F); msleep(1); + rtl8225_write(dev, 0x9, 0x335); msleep(1); + rtl8225_write(dev, 0xa, 0x9D4); msleep(1); + rtl8225_write(dev, 0xb, 0x7BB); msleep(1); + rtl8225_write(dev, 0xc, 0x850); msleep(1); + rtl8225_write(dev, 0xd, 0xCDF); msleep(1); + rtl8225_write(dev, 0xe, 0x02B); msleep(1); + rtl8225_write(dev, 0xf, 0x114); msleep(100); + + rtl8225_write(dev, 0x0, 0x1B7); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x2, 0xc4D); + + msleep(200); + rtl8225_write(dev, 0x2, 0x44D); + msleep(100); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0C4D); + msleep(200); + rtl8225_write(dev, 0x02, 0x044D); + msleep(100); + if (!(rtl8225_read(dev, 6) & (1 << 7))) + printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", + wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); + } + + msleep(200); + + rtl8225_write(dev, 0x0, 0x2BF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + msleep(1); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + msleep(1); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed? + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]); + rtl8225_write_phy_ofdm(dev, 0x21, 0x37); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); + rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); + rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); + rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); + rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); + rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); + rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); + rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); + rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + + rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1); + + rtl8225z2_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); +} + +void rtl8225_rf_stop(struct ieee80211_hw *dev) +{ + u8 reg; + struct rtl8187_priv *priv = dev->priv; + + rtl8225_write(dev, 0x4, 0x1f); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + + if (priv->rf_init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, channel); + else + rtl8225z2_rf_set_tx_power(dev, channel); + + rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]); + msleep(10); +} diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h new file mode 100644 index 00000000000..798ba4a9737 --- /dev/null +++ b/drivers/net/wireless/rtl8187_rtl8225.h @@ -0,0 +1,44 @@ +/* + * Radio tuning definitions for RTL8225 on RTL8187 + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL8187_RTL8225_H +#define RTL8187_RTL8225_H + +#define RTL8225_ANAPARAM_ON 0xa0000a59 +#define RTL8225_ANAPARAM2_ON 0x860c7312 +#define RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8225_ANAPARAM2_OFF 0x840dec11 + +void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data); +u16 rtl8225_read(struct ieee80211_hw *, u8 addr); + +void rtl8225_rf_init(struct ieee80211_hw *); +void rtl8225z2_rf_init(struct ieee80211_hw *); +void rtl8225_rf_stop(struct ieee80211_hw *); +void rtl8225_rf_set_channel(struct ieee80211_hw *, int); + + +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, + u8 addr, u32 data) +{ + rtl8187_write_phy(dev, addr, data); +} + +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, + u8 addr, u32 data) +{ + rtl8187_write_phy(dev, addr, data | 0x10000); +} + +#endif /* RTL8187_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h new file mode 100644 index 00000000000..283de30628e --- /dev/null +++ b/drivers/net/wireless/rtl818x.h @@ -0,0 +1,226 @@ +/* + * Definitions for RTL818x hardware + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL818X_H +#define RTL818X_H + +struct rtl818x_csr { + u8 MAC[6]; + u8 reserved_0[2]; + __le32 MAR[2]; + u8 RX_FIFO_COUNT; + u8 reserved_1; + u8 TX_FIFO_COUNT; + u8 BQREQ; + u8 reserved_2[4]; + __le32 TSFT[2]; + __le32 TLPDA; + __le32 TNPDA; + __le32 THPDA; + __le16 BRSR; + u8 BSSID[6]; + u8 RESP_RATE; + u8 EIFS; + u8 reserved_3[1]; + u8 CMD; +#define RTL818X_CMD_TX_ENABLE (1 << 2) +#define RTL818X_CMD_RX_ENABLE (1 << 3) +#define RTL818X_CMD_RESET (1 << 4) + u8 reserved_4[4]; + __le16 INT_MASK; + __le16 INT_STATUS; +#define RTL818X_INT_RX_OK (1 << 0) +#define RTL818X_INT_RX_ERR (1 << 1) +#define RTL818X_INT_TXL_OK (1 << 2) +#define RTL818X_INT_TXL_ERR (1 << 3) +#define RTL818X_INT_RX_DU (1 << 4) +#define RTL818X_INT_RX_FO (1 << 5) +#define RTL818X_INT_TXN_OK (1 << 6) +#define RTL818X_INT_TXN_ERR (1 << 7) +#define RTL818X_INT_TXH_OK (1 << 8) +#define RTL818X_INT_TXH_ERR (1 << 9) +#define RTL818X_INT_TXB_OK (1 << 10) +#define RTL818X_INT_TXB_ERR (1 << 11) +#define RTL818X_INT_ATIM (1 << 12) +#define RTL818X_INT_BEACON (1 << 13) +#define RTL818X_INT_TIME_OUT (1 << 14) +#define RTL818X_INT_TX_FO (1 << 15) + __le32 TX_CONF; +#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17) +#define RTL818X_TX_CONF_NO_ICV (1 << 19) +#define RTL818X_TX_CONF_DISCW (1 << 20) +#define RTL818X_TX_CONF_R8180_ABCD (2 << 25) +#define RTL818X_TX_CONF_R8180_F (3 << 25) +#define RTL818X_TX_CONF_R8185_ABC (4 << 25) +#define RTL818X_TX_CONF_R8185_D (5 << 25) +#define RTL818X_TX_CONF_HWVER_MASK (7 << 25) +#define RTL818X_TX_CONF_CW_MIN (1 << 31) + __le32 RX_CONF; +#define RTL818X_RX_CONF_MONITOR (1 << 0) +#define RTL818X_RX_CONF_NICMAC (1 << 1) +#define RTL818X_RX_CONF_MULTICAST (1 << 2) +#define RTL818X_RX_CONF_BROADCAST (1 << 3) +#define RTL818X_RX_CONF_DATA (1 << 18) +#define RTL818X_RX_CONF_CTRL (1 << 19) +#define RTL818X_RX_CONF_MGMT (1 << 20) +#define RTL818X_RX_CONF_BSSID (1 << 23) +#define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28) +#define RTL818X_RX_CONF_ONLYERLPKT (1 << 31) + __le32 INT_TIMEOUT; + __le32 TBDA; + u8 EEPROM_CMD; +#define RTL818X_EEPROM_CMD_READ (1 << 0) +#define RTL818X_EEPROM_CMD_WRITE (1 << 1) +#define RTL818X_EEPROM_CMD_CK (1 << 2) +#define RTL818X_EEPROM_CMD_CS (1 << 3) +#define RTL818X_EEPROM_CMD_NORMAL (0 << 6) +#define RTL818X_EEPROM_CMD_LOAD (1 << 6) +#define RTL818X_EEPROM_CMD_PROGRAM (2 << 6) +#define RTL818X_EEPROM_CMD_CONFIG (3 << 6) + u8 CONFIG0; + u8 CONFIG1; + u8 CONFIG2; + __le32 ANAPARAM; + u8 MSR; +#define RTL818X_MSR_NO_LINK (0 << 2) +#define RTL818X_MSR_ADHOC (1 << 2) +#define RTL818X_MSR_INFRA (2 << 2) + u8 CONFIG3; +#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6) + u8 CONFIG4; +#define RTL818X_CONFIG4_POWEROFF (1 << 6) +#define RTL818X_CONFIG4_VCOOFF (1 << 7) + u8 TESTR; + u8 reserved_9[2]; + __le16 PGSELECT; + __le32 ANAPARAM2; + u8 reserved_10[12]; + __le16 BEACON_INTERVAL; + __le16 ATIM_WND; + __le16 BEACON_INTERVAL_TIME; + __le16 ATIMTR_INTERVAL; + u8 reserved_11[4]; + u8 PHY[4]; + __le16 RFPinsOutput; + __le16 RFPinsEnable; + __le16 RFPinsSelect; + __le16 RFPinsInput; + __le32 RF_PARA; + __le32 RF_TIMING; + u8 GP_ENABLE; + u8 GPIO; + u8 reserved_12[10]; + u8 TX_AGC_CTL; +#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0) +#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1) +#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2) + u8 TX_GAIN_CCK; + u8 TX_GAIN_OFDM; + u8 TX_ANTENNA; + u8 reserved_13[16]; + u8 WPA_CONF; + u8 reserved_14[3]; + u8 SIFS; + u8 DIFS; + u8 SLOT; + u8 reserved_15[5]; + u8 CW_CONF; +#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0) +#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1) + u8 CW_VAL; + u8 RATE_FALLBACK; + u8 reserved_16[25]; + u8 CONFIG5; + u8 TX_DMA_POLLING; + u8 reserved_17[2]; + __le16 CWR; + u8 RETRY_CTR; + u8 reserved_18[5]; + __le32 RDSAR; + u8 reserved_19[18]; + u16 TALLY_CNT; + u8 TALLY_SEL; +} __attribute__((packed)); + +static const struct ieee80211_rate rtl818x_rates[] = { + { .rate = 10, + .val = 0, + .flags = IEEE80211_RATE_CCK }, + { .rate = 20, + .val = 1, + .flags = IEEE80211_RATE_CCK }, + { .rate = 55, + .val = 2, + .flags = IEEE80211_RATE_CCK }, + { .rate = 110, + .val = 3, + .flags = IEEE80211_RATE_CCK }, + { .rate = 60, + .val = 4, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 90, + .val = 5, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 120, + .val = 6, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 180, + .val = 7, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 240, + .val = 8, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 360, + .val = 9, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 480, + .val = 10, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 540, + .val = 11, + .flags = IEEE80211_RATE_OFDM }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .chan = 1, + .freq = 2412}, + { .chan = 2, + .freq = 2417}, + { .chan = 3, + .freq = 2422}, + { .chan = 4, + .freq = 2427}, + { .chan = 5, + .freq = 2432}, + { .chan = 6, + .freq = 2437}, + { .chan = 7, + .freq = 2442}, + { .chan = 8, + .freq = 2447}, + { .chan = 9, + .freq = 2452}, + { .chan = 10, + .freq = 2457}, + { .chan = 11, + .freq = 2462}, + { .chan = 12, + .freq = 2467}, + { .chan = 13, + .freq = 2472}, + { .chan = 14, + .freq = 2484} +}; + +#endif /* RTL818X_H */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index ce9230b2f63..c8b5c227193 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1011,7 +1011,7 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev, } else { skb->dev = dev; skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ - eth_copy_and_sum(skb, (unsigned char *)&sig.daddr, 12, 0); + skb_copy_to_linear_data(skb, (unsigned char *)&sig.daddr, 12); wl3501_receive(this, skb->data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 6603ad5be63..4d505903352 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o zd1211rw-objs := zd_chip.o zd_ieee80211.o \ zd_mac.o zd_netdev.o \ zd_rf_al2230.o zd_rf_rf2959.o \ - zd_rf_al7230b.o \ + zd_rf_al7230b.o zd_rf_uw2453.o \ zd_rf.o zd_usb.o zd_util.o ifeq ($(CONFIG_ZD1211RW_DEBUG),y) diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 95b4a2a2670..c39f1984b84 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -49,8 +49,9 @@ void zd_chip_clear(struct zd_chip *chip) ZD_MEMCLEAR(chip, sizeof(*chip)); } -static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size) +static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size) { + u8 *addr = zd_usb_to_netdev(&chip->usb)->dev_addr; return scnprintf(buffer, size, "%02x-%02x-%02x", addr[0], addr[1], addr[2]); } @@ -61,10 +62,10 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size) int i = 0; i = scnprintf(buffer, size, "zd1211%s chip ", - chip->is_zd1211b ? "b" : ""); + zd_chip_is_zd1211b(chip) ? "b" : ""); i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " "); - i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); + i += scnprint_mac_oui(chip, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " "); i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, @@ -366,64 +367,9 @@ error: return r; } -static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr, - const zd_addr_t *addr) -{ - int r; - u32 parts[2]; - - r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2); - if (r) { - dev_dbg_f(zd_chip_dev(chip), - "error: couldn't read e2p macs. Error number %d\n", r); - return r; - } - - mac_addr[0] = parts[0]; - mac_addr[1] = parts[0] >> 8; - mac_addr[2] = parts[0] >> 16; - mac_addr[3] = parts[0] >> 24; - mac_addr[4] = parts[1]; - mac_addr[5] = parts[1] >> 8; - - return 0; -} - -static int read_e2p_mac_addr(struct zd_chip *chip) -{ - static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 }; - - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr); -} - /* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and * CR_MAC_ADDR_P2 must be overwritten */ -void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr) -{ - mutex_lock(&chip->mutex); - memcpy(mac_addr, chip->e2p_mac, ETH_ALEN); - mutex_unlock(&chip->mutex); -} - -static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr) -{ - static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 }; - return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr); -} - -int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr) -{ - int r; - - dev_dbg_f(zd_chip_dev(chip), "\n"); - mutex_lock(&chip->mutex); - r = read_mac_addr(chip, mac_addr); - mutex_unlock(&chip->mutex); - return r; -} - int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) { int r; @@ -444,12 +390,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) mutex_lock(&chip->mutex); r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); -#ifdef DEBUG - { - u8 tmp[ETH_ALEN]; - read_mac_addr(chip, tmp); - } -#endif /* DEBUG */ mutex_unlock(&chip->mutex); return r; } @@ -809,7 +749,7 @@ out: static int hw_reset_phy(struct zd_chip *chip) { - return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) : + return zd_chip_is_zd1211b(chip) ? zd1211b_hw_reset_phy(chip) : zd1211_hw_reset_phy(chip); } @@ -874,7 +814,7 @@ static int hw_init_hmac(struct zd_chip *chip) if (r) return r; - return chip->is_zd1211b ? + return zd_chip_is_zd1211b(chip) ? zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip); } @@ -1136,8 +1076,15 @@ static int read_fw_regs_offset(struct zd_chip *chip) return 0; } +/* Read mac address using pre-firmware interface */ +int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr) +{ + dev_dbg_f(zd_chip_dev(chip), "\n"); + return zd_usb_read_fw(&chip->usb, E2P_MAC_ADDR_P1, addr, + ETH_ALEN); +} -int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) +int zd_chip_init_hw(struct zd_chip *chip) { int r; u8 rf_type; @@ -1145,7 +1092,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) dev_dbg_f(zd_chip_dev(chip), "\n"); mutex_lock(&chip->mutex); - chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0; #ifdef DEBUG r = test_init(chip); @@ -1201,10 +1147,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) goto out; #endif /* DEBUG */ - r = read_e2p_mac_addr(chip); - if (r) - goto out; - r = read_cal_int_tables(chip); if (r) goto out; @@ -1253,10 +1195,13 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, { int r; + if (!zd_rf_should_update_pwr_int(&chip->rf)) + return 0; + r = update_pwr_int(chip, channel); if (r) return r; - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { static const struct zd_ioreq16 ioreqs[] = { { CR69, 0x28 }, {}, @@ -1283,7 +1228,7 @@ static int patch_cck_gain(struct zd_chip *chip) int r; u32 value; - if (!chip->patch_cck_gain) + if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf)) return 0; ZD_ASSERT(mutex_is_locked(&chip->mutex)); diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index ce0a5f6da0d..f4698576ab7 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -608,6 +608,9 @@ enum { #define CR_ZD1211B_TXOP CTL_REG(0x0b20) #define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28) +/* Used to detect PLL lock */ +#define UW2453_INTR_REG ((zd_addr_t)0x85c1) + #define CWIN_SIZE 0x007f043f @@ -701,7 +704,6 @@ struct zd_chip { struct mutex mutex; /* Base address of FW_REG_ registers */ zd_addr_t fw_regs_base; - u8 e2p_mac[ETH_ALEN]; /* EepSetPoint in the vendor driver */ u8 pwr_cal_values[E2P_CHANNEL_COUNT]; /* integration values in the vendor driver */ @@ -712,7 +714,7 @@ struct zd_chip { unsigned int pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, new_phy_layout:1, al2230s_bit:1, - is_zd1211b:1, supports_tx_led:1; + supports_tx_led:1; }; static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) @@ -731,9 +733,15 @@ void zd_chip_init(struct zd_chip *chip, struct net_device *netdev, struct usb_interface *intf); void zd_chip_clear(struct zd_chip *chip); -int zd_chip_init_hw(struct zd_chip *chip, u8 device_type); +int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr); +int zd_chip_init_hw(struct zd_chip *chip); int zd_chip_reset(struct zd_chip *chip); +static inline int zd_chip_is_zd1211b(struct zd_chip *chip) +{ + return chip->usb.is_zd1211b; +} + static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values, const zd_addr_t *addresses, unsigned int count) @@ -822,8 +830,6 @@ static inline u8 _zd_chip_get_channel(struct zd_chip *chip) } u8 zd_chip_get_channel(struct zd_chip *chip); int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain); -void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr); -int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr); int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr); int zd_chip_switch_radio_on(struct zd_chip *chip); int zd_chip_switch_radio_off(struct zd_chip *chip); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6753d240c16..f6c487aa824 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -86,38 +86,46 @@ out: return r; } -int zd_mac_init_hw(struct zd_mac *mac, u8 device_type) +int zd_mac_preinit_hw(struct zd_mac *mac) { int r; - struct zd_chip *chip = &mac->chip; u8 addr[ETH_ALEN]; + + r = zd_chip_read_mac_addr_fw(&mac->chip, addr); + if (r) + return r; + + memcpy(mac->netdev->dev_addr, addr, ETH_ALEN); + return 0; +} + +int zd_mac_init_hw(struct zd_mac *mac) +{ + int r; + struct zd_chip *chip = &mac->chip; u8 default_regdomain; r = zd_chip_enable_int(chip); if (r) goto out; - r = zd_chip_init_hw(chip, device_type); + r = zd_chip_init_hw(chip); if (r) goto disable_int; - zd_get_e2p_mac_addr(chip, addr); - r = zd_write_mac_addr(chip, addr); - if (r) - goto disable_int; ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&mac->lock); - memcpy(mac->netdev->dev_addr, addr, ETH_ALEN); - spin_unlock_irq(&mac->lock); r = zd_read_regdomain(chip, &default_regdomain); if (r) goto disable_int; if (!zd_regdomain_supported(default_regdomain)) { - dev_dbg_f(zd_mac_dev(mac), - "Regulatory Domain %#04x is not supported.\n", - default_regdomain); - r = -EINVAL; - goto disable_int; + /* The vendor driver overrides the regulatory domain and + * allowed channel registers and unconditionally restricts + * available channels to 1-11 everywhere. Match their + * questionable behaviour only for regdomains which we don't + * recognise. */ + dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: " + "%#04x. Defaulting to FCC.\n", default_regdomain); + default_regdomain = ZD_REGDOMAIN_FCC; } spin_lock_irq(&mac->lock); mac->regdomain = mac->default_regdomain = default_regdomain; @@ -164,14 +172,25 @@ int zd_mac_open(struct net_device *netdev) { struct zd_mac *mac = zd_netdev_mac(netdev); struct zd_chip *chip = &mac->chip; + struct zd_usb *usb = &chip->usb; int r; + if (!usb->initialized) { + r = zd_usb_init_hw(usb); + if (r) + goto out; + } + tasklet_enable(&mac->rx_tasklet); r = zd_chip_enable_int(chip); if (r < 0) goto out; + r = zd_write_mac_addr(chip, netdev->dev_addr); + if (r) + goto disable_int; + r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); if (r < 0) goto disable_int; @@ -251,9 +270,11 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p) dev_dbg_f(zd_mac_dev(mac), "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data)); - r = zd_write_mac_addr(chip, addr->sa_data); - if (r) - return r; + if (netdev->flags & IFF_UP) { + r = zd_write_mac_addr(chip, addr->sa_data); + if (r) + return r; + } spin_lock_irqsave(&mac->lock, flags); memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN); @@ -855,7 +876,7 @@ static int fill_ctrlset(struct zd_mac *mac, /* ZD1211B: Computing the length difference this way, gives us * flexibility to compute the packet length. */ - cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ? + cs->packet_length = cpu_to_le16(zd_chip_is_zd1211b(&mac->chip) ? packet_length - frag_len : packet_length); /* diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index faf4c7828d4..9f9344eb50f 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -189,7 +189,8 @@ int zd_mac_init(struct zd_mac *mac, struct usb_interface *intf); void zd_mac_clear(struct zd_mac *mac); -int zd_mac_init_hw(struct zd_mac *mac, u8 device_type); +int zd_mac_preinit_hw(struct zd_mac *mac); +int zd_mac_init_hw(struct zd_mac *mac); int zd_mac_open(struct net_device *netdev); int zd_mac_stop(struct net_device *netdev); diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index 549c23bcd6c..abe5d38f7f4 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -34,7 +34,7 @@ static const char * const rfs[] = { [AL2210_RF] = "AL2210_RF", [MAXIM_NEW_RF] = "MAXIM_NEW_RF", [UW2453_RF] = "UW2453_RF", - [UNKNOWN_A_RF] = "UNKNOWN_A_RF", + [AL2230S_RF] = "AL2230S_RF", [RALINK_RF] = "RALINK_RF", [INTERSIL_RF] = "INTERSIL_RF", [RF2959_RF] = "RF2959_RF", @@ -52,34 +52,39 @@ const char *zd_rf_name(u8 type) void zd_rf_init(struct zd_rf *rf) { memset(rf, 0, sizeof(*rf)); + + /* default to update channel integration, as almost all RF's do want + * this */ + rf->update_channel_int = 1; } void zd_rf_clear(struct zd_rf *rf) { + if (rf->clear) + rf->clear(rf); ZD_MEMCLEAR(rf, sizeof(*rf)); } int zd_rf_init_hw(struct zd_rf *rf, u8 type) { - int r, t; + int r = 0; + int t; struct zd_chip *chip = zd_rf_to_chip(rf); ZD_ASSERT(mutex_is_locked(&chip->mutex)); switch (type) { case RF2959_RF: r = zd_rf_init_rf2959(rf); - if (r) - return r; break; case AL2230_RF: + case AL2230S_RF: r = zd_rf_init_al2230(rf); - if (r) - return r; break; case AL7230B_RF: r = zd_rf_init_al7230b(rf); - if (r) - return r; + break; + case UW2453_RF: + r = zd_rf_init_uw2453(rf); break; default: dev_err(zd_chip_dev(chip), @@ -88,6 +93,9 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type) return -ENODEV; } + if (r) + return r; + rf->type = type; r = zd_chip_lock_phy_regs(chip); diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index aa9cc105ce6..30502f26b71 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -26,7 +26,7 @@ #define AL2210_RF 0x7 #define MAXIM_NEW_RF 0x8 #define UW2453_RF 0x9 -#define UNKNOWN_A_RF 0xa +#define AL2230S_RF 0xa #define RALINK_RF 0xb #define INTERSIL_RF 0xc #define RF2959_RF 0xd @@ -48,12 +48,26 @@ struct zd_rf { u8 channel; + /* whether channel integration and calibration should be updated + * defaults to 1 (yes) */ + u8 update_channel_int:1; + + /* whether CR47 should be patched from the EEPROM, if the appropriate + * flag is set in the POD. The vendor driver suggests that this should + * be done for all RF's, but a bug in their code prevents but their + * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ + u8 patch_cck_gain:1; + + /* private RF driver data */ + void *priv; + /* RF-specific functions */ int (*init_hw)(struct zd_rf *rf); int (*set_channel)(struct zd_rf *rf, u8 channel); int (*switch_radio_on)(struct zd_rf *rf); int (*switch_radio_off)(struct zd_rf *rf); int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel); + void (*clear)(struct zd_rf *rf); }; const char *zd_rf_name(u8 type); @@ -71,10 +85,24 @@ int zd_switch_radio_off(struct zd_rf *rf); int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel); int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel); +static inline int zd_rf_should_update_pwr_int(struct zd_rf *rf) +{ + return rf->update_channel_int; +} + +static inline int zd_rf_should_patch_cck_gain(struct zd_rf *rf) +{ + return rf->patch_cck_gain; +} + +int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel); +int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel); + /* Functions for individual RF chips */ int zd_rf_init_rf2959(struct zd_rf *rf); int zd_rf_init_al2230(struct zd_rf *rf); int zd_rf_init_al7230b(struct zd_rf *rf); +int zd_rf_init_uw2453(struct zd_rf *rf); #endif /* _ZD_RF_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 511392acfed..006774de320 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -21,6 +21,8 @@ #include "zd_usb.h" #include "zd_chip.h" +#define IS_AL2230S(chip) ((chip)->al2230s_bit || (chip)->rf.type == AL2230S_RF) + static const u32 zd1211_al2230_table[][3] = { RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, }, RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, }, @@ -176,7 +178,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) if (r) return r; - if (chip->al2230s_bit) { + if (IS_AL2230S(chip)) { r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, ARRAY_SIZE(ioreqs_init_al2230s)); if (r) @@ -188,7 +190,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) return r; /* improve band edge for AL2230S */ - if (chip->al2230s_bit) + if (IS_AL2230S(chip)) r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS); else r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS); @@ -314,7 +316,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) if (r) return r; - if (chip->al2230s_bit) { + if (IS_AL2230S(chip)) { r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, ARRAY_SIZE(ioreqs_init_al2230s)); if (r) @@ -328,7 +330,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) if (r) return r; - if (chip->al2230s_bit) + if (IS_AL2230S(chip)) r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS); else r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS); @@ -422,7 +424,7 @@ int zd_rf_init_al2230(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); rf->switch_radio_off = al2230_switch_radio_off; - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { rf->init_hw = zd1211b_al2230_init_hw; rf->set_channel = zd1211b_al2230_set_channel; rf->switch_radio_on = zd1211b_al2230_switch_radio_on; @@ -432,5 +434,6 @@ int zd_rf_init_al2230(struct zd_rf *rf) rf->switch_radio_on = zd1211_al2230_switch_radio_on; } rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->patch_cck_gain = 1; return 0; } diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 5e5e9ddc6a7..73d0bb26f81 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -473,7 +473,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { rf->init_hw = zd1211b_al7230b_init_hw; rf->switch_radio_on = zd1211b_al7230b_switch_radio_on; rf->set_channel = zd1211b_al7230b_set_channel; @@ -483,6 +483,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf) rf->switch_radio_on = zd1211_al7230b_switch_radio_on; rf->set_channel = zd1211_al7230b_set_channel; rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->patch_cck_gain = 1; } rf->switch_radio_off = al7230b_switch_radio_off; diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 2d736bdf707..cc70d40684e 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -265,7 +265,7 @@ int zd_rf_init_rf2959(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { dev_err(zd_chip_dev(chip), "RF2959 is currently not supported for ZD1211B" " devices\n"); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c new file mode 100644 index 00000000000..857dcf3eae6 --- /dev/null +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -0,0 +1,534 @@ +/* zd_rf_uw2453.c: Functions for the UW2453 RF controller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> + +#include "zd_rf.h" +#include "zd_usb.h" +#include "zd_chip.h" + +/* This RF programming code is based upon the code found in v2.16.0.0 of the + * ZyDAS vendor driver. Unlike other RF's, Ubec publish full technical specs + * for this RF on their website, so we're able to understand more than + * usual as to what is going on. Thumbs up for Ubec for doing that. */ + +/* The 3-wire serial interface provides access to 8 write-only registers. + * The data format is a 4 bit register address followed by a 20 bit value. */ +#define UW2453_REGWRITE(reg, val) ((((reg) & 0xf) << 20) | ((val) & 0xfffff)) + +/* For channel tuning, we have to configure registers 1 (synthesizer), 2 (synth + * fractional divide ratio) and 3 (VCO config). + * + * We configure the RF to produce an interrupt when the PLL is locked onto + * the configured frequency. During initialization, we run through a variety + * of different VCO configurations on channel 1 until we detect a PLL lock. + * When this happens, we remember which VCO configuration produced the lock + * and use it later. Actually, we use the configuration *after* the one that + * produced the lock, which seems odd, but it works. + * + * If we do not see a PLL lock on any standard VCO config, we fall back on an + * autocal configuration, which has a fixed (as opposed to per-channel) VCO + * config and different synth values from the standard set (divide ratio + * is still shared with the standard set). */ + +/* The per-channel synth values for all standard VCO configurations. These get + * written to register 1. */ +static const u8 uw2453_std_synth[] = { + RF_CHANNEL( 1) = 0x47, + RF_CHANNEL( 2) = 0x47, + RF_CHANNEL( 3) = 0x67, + RF_CHANNEL( 4) = 0x67, + RF_CHANNEL( 5) = 0x67, + RF_CHANNEL( 6) = 0x67, + RF_CHANNEL( 7) = 0x57, + RF_CHANNEL( 8) = 0x57, + RF_CHANNEL( 9) = 0x57, + RF_CHANNEL(10) = 0x57, + RF_CHANNEL(11) = 0x77, + RF_CHANNEL(12) = 0x77, + RF_CHANNEL(13) = 0x77, + RF_CHANNEL(14) = 0x4f, +}; + +/* This table stores the synthesizer fractional divide ratio for *all* VCO + * configurations (both standard and autocal). These get written to register 2. + */ +static const u16 uw2453_synth_divide[] = { + RF_CHANNEL( 1) = 0x999, + RF_CHANNEL( 2) = 0x99b, + RF_CHANNEL( 3) = 0x998, + RF_CHANNEL( 4) = 0x99a, + RF_CHANNEL( 5) = 0x999, + RF_CHANNEL( 6) = 0x99b, + RF_CHANNEL( 7) = 0x998, + RF_CHANNEL( 8) = 0x99a, + RF_CHANNEL( 9) = 0x999, + RF_CHANNEL(10) = 0x99b, + RF_CHANNEL(11) = 0x998, + RF_CHANNEL(12) = 0x99a, + RF_CHANNEL(13) = 0x999, + RF_CHANNEL(14) = 0xccc, +}; + +/* Here is the data for all the standard VCO configurations. We shrink our + * table a little by observing that both channels in a consecutive pair share + * the same value. We also observe that the high 4 bits ([0:3] in the specs) + * are all 'Reserved' and are always set to 0x4 - we chop them off in the data + * below. */ +#define CHAN_TO_PAIRIDX(a) ((a - 1) / 2) +#define RF_CHANPAIR(a,b) [CHAN_TO_PAIRIDX(a)] +static const u16 uw2453_std_vco_cfg[][7] = { + { /* table 1 */ + RF_CHANPAIR( 1, 2) = 0x664d, + RF_CHANPAIR( 3, 4) = 0x604d, + RF_CHANPAIR( 5, 6) = 0x6675, + RF_CHANPAIR( 7, 8) = 0x6475, + RF_CHANPAIR( 9, 10) = 0x6655, + RF_CHANPAIR(11, 12) = 0x6455, + RF_CHANPAIR(13, 14) = 0x6665, + }, + { /* table 2 */ + RF_CHANPAIR( 1, 2) = 0x666d, + RF_CHANPAIR( 3, 4) = 0x606d, + RF_CHANPAIR( 5, 6) = 0x664d, + RF_CHANPAIR( 7, 8) = 0x644d, + RF_CHANPAIR( 9, 10) = 0x6675, + RF_CHANPAIR(11, 12) = 0x6475, + RF_CHANPAIR(13, 14) = 0x6655, + }, + { /* table 3 */ + RF_CHANPAIR( 1, 2) = 0x665d, + RF_CHANPAIR( 3, 4) = 0x605d, + RF_CHANPAIR( 5, 6) = 0x666d, + RF_CHANPAIR( 7, 8) = 0x646d, + RF_CHANPAIR( 9, 10) = 0x664d, + RF_CHANPAIR(11, 12) = 0x644d, + RF_CHANPAIR(13, 14) = 0x6675, + }, + { /* table 4 */ + RF_CHANPAIR( 1, 2) = 0x667d, + RF_CHANPAIR( 3, 4) = 0x607d, + RF_CHANPAIR( 5, 6) = 0x665d, + RF_CHANPAIR( 7, 8) = 0x645d, + RF_CHANPAIR( 9, 10) = 0x666d, + RF_CHANPAIR(11, 12) = 0x646d, + RF_CHANPAIR(13, 14) = 0x664d, + }, + { /* table 5 */ + RF_CHANPAIR( 1, 2) = 0x6643, + RF_CHANPAIR( 3, 4) = 0x6043, + RF_CHANPAIR( 5, 6) = 0x667d, + RF_CHANPAIR( 7, 8) = 0x647d, + RF_CHANPAIR( 9, 10) = 0x665d, + RF_CHANPAIR(11, 12) = 0x645d, + RF_CHANPAIR(13, 14) = 0x666d, + }, + { /* table 6 */ + RF_CHANPAIR( 1, 2) = 0x6663, + RF_CHANPAIR( 3, 4) = 0x6063, + RF_CHANPAIR( 5, 6) = 0x6643, + RF_CHANPAIR( 7, 8) = 0x6443, + RF_CHANPAIR( 9, 10) = 0x667d, + RF_CHANPAIR(11, 12) = 0x647d, + RF_CHANPAIR(13, 14) = 0x665d, + }, + { /* table 7 */ + RF_CHANPAIR( 1, 2) = 0x6653, + RF_CHANPAIR( 3, 4) = 0x6053, + RF_CHANPAIR( 5, 6) = 0x6663, + RF_CHANPAIR( 7, 8) = 0x6463, + RF_CHANPAIR( 9, 10) = 0x6643, + RF_CHANPAIR(11, 12) = 0x6443, + RF_CHANPAIR(13, 14) = 0x667d, + }, + { /* table 8 */ + RF_CHANPAIR( 1, 2) = 0x6673, + RF_CHANPAIR( 3, 4) = 0x6073, + RF_CHANPAIR( 5, 6) = 0x6653, + RF_CHANPAIR( 7, 8) = 0x6453, + RF_CHANPAIR( 9, 10) = 0x6663, + RF_CHANPAIR(11, 12) = 0x6463, + RF_CHANPAIR(13, 14) = 0x6643, + }, + { /* table 9 */ + RF_CHANPAIR( 1, 2) = 0x664b, + RF_CHANPAIR( 3, 4) = 0x604b, + RF_CHANPAIR( 5, 6) = 0x6673, + RF_CHANPAIR( 7, 8) = 0x6473, + RF_CHANPAIR( 9, 10) = 0x6653, + RF_CHANPAIR(11, 12) = 0x6453, + RF_CHANPAIR(13, 14) = 0x6663, + }, + { /* table 10 */ + RF_CHANPAIR( 1, 2) = 0x666b, + RF_CHANPAIR( 3, 4) = 0x606b, + RF_CHANPAIR( 5, 6) = 0x664b, + RF_CHANPAIR( 7, 8) = 0x644b, + RF_CHANPAIR( 9, 10) = 0x6673, + RF_CHANPAIR(11, 12) = 0x6473, + RF_CHANPAIR(13, 14) = 0x6653, + }, + { /* table 11 */ + RF_CHANPAIR( 1, 2) = 0x665b, + RF_CHANPAIR( 3, 4) = 0x605b, + RF_CHANPAIR( 5, 6) = 0x666b, + RF_CHANPAIR( 7, 8) = 0x646b, + RF_CHANPAIR( 9, 10) = 0x664b, + RF_CHANPAIR(11, 12) = 0x644b, + RF_CHANPAIR(13, 14) = 0x6673, + }, + +}; + +/* The per-channel synth values for autocal. These get written to register 1. */ +static const u16 uw2453_autocal_synth[] = { + RF_CHANNEL( 1) = 0x6847, + RF_CHANNEL( 2) = 0x6847, + RF_CHANNEL( 3) = 0x6867, + RF_CHANNEL( 4) = 0x6867, + RF_CHANNEL( 5) = 0x6867, + RF_CHANNEL( 6) = 0x6867, + RF_CHANNEL( 7) = 0x6857, + RF_CHANNEL( 8) = 0x6857, + RF_CHANNEL( 9) = 0x6857, + RF_CHANNEL(10) = 0x6857, + RF_CHANNEL(11) = 0x6877, + RF_CHANNEL(12) = 0x6877, + RF_CHANNEL(13) = 0x6877, + RF_CHANNEL(14) = 0x684f, +}; + +/* The VCO configuration for autocal (all channels) */ +static const u16 UW2453_AUTOCAL_VCO_CFG = 0x6662; + +/* TX gain settings. The array index corresponds to the TX power integration + * values found in the EEPROM. The values get written to register 7. */ +static u32 uw2453_txgain[] = { + [0x00] = 0x0e313, + [0x01] = 0x0fb13, + [0x02] = 0x0e093, + [0x03] = 0x0f893, + [0x04] = 0x0ea93, + [0x05] = 0x1f093, + [0x06] = 0x1f493, + [0x07] = 0x1f693, + [0x08] = 0x1f393, + [0x09] = 0x1f35b, + [0x0a] = 0x1e6db, + [0x0b] = 0x1ff3f, + [0x0c] = 0x1ffff, + [0x0d] = 0x361d7, + [0x0e] = 0x37fbf, + [0x0f] = 0x3ff8b, + [0x10] = 0x3ff33, + [0x11] = 0x3fb3f, + [0x12] = 0x3ffff, +}; + +/* RF-specific structure */ +struct uw2453_priv { + /* index into synth/VCO config tables where PLL lock was found + * -1 means autocal */ + int config; +}; + +#define UW2453_PRIV(rf) ((struct uw2453_priv *) (rf)->priv) + +static int uw2453_synth_set_channel(struct zd_chip *chip, int channel, + bool autocal) +{ + int r; + int idx = channel - 1; + u32 val; + + if (autocal) + val = UW2453_REGWRITE(1, uw2453_autocal_synth[idx]); + else + val = UW2453_REGWRITE(1, uw2453_std_synth[idx]); + + r = zd_rfwrite_locked(chip, val, RF_RV_BITS); + if (r) + return r; + + return zd_rfwrite_locked(chip, + UW2453_REGWRITE(2, uw2453_synth_divide[idx]), RF_RV_BITS); +} + +static int uw2453_write_vco_cfg(struct zd_chip *chip, u16 value) +{ + /* vendor driver always sets these upper bits even though the specs say + * they are reserved */ + u32 val = 0x40000 | value; + return zd_rfwrite_locked(chip, UW2453_REGWRITE(3, val), RF_RV_BITS); +} + +static int uw2453_init_mode(struct zd_chip *chip) +{ + static const u32 rv[] = { + UW2453_REGWRITE(0, 0x25f98), /* enter IDLE mode */ + UW2453_REGWRITE(0, 0x25f9a), /* enter CAL_VCO mode */ + UW2453_REGWRITE(0, 0x25f94), /* enter RX/TX mode */ + UW2453_REGWRITE(0, 0x27fd4), /* power down RSSI circuit */ + }; + + return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); +} + +static int uw2453_set_tx_gain_level(struct zd_chip *chip, int channel) +{ + u8 int_value = chip->pwr_int_values[channel - 1]; + + if (int_value >= ARRAY_SIZE(uw2453_txgain)) { + dev_dbg_f(zd_chip_dev(chip), "can't configure TX gain for " + "int value %x on channel %d\n", int_value, channel); + return 0; + } + + return zd_rfwrite_locked(chip, + UW2453_REGWRITE(7, uw2453_txgain[int_value]), RF_RV_BITS); +} + +static int uw2453_init_hw(struct zd_rf *rf) +{ + int i, r; + int found_config = -1; + u16 intr_status; + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { + { CR10, 0x89 }, { CR15, 0x20 }, + { CR17, 0x28 }, /* 6112 no change */ + { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 }, + { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 }, + { CR33, 0x28 }, { CR34, 0x30 }, + { CR35, 0x43 }, /* 6112 3e->43 */ + { CR41, 0x24 }, { CR44, 0x32 }, + { CR46, 0x92 }, /* 6112 96->92 */ + { CR47, 0x1e }, + { CR48, 0x04 }, /* 5602 Roger */ + { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 }, + { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, + { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d }, + { CR99, 0x28 }, { CR100, 0x02 }, + { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ + { CR102, 0x27 }, + { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */ + { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ + { CR109, 0x13 }, + { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ + { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 }, + { CR114, 0x23 }, /* 6221 27->23 */ + { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ + { CR116, 0x24 }, /* 6220 1c->24 */ + { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ + { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ + { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ + { CR120, 0x4f }, + { CR121, 0x1f }, /* 6220 4f->1f */ + { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad }, + { CR126, 0x6c }, { CR127, 0x03 }, + { CR128, 0x14 }, /* 6302 12->11 */ + { CR129, 0x12 }, /* 6301 10->0f */ + { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 }, + { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff }, + { CR253, 0xff }, + }; + + static const u32 rv[] = { + UW2453_REGWRITE(4, 0x2b), /* configure reciever gain */ + UW2453_REGWRITE(5, 0x19e4f), /* configure transmitter gain */ + UW2453_REGWRITE(6, 0xf81ad), /* enable RX/TX filter tuning */ + UW2453_REGWRITE(7, 0x3fffe), /* disable TX gain in test mode */ + + /* enter CAL_FIL mode, TX gain set by registers, RX gain set by pins, + * RSSI circuit powered down, reduced RSSI range */ + UW2453_REGWRITE(0, 0x25f9c), /* 5d01 cal_fil */ + + /* synthesizer configuration for channel 1 */ + UW2453_REGWRITE(1, 0x47), + UW2453_REGWRITE(2, 0x999), + + /* disable manual VCO band selection */ + UW2453_REGWRITE(3, 0x7602), + + /* enable manual VCO band selection, configure current level */ + UW2453_REGWRITE(3, 0x46063), + }; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) + return r; + + r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); + if (r) + return r; + + r = uw2453_init_mode(chip); + if (r) + return r; + + /* Try all standard VCO configuration settings on channel 1 */ + for (i = 0; i < ARRAY_SIZE(uw2453_std_vco_cfg) - 1; i++) { + /* Configure synthesizer for channel 1 */ + r = uw2453_synth_set_channel(chip, 1, false); + if (r) + return r; + + /* Write VCO config */ + r = uw2453_write_vco_cfg(chip, uw2453_std_vco_cfg[i][0]); + if (r) + return r; + + /* ack interrupt event */ + r = zd_iowrite16_locked(chip, 0x0f, UW2453_INTR_REG); + if (r) + return r; + + /* check interrupt status */ + r = zd_ioread16_locked(chip, &intr_status, UW2453_INTR_REG); + if (r) + return r; + + if (!intr_status & 0xf) { + dev_dbg_f(zd_chip_dev(chip), + "PLL locked on configuration %d\n", i); + found_config = i; + break; + } + } + + if (found_config == -1) { + /* autocal */ + dev_dbg_f(zd_chip_dev(chip), + "PLL did not lock, using autocal\n"); + + r = uw2453_synth_set_channel(chip, 1, true); + if (r) + return r; + + r = uw2453_write_vco_cfg(chip, UW2453_AUTOCAL_VCO_CFG); + if (r) + return r; + } + + /* To match the vendor driver behaviour, we use the configuration after + * the one that produced a lock. */ + UW2453_PRIV(rf)->config = found_config + 1; + + return zd_iowrite16_locked(chip, 0x06, CR203); +} + +static int uw2453_set_channel(struct zd_rf *rf, u8 channel) +{ + int r; + u16 vco_cfg; + int config = UW2453_PRIV(rf)->config; + bool autocal = (config == -1); + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { + { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, + { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, + }; + + r = uw2453_synth_set_channel(chip, channel, autocal); + if (r) + return r; + + if (autocal) + vco_cfg = UW2453_AUTOCAL_VCO_CFG; + else + vco_cfg = uw2453_std_vco_cfg[config][CHAN_TO_PAIRIDX(channel)]; + + r = uw2453_write_vco_cfg(chip, vco_cfg); + if (r) + return r; + + r = uw2453_init_mode(chip); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) + return r; + + r = uw2453_set_tx_gain_level(chip, channel); + if (r) + return r; + + return zd_iowrite16_locked(chip, 0x06, CR203); +} + +static int uw2453_switch_radio_on(struct zd_rf *rf) +{ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + struct zd_ioreq16 ioreqs[] = { + { CR11, 0x00 }, { CR251, 0x3f }, + }; + + /* enter RXTX mode */ + r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f94), RF_RV_BITS); + if (r) + return r; + + if (zd_chip_is_zd1211b(chip)) + ioreqs[1].value = 0x7f; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int uw2453_switch_radio_off(struct zd_rf *rf) +{ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { + { CR11, 0x04 }, { CR251, 0x2f }, + }; + + /* enter IDLE mode */ + /* FIXME: shouldn't we go to SLEEP? sent email to zydas */ + r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f90), RF_RV_BITS); + if (r) + return r; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static void uw2453_clear(struct zd_rf *rf) +{ + kfree(rf->priv); +} + +int zd_rf_init_uw2453(struct zd_rf *rf) +{ + rf->init_hw = uw2453_init_hw; + rf->set_channel = uw2453_set_channel; + rf->switch_radio_on = uw2453_switch_radio_on; + rf->switch_radio_off = uw2453_switch_radio_off; + rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->clear = uw2453_clear; + /* we have our own TX integration code */ + rf->update_channel_int = 0; + + rf->priv = kmalloc(sizeof(struct uw2453_priv), GFP_KERNEL); + if (rf->priv == NULL) + return -ENOMEM; + + return 0; +} + diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 8459549d0ce..a9c339ef116 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -15,7 +15,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <asm/unaligned.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> @@ -26,6 +25,7 @@ #include <linux/usb.h> #include <linux/workqueue.h> #include <net/ieee80211.h> +#include <asm/unaligned.h> #include "zd_def.h" #include "zd_netdev.h" @@ -54,6 +54,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, @@ -70,6 +71,9 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, @@ -194,26 +198,27 @@ static u16 get_word(const void *data, u16 offset) return le16_to_cpu(p[offset]); } -static char *get_fw_name(char *buffer, size_t size, u8 device_type, +static char *get_fw_name(struct zd_usb *usb, char *buffer, size_t size, const char* postfix) { scnprintf(buffer, size, "%s%s", - device_type == DEVICE_ZD1211B ? + usb->is_zd1211b ? FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX, postfix); return buffer; } -static int handle_version_mismatch(struct usb_device *udev, u8 device_type, +static int handle_version_mismatch(struct zd_usb *usb, const struct firmware *ub_fw) { + struct usb_device *udev = zd_usb_to_usbdev(usb); const struct firmware *ur_fw = NULL; int offset; int r = 0; char fw_name[128]; r = request_fw_file(&ur_fw, - get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"), + get_fw_name(usb, fw_name, sizeof(fw_name), "ur"), &udev->dev); if (r) goto error; @@ -236,11 +241,12 @@ error: return r; } -static int upload_firmware(struct usb_device *udev, u8 device_type) +static int upload_firmware(struct zd_usb *usb) { int r; u16 fw_bcdDevice; u16 bcdDevice; + struct usb_device *udev = zd_usb_to_usbdev(usb); const struct firmware *ub_fw = NULL; const struct firmware *uph_fw = NULL; char fw_name[128]; @@ -248,7 +254,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) bcdDevice = get_bcdDevice(udev); r = request_fw_file(&ub_fw, - get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"), + get_fw_name(usb, fw_name, sizeof(fw_name), "ub"), &udev->dev); if (r) goto error; @@ -263,7 +269,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) dev_warn(&udev->dev, "device has old bootcode, please " "report success or failure\n"); - r = handle_version_mismatch(udev, device_type, ub_fw); + r = handle_version_mismatch(usb, ub_fw); if (r) goto error; } else { @@ -274,7 +280,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) r = request_fw_file(&uph_fw, - get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"), + get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"), &udev->dev); if (r) goto error; @@ -293,6 +299,30 @@ error: return r; } +/* Read data from device address space using "firmware interface" which does + * not require firmware to be loaded. */ +int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) +{ + int r; + struct usb_device *udev = zd_usb_to_usbdev(usb); + + r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, + data, len, 5000); + if (r < 0) { + dev_err(&udev->dev, + "read over firmware interface failed: %d\n", r); + return r; + } else if (r != len) { + dev_err(&udev->dev, + "incomplete read over firmware interface: %d/%d\n", + r, len); + return -EIO; + } + + return 0; +} + #define urb_dev(urb) (&(urb)->dev->dev) static inline void handle_regs_int(struct urb *urb) @@ -919,9 +949,42 @@ static int eject_installer(struct usb_interface *intf) return 0; } +int zd_usb_init_hw(struct zd_usb *usb) +{ + int r; + struct zd_mac *mac = zd_usb_to_mac(usb); + + dev_dbg_f(zd_usb_dev(usb), "\n"); + + r = upload_firmware(usb); + if (r) { + dev_err(zd_usb_dev(usb), + "couldn't load firmware. Error number %d\n", r); + return r; + } + + r = usb_reset_configuration(zd_usb_to_usbdev(usb)); + if (r) { + dev_dbg_f(zd_usb_dev(usb), + "couldn't reset configuration. Error number %d\n", r); + return r; + } + + r = zd_mac_init_hw(mac); + if (r) { + dev_dbg_f(zd_usb_dev(usb), + "couldn't initialize mac. Error number %d\n", r); + return r; + } + + usb->initialized = 1; + return 0; +} + static int probe(struct usb_interface *intf, const struct usb_device_id *id) { int r; + struct zd_usb *usb; struct usb_device *udev = interface_to_usbdev(intf); struct net_device *netdev = NULL; @@ -949,26 +1012,10 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } - r = upload_firmware(udev, id->driver_info); - if (r) { - dev_err(&intf->dev, - "couldn't load firmware. Error number %d\n", r); - goto error; - } + usb = &zd_netdev_mac(netdev)->chip.usb; + usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0; - r = usb_reset_configuration(udev); - if (r) { - dev_dbg_f(&intf->dev, - "couldn't reset configuration. Error number %d\n", r); - goto error; - } - - /* At this point the interrupt endpoint is not generally enabled. We - * save the USB bandwidth until the network device is opened. But - * notify that the initialization of the MAC will require the - * interrupts to be temporary enabled. - */ - r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info); + r = zd_mac_preinit_hw(zd_netdev_mac(netdev)); if (r) { dev_dbg_f(&intf->dev, "couldn't initialize mac. Error number %d\n", r); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 506ea6a7439..961a7a12ad6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -188,6 +188,7 @@ struct zd_usb { struct zd_usb_rx rx; struct zd_usb_tx tx; struct usb_interface *intf; + u8 is_zd1211b:1, initialized:1; }; #define zd_usb_dev(usb) (&usb->intf->dev) @@ -236,6 +237,8 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits); +int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len); + extern struct workqueue_struct *zd_workqueue; #endif /* _ZD_USB_H */ |