📄 wl3501_cs.c
字号:
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, .spy_offset = offsetof(struct wl3501_card, spy_data),};/** * 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 dev_link_t *wl3501_attach(void){ client_reg_t client_reg; dev_link_t *link; struct net_device *dev; int ret; /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(*link), GFP_KERNEL); if (!link) goto out; memset(link, 0, sizeof(struct dev_link_t)); /* The io structure describes IO port mapping */ link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = 5; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = wl3501_interrupt; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->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; dev->get_wireless_stats = wl3501_get_wireless_stats; dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def; SET_ETHTOOL_OPS(dev, &ops); netif_stop_queue(dev); link->priv = link->irq.Instance = dev; /* Register with Card Services */ link->next = wl3501_dev_list; wl3501_dev_list = link; client_reg.dev_info = &wl3501_dev_info; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = wl3501_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); if (ret) { cs_error(link->handle, RegisterClient, ret); wl3501_detach(link); link = NULL; }out: return link;out_link: kfree(link); link = NULL; goto out;}#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 void wl3501_config(dev_link_t *link){ tuple_t tuple; cisparse_t parse; client_handle_t handle = link->handle; 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(handle, &tuple)); tuple.TupleData = bf; tuple.TupleDataMax = sizeof(bf); tuple.TupleOffset = 0; CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; /* 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->handle, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { cs_error(link->handle, 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->handle, &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->handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; SET_NETDEV_DEV(dev, &handle_to_dev(handle)); 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. */ link->dev = &this->node; link->state &= ~DEV_CONFIG_PENDING; 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); goto out;cs_failed: cs_error(link->handle, last_fn, last_ret);failed: wl3501_release(link);out: return;}/** * 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(dev_link_t *link){ struct net_device *dev = link->priv; /* Unlink the device chain */ if (link->dev) { unregister_netdev(dev); link->dev = NULL; } /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG;}/** * wl3501_event - The card status event handler * @event - event * @pri - priority * @args - arguments for this event * * The card status event handler. Mostly, this schedules other stuff to run * after an event is received. A CARD_REMOVAL event also sets some flags to * discourage the net drivers from trying to talk to the card any more. * * When a CARD_REMOVAL event is received, we immediately set a flag to block * future accesses to this device. All the functions that actually access the * device should check this flag to make sure the card is still present. */static int wl3501_event(event_t event, int pri, event_callback_args_t *args){ dev_link_t *link = args->client_data; struct net_device *dev = link->priv; switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { while (link->open > 0) wl3501_close(dev); netif_device_detach(dev); wl3501_release(link); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; wl3501_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) netif_device_detach(dev); pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { wl3501_reset(dev); netif_device_attach(dev); } } break; } return 0;}static struct pcmcia_driver wl3501_driver = { .owner = THIS_MODULE, .drv = { .name = "wl3501_cs", }, .attach = wl3501_attach, .detach = wl3501_detach,};static int __init wl3501_init_module(void){ return pcmcia_register_driver(&wl3501_driver);}static void __exit wl3501_exit_module(void){ dprintk(0, ": unloading"); pcmcia_unregister_driver(&wl3501_driver); BUG_ON(wl3501_dev_list != NULL);}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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -