wl3501_cs.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,165 行 · 第 1/4 页
C
2,165 行
if (!wl3501_esbq_confirm(this)) goto free; wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); switch (sig_id) { case WL3501_SIG_DEAUTH_IND: case WL3501_SIG_DISASSOC_IND: case WL3501_SIG_ALARM: wl3501_alarm_interrupt(dev, this); break; case WL3501_SIG_MD_CONFIRM: wl3501_md_confirm_interrupt(dev, this, addr); break; case WL3501_SIG_MD_IND: wl3501_md_ind_interrupt(dev, this, addr); break; case WL3501_SIG_GET_CONFIRM: wl3501_get_confirm_interrupt(this, addr, &this->sig_get_confirm, sizeof(this->sig_get_confirm)); break; case WL3501_SIG_PWR_MGMT_CONFIRM: wl3501_get_confirm_interrupt(this, addr, &this->sig_pwr_mgmt_confirm, sizeof(this->sig_pwr_mgmt_confirm)); break; case WL3501_SIG_START_CONFIRM: wl3501_start_confirm_interrupt(dev, this, addr); break; case WL3501_SIG_SCAN_CONFIRM: wl3501_mgmt_scan_confirm(this, addr); break; case WL3501_SIG_JOIN_CONFIRM: wl3501_mgmt_join_confirm(dev, addr); break; case WL3501_SIG_ASSOC_CONFIRM: wl3501_assoc_confirm_interrupt(dev, addr); break; case WL3501_SIG_AUTH_CONFIRM: wl3501_auth_confirm_interrupt(this, addr); break; case WL3501_SIG_RESYNC_CONFIRM: wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ break; } wl3501_esbq_confirm_done(this); morepkts = 1; /* free request if necessary */free: wl3501_esbq_req_free(this); if (morepkts) goto loop;}static inline void wl3501_ack_interrupt(struct wl3501_card *this){ wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR);}/** * wl3501_interrupt - Hardware interrupt from card. * @irq - Interrupt number * @dev_id - net_device * @regs - registers * * We must acknowledge the interrupt as soon as possible, and block the * interrupt from the same card immediately to prevent re-entry. * * Before accessing the Control_Status_Block, we must lock SUTRO first. * On the other hand, to prevent SUTRO from malfunctioning, we must * unlock the SUTRO as soon as possible. */static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_id; struct wl3501_card *this; int handled = 1; if (!dev) goto unknown; this = dev->priv; spin_lock(&this->lock); wl3501_ack_interrupt(this); wl3501_block_interrupt(this); wl3501_rx_interrupt(dev); wl3501_unblock_interrupt(this); spin_unlock(&this->lock);out: return IRQ_RETVAL(handled);unknown: handled = 0; printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq); goto out;}static int wl3501_reset_board(struct wl3501_card *this){ u8 tmp = 0; int i, rc = 0; /* Coreset */ wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); /* Reset SRAM 0x480 to zero */ wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); /* Start up */ wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); WL3501_NOPLOOP(1024 * 50); wl3501_unblock_interrupt(this); /* acme: was commented */ /* Polling Self_Test_Status */ for (i = 0; i < 10000; i++) { wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); if (tmp == 'W') { /* firmware complete all test successfully */ tmp = 'A'; wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); goto out; } WL3501_NOPLOOP(10); } printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__); rc = -ENODEV;out: return rc;}static int wl3501_init_firmware(struct wl3501_card *this){ u16 ptr, next; int rc = wl3501_reset_board(this); if (rc) goto fail; this->card_name[0] = '\0'; wl3501_get_from_wla(this, 0x1a00, this->card_name, sizeof(this->card_name)); this->card_name[sizeof(this->card_name) - 1] = '\0'; this->firmware_date[0] = '\0'; wl3501_get_from_wla(this, 0x1a40, this->firmware_date, sizeof(this->firmware_date)); this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; /* Switch to SRAM Page 0 */ wl3501_switch_page(this, WL3501_BSS_SPAGE0); /* Read parameter from card */ wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; this->esbq_req_end += this->esbq_req_start; this->esbq_confirm = this->esbq_confirm_start; this->esbq_confirm_end += this->esbq_confirm_start; /* Initial Tx Buffer */ this->tx_buffer_cnt = 1; ptr = this->tx_buffer_head; next = ptr + WL3501_BLKSZ; while ((next - this->tx_buffer_head) < this->tx_buffer_size) { this->tx_buffer_cnt++; wl3501_set_to_wla(this, ptr, &next, sizeof(next)); ptr = next; next = ptr + WL3501_BLKSZ; } rc = 0; next = 0; wl3501_set_to_wla(this, ptr, &next, sizeof(next)); this->tx_buffer_tail = ptr;out: return rc;fail: printk(KERN_WARNING "%s: failed!\n", __FUNCTION__); goto out;}static int wl3501_close(struct net_device *dev){ struct wl3501_card *this = dev->priv; int rc = -ENODEV; unsigned long flags; struct pcmcia_device *link; link = this->p_dev; spin_lock_irqsave(&this->lock, flags); link->open--; /* Stop wl3501_hard_start_xmit() from now on */ netif_stop_queue(dev); wl3501_ack_interrupt(this); /* Mask interrupts from the SUTRO */ wl3501_block_interrupt(this); rc = 0; printk(KERN_INFO "%s: WL3501 closed\n", dev->name); spin_unlock_irqrestore(&this->lock, flags); return rc;}/** * wl3501_reset - Reset the SUTRO. * @dev - network device * * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() * and wl3501_open() again, but I wouldn't like to free_irq() when the driver * is running. It seems to be dangerous. */static int wl3501_reset(struct net_device *dev){ struct wl3501_card *this = dev->priv; int rc = -ENODEV; wl3501_block_interrupt(this); if (wl3501_init_firmware(this)) { printk(KERN_WARNING "%s: Can't initialize Firmware!\n", dev->name); /* Free IRQ, and mark IRQ as unused */ free_irq(dev->irq, dev); goto out; } /* * Queue has to be started only when the Card is Started */ netif_stop_queue(dev); this->adhoc_times = 0; wl3501_ack_interrupt(this); wl3501_unblock_interrupt(this); wl3501_mgmt_scan(this, 100); dprintk(1, "%s: device reset", dev->name); rc = 0;out: return rc;}static void wl3501_tx_timeout(struct net_device *dev){ struct wl3501_card *this = dev->priv; struct net_device_stats *stats = &this->stats; unsigned long flags; int rc; stats->tx_errors++; spin_lock_irqsave(&this->lock, flags); rc = wl3501_reset(dev); spin_unlock_irqrestore(&this->lock, flags); if (rc) printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", dev->name, rc); else { dev->trans_start = jiffies; netif_wake_queue(dev); }}/* * Return : 0 - OK * 1 - Could not transmit (dev_queue_xmit will queue it) * and try to sent it later */static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){ int enabled, rc; struct wl3501_card *this = dev->priv; unsigned long flags; spin_lock_irqsave(&this->lock, flags); enabled = wl3501_block_interrupt(this); dev->trans_start = jiffies; rc = wl3501_send_pkt(this, skb->data, skb->len); if (enabled) wl3501_unblock_interrupt(this); if (rc) { ++this->stats.tx_dropped; netif_stop_queue(dev); } else { ++this->stats.tx_packets; this->stats.tx_bytes += skb->len; kfree_skb(skb); if (this->tx_buffer_cnt < 2) netif_stop_queue(dev); } spin_unlock_irqrestore(&this->lock, flags); return rc;}static int wl3501_open(struct net_device *dev){ int rc = -ENODEV; struct wl3501_card *this = dev->priv; unsigned long flags; struct pcmcia_device *link; link = this->p_dev; spin_lock_irqsave(&this->lock, flags); if (!pcmcia_dev_present(link)) goto out; netif_device_attach(dev); link->open++; /* Initial WL3501 firmware */ dprintk(1, "%s: Initialize WL3501 firmware...", dev->name); if (wl3501_init_firmware(this)) goto fail; /* Initial device variables */ this->adhoc_times = 0; /* Acknowledge Interrupt, for cleaning last state */ wl3501_ack_interrupt(this); /* Enable interrupt from card after all */ wl3501_unblock_interrupt(this); wl3501_mgmt_scan(this, 100); rc = 0; dprintk(1, "%s: WL3501 opened", dev->name); printk(KERN_INFO "%s: Card Name: %s\n" "%s: Firmware Date: %s\n", dev->name, this->card_name, dev->name, this->firmware_date);out: spin_unlock_irqrestore(&this->lock, flags); return rc;fail: printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); goto out;}static struct net_device_stats *wl3501_get_stats(struct net_device *dev){ struct wl3501_card *this = dev->priv; return &this->stats;}static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev){ struct wl3501_card *this = dev->priv; struct iw_statistics *wstats = &this->wstats; u32 value; /* size checked: it is u32 */ memset(wstats, 0, sizeof(*wstats)); wstats->status = netif_running(dev); if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, &value, sizeof(value))) wstats->discard.code += value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, &value, sizeof(value))) wstats->discard.code += value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, &value, sizeof(value))) wstats->discard.code += value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, &value, sizeof(value))) wstats->discard.retries = value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, &value, sizeof(value))) wstats->discard.misc += value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, &value, sizeof(value))) wstats->discard.misc += value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, &value, sizeof(value))) wstats->discard.misc += value; if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, &value, sizeof(value))) wstats->discard.misc += value; return wstats;}static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));}static struct ethtool_ops ops = { .get_drvinfo = wl3501_get_drvinfo};/** * wl3501_detach - deletes a driver "instance" * @link - FILL_IN * * This deletes a driver "instance". The device is de-registered with Card * Services. If it has been released, all local data structures are freed. * Otherwise, the structures will be freed when the device is released. */static void wl3501_detach(struct pcmcia_device *link){ struct net_device *dev = link->priv; /* If the device is currently configured and active, we won't actually * delete it yet. Instead, it is marked so that when the release() * function is called, that will trigger a proper detach(). */ while (link->open > 0) wl3501_close(dev); netif_device_detach(dev); wl3501_release(link); if (link->priv) free_netdev(link->priv); return;}static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ strlcpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); return 0;}static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; int channel = wrqu->freq.m; int rc = -EINVAL; if (iw_valid_channel(this->reg_domain, channel)) { this->chan = channel; rc = wl3501_reset(dev); } return rc;}static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000; wrqu->freq.e = 1; return 0;}static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ int rc = -EINVAL; if (wrqu->mode == IW_MODE_INFRA || wrqu->mode == IW_MODE_ADHOC || wrqu->mode == IW_MODE_AUTO) { struct wl3501_card *this = dev->priv; this->net_type = wrqu->mode; rc = wl3501_reset(dev); } return rc;}static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; wrqu->mode = this->net_type; return 0;}static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; wrqu->sens.value = this->rssi; wrqu->sens.disabled = !wrqu->sens.value; wrqu->sens.fixed = 1; return 0;}static int wl3501_get_range(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct iw_range *range = (struct iw_range *)extra; /* Set the length (very important for backward compatibility) */ wrqu->data.length = sizeof(*range); /* Set all the info we don't care or don't know about to zero */ memset(range, 0, sizeof(*range)); /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 1; range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ /* FIXME: study the code to fill in more fields... */ return 0;}static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; int rc = -EINVAL; /* FIXME: we support other ARPHRDs...*/ if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) goto out; if (!memcmp(bcast, wrqu->ap_addr.sa_data, ETH_ALEN)) { /* FIXME: rescan? */ } else memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); /* FIXME: rescan? deassoc & scan? */ rc = 0;out: return rc;}static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct wl3501_card *this = dev->priv; wrqu->ap_addr.sa_family = ARPHRD_ETHER; memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); return 0;}static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ /* * FIXME: trigger scanning with a reset, yes, I'm lazy */ return wl3501_reset(dev);}static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?