wl3501_cs.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,165 行 · 第 1/4 页
C
2,165 行
union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; int i; char *current_ev = extra; struct iw_event iwe; for (i = 0; i < this->bss_cnt; ++i) { iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN); current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; iwe.u.data.length = this->bss_set[i].ssid.el.len; current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, this->bss_set[i].ssid.essid); iwe.cmd = SIOCGIWMODE; iwe.u.mode = this->bss_set[i].bss_type; current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = this->bss_set[i].ds_pset.chan; iwe.u.freq.e = 0; current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); iwe.cmd = SIOCGIWENCODE; if (this->bss_set[i].cap_info & WL3501_MGMT_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); } /* Length of data */ wrqu->data.length = (current_ev - extra); wrqu->data.flags = 0; /* FIXME: set properly these flags */ return 0;}static int wl3501_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; if (wrqu->data.flags) { iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, extra, wrqu->data.length); } else { /* We accept any ESSID */ iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, "ANY", 3); } return wl3501_reset(dev);}static int wl3501_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; unsigned long flags; spin_lock_irqsave(&this->lock, flags); wrqu->essid.flags = 1; wrqu->essid.length = this->essid.el.len; memcpy(extra, this->essid.essid, this->essid.el.len); spin_unlock_irqrestore(&this->lock, flags); return 0;}static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; if (wrqu->data.length > sizeof(this->nick)) return -E2BIG; strlcpy(this->nick, extra, wrqu->data.length); return 0;}static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; strlcpy(extra, this->nick, 32); wrqu->data.length = strlen(extra); return 0;}static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ /* * FIXME: have to see from where to get this info, perhaps this card * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most * common with the Planet Access Points. -acme */ wrqu->bitrate.value = 2000000; wrqu->bitrate.fixed = 1; return 0;}static int wl3501_get_rts_threshold(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ u16 threshold; /* size checked: it is u16 */ struct wl3501_card *this = dev->priv; int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, &threshold, sizeof(threshold)); if (!rc) { wrqu->rts.value = threshold; wrqu->rts.disabled = threshold >= 2347; wrqu->rts.fixed = 1; } return rc;}static int wl3501_get_frag_threshold(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ u16 threshold; /* size checked: it is u16 */ struct wl3501_card *this = dev->priv; int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, &threshold, sizeof(threshold)); if (!rc) { wrqu->frag.value = threshold; wrqu->frag.disabled = threshold >= 2346; wrqu->frag.fixed = 1; } return rc;}static int wl3501_get_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ u16 txpow; struct wl3501_card *this = dev->priv; int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, &txpow, sizeof(txpow)); if (!rc) { wrqu->txpower.value = txpow; wrqu->txpower.disabled = 0; /* * From the MIB values I think this can be configurable, * as it lists several tx power levels -acme */ wrqu->txpower.fixed = 0; wrqu->txpower.flags = IW_TXPOW_MWATT; } return rc;}static int wl3501_get_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ u8 retry; /* size checked: it is u8 */ struct wl3501_card *this = dev->priv; int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_LONG_RETRY_LIMIT, &retry, sizeof(retry)); if (rc) goto out; if (wrqu->retry.flags & IW_RETRY_MAX) { wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; goto set_value; } rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, &retry, sizeof(retry)); if (rc) goto out; wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;set_value: wrqu->retry.value = retry; wrqu->retry.disabled = 0;out: return rc;}static int wl3501_get_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ u8 implemented, restricted, keys[100], len_keys, tocopy; struct wl3501_card *this = dev->priv; int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, &implemented, sizeof(implemented)); if (rc) goto out; if (!implemented) { wrqu->encoding.flags = IW_ENCODE_DISABLED; goto out; } rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, &restricted, sizeof(restricted)); if (rc) goto out; wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN; rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, &len_keys, sizeof(len_keys)); if (rc) goto out; rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, keys, len_keys); if (rc) goto out; tocopy = min_t(u8, len_keys, wrqu->encoding.length); tocopy = min_t(u8, tocopy, 100); wrqu->encoding.length = tocopy; memset(extra, 0, tocopy); memcpy(extra, keys, tocopy);out: return rc;}static int wl3501_get_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ u8 pwr_state; struct wl3501_card *this = dev->priv; int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_CURRENT_PWR_STATE, &pwr_state, sizeof(pwr_state)); if (rc) goto out; wrqu->power.disabled = !pwr_state; wrqu->power.flags = IW_POWER_ON;out: return rc;}static const iw_handler wl3501_handler[] = { [SIOCGIWNAME - SIOCIWFIRST] = wl3501_get_name, [SIOCSIWFREQ - SIOCIWFIRST] = wl3501_set_freq, [SIOCGIWFREQ - SIOCIWFIRST] = wl3501_get_freq, [SIOCSIWMODE - SIOCIWFIRST] = wl3501_set_mode, [SIOCGIWMODE - SIOCIWFIRST] = wl3501_get_mode, [SIOCGIWSENS - SIOCIWFIRST] = wl3501_get_sens, [SIOCGIWRANGE - SIOCIWFIRST] = wl3501_get_range, [SIOCSIWSPY - SIOCIWFIRST] = iw_handler_set_spy, [SIOCGIWSPY - SIOCIWFIRST] = iw_handler_get_spy, [SIOCSIWTHRSPY - SIOCIWFIRST] = iw_handler_set_thrspy, [SIOCGIWTHRSPY - SIOCIWFIRST] = iw_handler_get_thrspy, [SIOCSIWAP - SIOCIWFIRST] = wl3501_set_wap, [SIOCGIWAP - SIOCIWFIRST] = wl3501_get_wap, [SIOCSIWSCAN - SIOCIWFIRST] = wl3501_set_scan, [SIOCGIWSCAN - SIOCIWFIRST] = wl3501_get_scan, [SIOCSIWESSID - SIOCIWFIRST] = wl3501_set_essid, [SIOCGIWESSID - SIOCIWFIRST] = wl3501_get_essid, [SIOCSIWNICKN - SIOCIWFIRST] = wl3501_set_nick, [SIOCGIWNICKN - SIOCIWFIRST] = wl3501_get_nick, [SIOCGIWRATE - SIOCIWFIRST] = wl3501_get_rate, [SIOCGIWRTS - SIOCIWFIRST] = wl3501_get_rts_threshold, [SIOCGIWFRAG - SIOCIWFIRST] = wl3501_get_frag_threshold, [SIOCGIWTXPOW - SIOCIWFIRST] = wl3501_get_txpow, [SIOCGIWRETRY - SIOCIWFIRST] = wl3501_get_retry, [SIOCGIWENCODE - SIOCIWFIRST] = wl3501_get_encode, [SIOCGIWPOWER - SIOCIWFIRST] = wl3501_get_power,};static const struct iw_handler_def wl3501_handler_def = { .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler), .standard = (iw_handler *)wl3501_handler, .get_wireless_stats = wl3501_get_wireless_stats,};/** * wl3501_attach - creates an "instance" of the driver * * Creates an "instance" of the driver, allocating local data structures for * one device. The device is registered with Card Services. * * The dev_link structure is initialized, but we don't actually configure the * card at this point -- we wait until we receive a card insertion event. */static int wl3501_probe(struct pcmcia_device *p_dev){ struct net_device *dev; struct wl3501_card *this; /* The io structure describes IO port mapping */ p_dev->io.NumPorts1 = 16; p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; p_dev->io.IOAddrLines = 5; /* Interrupt setup */ p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = wl3501_interrupt; /* General socket configuration */ p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; p_dev->conf.ConfigIndex = 1; p_dev->conf.Present = PRESENT_OPTION; dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) goto out_link; dev->open = wl3501_open; dev->stop = wl3501_close; dev->hard_start_xmit = wl3501_hard_start_xmit; dev->tx_timeout = wl3501_tx_timeout; dev->watchdog_timeo = 5 * HZ; dev->get_stats = wl3501_get_stats; this = dev->priv; this->wireless_data.spy_data = &this->spy_data; this->p_dev = p_dev; dev->wireless_data = &this->wireless_data; dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def; SET_ETHTOOL_OPS(dev, &ops); netif_stop_queue(dev); p_dev->priv = p_dev->irq.Instance = dev; return wl3501_config(p_dev);out_link: return -ENOMEM;}#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)/** * wl3501_config - configure the PCMCIA socket and make eth device available * @link - FILL_IN * * wl3501_config() is scheduled to run after a CARD_INSERTION event is * received, to configure the PCMCIA socket, and to make the ethernet device * available to the system. */static int wl3501_config(struct pcmcia_device *link){ tuple_t tuple; cisparse_t parse; struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; unsigned char bf[64]; struct wl3501_card *this; /* This reads the card's CONFIG tuple to find its config registers. */ tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = bf; tuple.TupleDataMax = sizeof(bf); tuple.TupleOffset = 0; CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- * see the serial driver for an example. */ for (j = 0x280; j < 0x400; j += 0x20) { /* The '^0x300' is so that we probe 0x300-0x3ff first, then * 0x200-0x2ff, and so on, because this seems safer */ link->io.BasePort1 = j; link->io.BasePort2 = link->io.BasePort1 + 0x10; i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { cs_error(link, RequestIO, i); goto failed; } /* Now allocate an interrupt line. Note that this does not actually * assign a handler to the interrupt. */ CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O * windows and the interrupt mapping. */ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev)) { printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); goto failed; } SET_MODULE_OWNER(dev); this = dev->priv; /* * At this point, the dev_node_t structure(s) should be initialized and * arranged in a linked list at link->dev_node. */ link->dev_node = &this->node; this->base_addr = dev->base_addr; if (!wl3501_get_flash_mac_addr(this)) { printk(KERN_WARNING "%s: Cant read MAC addr in flash ROM?\n", dev->name); goto failed; } strcpy(this->node.dev_name, dev->name); /* print probe information */ printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:", dev->name, this->base_addr, (int)dev->irq); for (i = 0; i < 6; i++) { dev->dev_addr[i] = ((char *)&this->mac_addr)[i]; printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); } printk("\n"); /* * Initialize card parameters - added by jss */ this->net_type = IW_MODE_INFRA; this->bss_cnt = 0; this->join_sta_bss = 0; this->adhoc_times = 0; iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, "ANY", 3); this->card_name[0] = '\0'; this->firmware_date[0] = '\0'; this->rssi = 255; this->chan = iw_default_channel(this->reg_domain); strlcpy(this->nick, "Planet WL3501", sizeof(this->nick)); spin_lock_init(&this->lock); init_waitqueue_head(&this->wait); netif_start_queue(dev); return 0;cs_failed: cs_error(link, last_fn, last_ret);failed: wl3501_release(link); return -ENODEV;}/** * wl3501_release - unregister the net, release PCMCIA configuration * @arg - link * * After a card is removed, wl3501_release() will unregister the net device, * and release the PCMCIA configuration. If the device is still open, this * will be postponed until it is closed. */static void wl3501_release(struct pcmcia_device *link){ struct net_device *dev = link->priv; /* Unlink the device chain */ if (link->dev_node) unregister_netdev(dev); pcmcia_disable_device(link);}static int wl3501_suspend(struct pcmcia_device *link){ struct net_device *dev = link->priv; wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); if (link->open) netif_device_detach(dev); return 0;}static int wl3501_resume(struct pcmcia_device *link){ struct net_device *dev = link->priv; wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); if (link->open) { wl3501_reset(dev); netif_device_attach(dev); } return 0;}static struct pcmcia_device_id wl3501_ids[] = { PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), PCMCIA_DEVICE_NULL};MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);static struct pcmcia_driver wl3501_driver = { .owner = THIS_MODULE, .drv = { .name = "wl3501_cs", }, .probe = wl3501_probe, .remove = wl3501_detach, .id_table = wl3501_ids, .suspend = wl3501_suspend, .resume = wl3501_resume,};static int __init wl3501_init_module(void){ return pcmcia_register_driver(&wl3501_driver);}static void __exit wl3501_exit_module(void){ pcmcia_unregister_driver(&wl3501_driver);}module_init(wl3501_init_module);module_exit(wl3501_exit_module);MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, " "Arnaldo Carvalho de Melo <acme@conectiva.com.br>," "Gustavo Niemeyer <niemeyer@conectiva.com>");MODULE_DESCRIPTION("Planet wl3501 wireless driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?