📄 main.c
字号:
INIT_LIST_HEAD(&adapter->cmdfreeq); INIT_LIST_HEAD(&adapter->cmdpendingq); spin_lock_init(&adapter->driver_lock); init_waitqueue_head(&adapter->cmd_pending); adapter->nr_cmd_pending = 0; /* Allocate the command buffers */ if (libertas_allocate_cmd_buffer(priv)) { lbs_pr_err("Out of memory allocating command buffers\n"); ret = -1; }out: return ret;}static void libertas_free_adapter(wlan_private * priv){ wlan_adapter *adapter = priv->adapter; if (!adapter) { lbs_deb_fw("why double free adapter?\n"); return; } lbs_deb_fw("free command buffer\n"); libertas_free_cmd_buffer(priv); lbs_deb_fw("free command_timer\n"); del_timer(&adapter->command_timer); lbs_deb_fw("free scan results table\n"); kfree(adapter->networks); adapter->networks = NULL; /* Free the adapter object itself */ lbs_deb_fw("free adapter\n"); kfree(adapter); priv->adapter = NULL;}/** * @brief This function adds the card. it will probe the * card, allocate the wlan_priv and initialize the device. * * @param card A pointer to card * @return A pointer to wlan_private structure */wlan_private *libertas_add_card(void *card, struct device *dmdev){ struct net_device *dev = NULL; wlan_private *priv = NULL; lbs_deb_enter(LBS_DEB_NET); /* Allocate an Ethernet device and register it */ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { lbs_pr_err("init ethX device failed\n"); goto done; } priv = dev->priv; /* allocate buffer for wlan_adapter */ if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { lbs_pr_err("allocate buffer for wlan_adapter failed\n"); goto err_kzalloc; } if (libertas_init_adapter(priv)) { lbs_pr_err("failed to initialize adapter structure.\n"); goto err_init_adapter; } priv->dev = dev; priv->card = card; priv->mesh_open = 0; priv->infra_open = 0; priv->hotplug_device = dmdev; /* Setup the OS Interface to our functions */ dev->open = libertas_open; dev->hard_start_xmit = libertas_pre_start_xmit; dev->stop = libertas_close; dev->set_mac_address = libertas_set_mac_address; dev->tx_timeout = libertas_tx_timeout; dev->get_stats = libertas_get_stats; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &libertas_ethtool_ops;#ifdef WIRELESS_EXT dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;#endif dev->flags |= IFF_BROADCAST | IFF_MULTICAST; dev->set_multicast_list = libertas_set_multicast_list; SET_NETDEV_DEV(dev, dmdev); priv->rtap_net_dev = NULL; if (device_create_file(dmdev, &dev_attr_libertas_rtap)) goto err_init_adapter; lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); if (IS_ERR(priv->main_thread)) { lbs_deb_thread("Error creating main thread.\n"); goto err_kthread_run; } priv->work_thread = create_singlethread_workqueue("libertas_worker"); INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); INIT_WORK(&priv->sync_channel, libertas_sync_channel); goto done;err_kthread_run: device_remove_file(dmdev, &dev_attr_libertas_rtap);err_init_adapter: libertas_free_adapter(priv);err_kzalloc: free_netdev(dev); priv = NULL;done: lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv); return priv;}EXPORT_SYMBOL_GPL(libertas_add_card);int libertas_remove_card(wlan_private *priv){ wlan_adapter *adapter = priv->adapter; struct net_device *dev = priv->dev; union iwreq_data wrqu; lbs_deb_enter(LBS_DEB_MAIN); libertas_remove_rtap(priv); dev = priv->dev; device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); cancel_delayed_work(&priv->scan_work); cancel_delayed_work(&priv->assoc_work); destroy_workqueue(priv->work_thread); if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { adapter->psmode = WLAN802_11POWERMODECAM; libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); /* Stop the thread servicing the interrupts */ adapter->surpriseremoved = 1; kthread_stop(priv->main_thread); libertas_free_adapter(priv); priv->dev = NULL; free_netdev(dev); lbs_deb_leave(LBS_DEB_MAIN); return 0;}EXPORT_SYMBOL_GPL(libertas_remove_card);int libertas_start_card(wlan_private *priv){ struct net_device *dev = priv->dev; int ret = -1; lbs_deb_enter(LBS_DEB_MAIN); /* poke the firmware */ ret = wlan_setup_firmware(priv); if (ret) goto done; /* init 802.11d */ libertas_init_11d(priv); if (register_netdev(dev)) { lbs_pr_err("cannot register ethX device\n"); goto done; } libertas_debugfs_init_one(priv, dev); lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); ret = 0;done: lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret;}EXPORT_SYMBOL_GPL(libertas_start_card);int libertas_stop_card(wlan_private *priv){ struct net_device *dev = priv->dev; int ret = -1; struct cmd_ctrl_node *cmdnode; unsigned long flags; lbs_deb_enter(LBS_DEB_MAIN); netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); libertas_debugfs_remove_one(priv); /* Flush pending command nodes */ spin_lock_irqsave(&priv->adapter->driver_lock, flags); list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { cmdnode->cmdwaitqwoken = 1; wake_up_interruptible(&cmdnode->cmdwait_q); } spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); unregister_netdev(dev); lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret;}EXPORT_SYMBOL_GPL(libertas_stop_card);/** * @brief This function adds mshX interface * * @param priv A pointer to the wlan_private structure * @return 0 if successful, -X otherwise */int libertas_add_mesh(wlan_private *priv, struct device *dev){ struct net_device *mesh_dev = NULL; int ret = 0; lbs_deb_enter(LBS_DEB_MESH); /* Allocate a virtual mesh device */ if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) { lbs_deb_mesh("init mshX device failed\n"); ret = -ENOMEM; goto done; } mesh_dev->priv = priv; priv->mesh_dev = mesh_dev; mesh_dev->open = libertas_mesh_open; mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit; mesh_dev->stop = libertas_mesh_close; mesh_dev->get_stats = libertas_get_stats; mesh_dev->set_mac_address = libertas_set_mac_address; mesh_dev->ethtool_ops = &libertas_ethtool_ops; memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, sizeof(priv->dev->dev_addr)); SET_NETDEV_DEV(priv->mesh_dev, dev);#ifdef WIRELESS_EXT mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;#endif /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { lbs_pr_err("cannot register mshX virtual interface\n"); goto err_free; } ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); if (ret) goto err_unregister; /* Everything successful */ ret = 0; goto done;err_unregister: unregister_netdev(mesh_dev);err_free: free_netdev(mesh_dev);done: lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret;}EXPORT_SYMBOL_GPL(libertas_add_mesh);void libertas_remove_mesh(wlan_private *priv){ struct net_device *mesh_dev; lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; mesh_dev = priv->mesh_dev; netif_stop_queue(mesh_dev); netif_carrier_off(priv->mesh_dev); sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); unregister_netdev(mesh_dev); priv->mesh_dev = NULL ; free_netdev(mesh_dev);out: lbs_deb_leave(LBS_DEB_MAIN);}EXPORT_SYMBOL_GPL(libertas_remove_mesh);/** * @brief This function finds the CFP in * region_cfp_table based on region and band parameter. * * @param region The region code * @param band The band * @param cfp_no A pointer to CFP number * @return A pointer to CFP */struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no){ int i, end; lbs_deb_enter(LBS_DEB_MAIN); end = ARRAY_SIZE(region_cfp_table); for (i = 0; i < end ; i++) { lbs_deb_main("region_cfp_table[i].region=%d\n", region_cfp_table[i].region); if (region_cfp_table[i].region == region) { *cfp_no = region_cfp_table[i].cfp_no_BG; lbs_deb_leave(LBS_DEB_MAIN); return region_cfp_table[i].cfp_BG; } } lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); return NULL;}int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band){ wlan_adapter *adapter = priv->adapter; int ret = 0; int i = 0; struct chan_freq_power *cfp; int cfp_no; lbs_deb_enter(LBS_DEB_MAIN); memset(adapter->region_channel, 0, sizeof(adapter->region_channel)); { cfp = libertas_get_region_cfp_table(region, band, &cfp_no); if (cfp != NULL) { adapter->region_channel[i].nrcfp = cfp_no; adapter->region_channel[i].CFP = cfp; } else { lbs_deb_main("wrong region code %#x in band B/G\n", region); ret = -1; goto out; } adapter->region_channel[i].valid = 1; adapter->region_channel[i].region = region; adapter->region_channel[i].band = band; i++; }out: lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret;}/** * @brief This function handles the interrupt. it will change PS * state if applicable. it will wake up main_thread to handle * the interrupt event as well. * * @param dev A pointer to net_device structure * @return n/a */void libertas_interrupt(struct net_device *dev){ wlan_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_THREAD); lbs_deb_thread("libertas_interrupt: intcounter=%d\n", priv->adapter->intcounter); priv->adapter->intcounter++; if (priv->adapter->psstate == PS_STATE_SLEEP) { priv->adapter->psstate = PS_STATE_AWAKE; netif_wake_queue(dev); if (priv->mesh_dev) netif_wake_queue(priv->mesh_dev); } wake_up_interruptible(&priv->waitq); lbs_deb_leave(LBS_DEB_THREAD);}EXPORT_SYMBOL_GPL(libertas_interrupt);int libertas_reset_device(wlan_private *priv){ int ret; lbs_deb_enter(LBS_DEB_MAIN); ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, CMD_ACT_HALT, 0, 0, NULL); msleep_interruptible(10); lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret;}EXPORT_SYMBOL_GPL(libertas_reset_device);static int libertas_init_module(void){ lbs_deb_enter(LBS_DEB_MAIN); libertas_debugfs_init(); lbs_deb_leave(LBS_DEB_MAIN); return 0;}static void libertas_exit_module(void){ lbs_deb_enter(LBS_DEB_MAIN); libertas_debugfs_remove(); lbs_deb_leave(LBS_DEB_MAIN);}/* * rtap interface support fuctions */static int libertas_rtap_open(struct net_device *dev){ netif_carrier_off(dev); netif_stop_queue(dev); return 0;}static int libertas_rtap_stop(struct net_device *dev){ return 0;}static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){ netif_stop_queue(dev); return -EOPNOTSUPP;}static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev){ wlan_private *priv = dev->priv; return &priv->ieee->stats;}void libertas_remove_rtap(wlan_private *priv){ if (priv->rtap_net_dev == NULL) return; unregister_netdev(priv->rtap_net_dev); free_ieee80211(priv->rtap_net_dev); priv->rtap_net_dev = NULL;}int libertas_add_rtap(wlan_private *priv){ int rc = 0; if (priv->rtap_net_dev) return -EPERM; priv->rtap_net_dev = alloc_ieee80211(0); if (priv->rtap_net_dev == NULL) return -ENOMEM; priv->ieee = netdev_priv(priv->rtap_net_dev); strcpy(priv->rtap_net_dev->name, "rtap%d"); priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; priv->rtap_net_dev->open = libertas_rtap_open; priv->rtap_net_dev->stop = libertas_rtap_stop; priv->rtap_net_dev->get_stats = libertas_rtap_get_stats; priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit; priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list; priv->rtap_net_dev->priv = priv; priv->ieee->iw_mode = IW_MODE_MONITOR; rc = register_netdev(priv->rtap_net_dev); if (rc) { free_ieee80211(priv->rtap_net_dev); priv->rtap_net_dev = NULL; return rc; } return 0;}module_init(libertas_init_module);module_exit(libertas_exit_module);MODULE_DESCRIPTION("Libertas WLAN Driver Library");MODULE_AUTHOR("Marvell International Ltd.");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -