⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 adm8211.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	priv->mode = IEEE80211_IF_TYPE_MNTR;	adm8211_update_mode(dev);	ADM8211_CSR_WRITE(RDR, 0);	adm8211_set_interval(dev, 100, 10);	return 0;fail:	return retval;}static void adm8211_stop(struct ieee80211_hw *dev){	struct adm8211_priv *priv = dev->priv;	priv->mode = IEEE80211_IF_TYPE_INVALID;	priv->nar = 0;	ADM8211_CSR_WRITE(NAR, 0);	ADM8211_CSR_WRITE(IER, 0);	ADM8211_CSR_READ(NAR);	free_irq(priv->pdev->irq, dev);	adm8211_free_rings(dev);}static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,				   int plcp_signal, int short_preamble){	/* Alternative calculation from NetBSD: *//* IEEE 802.11b durations for DSSS PHY in microseconds */#define IEEE80211_DUR_DS_LONG_PREAMBLE	144#define IEEE80211_DUR_DS_SHORT_PREAMBLE	72#define IEEE80211_DUR_DS_FAST_PLCPHDR	24#define IEEE80211_DUR_DS_SLOW_PLCPHDR	48#define IEEE80211_DUR_DS_SLOW_ACK	112#define IEEE80211_DUR_DS_FAST_ACK	56#define IEEE80211_DUR_DS_SLOW_CTS	112#define IEEE80211_DUR_DS_FAST_CTS	56#define IEEE80211_DUR_DS_SLOT		20#define IEEE80211_DUR_DS_SIFS		10	int remainder;	*dur = (80 * (24 + payload_len) + plcp_signal - 1)		/ plcp_signal;	if (plcp_signal <= PLCP_SIGNAL_2M)		/* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */		*dur += 3 * (IEEE80211_DUR_DS_SIFS +			     IEEE80211_DUR_DS_SHORT_PREAMBLE +			     IEEE80211_DUR_DS_FAST_PLCPHDR) +			     IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK;	else		/* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */		*dur += 3 * (IEEE80211_DUR_DS_SIFS +			     IEEE80211_DUR_DS_SHORT_PREAMBLE +			     IEEE80211_DUR_DS_FAST_PLCPHDR) +			     IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK;	/* lengthen duration if long preamble */	if (!short_preamble)		*dur +=	3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -			     IEEE80211_DUR_DS_SHORT_PREAMBLE) +			3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -			     IEEE80211_DUR_DS_FAST_PLCPHDR);	*plcp = (80 * len) / plcp_signal;	remainder = (80 * len) % plcp_signal;	if (plcp_signal == PLCP_SIGNAL_11M &&	    remainder <= 30 && remainder > 0)		*plcp = (*plcp | 0x8000) + 1;	else if (remainder)		(*plcp)++;}/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,			   u16 plcp_signal,			   struct ieee80211_tx_control *control,			   size_t hdrlen){	struct adm8211_priv *priv = dev->priv;	unsigned long flags;	dma_addr_t mapping;	unsigned int entry;	u32 flag;	mapping = pci_map_single(priv->pdev, skb->data, skb->len,				 PCI_DMA_TODEVICE);	spin_lock_irqsave(&priv->lock, flags);	if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)		flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;	else		flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;	if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2)		ieee80211_stop_queue(dev, 0);	entry = priv->cur_tx % priv->tx_ring_size;	priv->tx_buffers[entry].skb = skb;	priv->tx_buffers[entry].mapping = mapping;	memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));	priv->tx_buffers[entry].hdrlen = hdrlen;	priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);	if (entry == priv->tx_ring_size - 1)		flag |= TDES1_CONTROL_TER;	priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len);	/* Set TX rate (SIGNAL field in PLCP PPDU format) */	flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */;	priv->tx_ring[entry].status = cpu_to_le32(flag);	priv->cur_tx++;	spin_unlock_irqrestore(&priv->lock, flags);	/* Trigger transmit poll */	ADM8211_CSR_WRITE(TDR, 0);}/* Put adm8211_tx_hdr on skb and transmit */static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,		      struct ieee80211_tx_control *control){	struct adm8211_tx_hdr *txhdr;	u16 fc;	size_t payload_len, hdrlen;	int plcp, dur, len, plcp_signal, short_preamble;	struct ieee80211_hdr *hdr;	if (control->tx_rate < 0) {		short_preamble = 1;		plcp_signal = -control->tx_rate;	} else {		short_preamble = 0;		plcp_signal = control->tx_rate;	}	hdr = (struct ieee80211_hdr *)skb->data;	fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;	hdrlen = ieee80211_get_hdrlen(fc);	memcpy(skb->cb, skb->data, hdrlen);	hdr = (struct ieee80211_hdr *)skb->cb;	skb_pull(skb, hdrlen);	payload_len = skb->len;	txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));	memset(txhdr, 0, sizeof(*txhdr));	memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN);	txhdr->signal = plcp_signal;	txhdr->frame_body_size = cpu_to_le16(payload_len);	txhdr->frame_control = hdr->frame_control;	len = hdrlen + payload_len + FCS_LEN;	if (fc & IEEE80211_FCTL_PROTECTED)		len += 8;	txhdr->frag = cpu_to_le16(0x0FFF);	adm8211_calc_durations(&dur, &plcp, payload_len,			       len, plcp_signal, short_preamble);	txhdr->plcp_frag_head_len = cpu_to_le16(plcp);	txhdr->plcp_frag_tail_len = cpu_to_le16(plcp);	txhdr->dur_frag_head = cpu_to_le16(dur);	txhdr->dur_frag_tail = cpu_to_le16(dur);	txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER);	if (short_preamble)		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);	if (fc & IEEE80211_FCTL_PROTECTED)		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);	txhdr->retry_limit = control->retry_limit;	adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);	return NETDEV_TX_OK;}static int adm8211_alloc_rings(struct ieee80211_hw *dev){	struct adm8211_priv *priv = dev->priv;	unsigned int ring_size;	priv->rx_buffers = kmalloc(sizeof(*priv->rx_buffers) * priv->rx_ring_size +				   sizeof(*priv->tx_buffers) * priv->tx_ring_size, GFP_KERNEL);	if (!priv->rx_buffers)		return -ENOMEM;	priv->tx_buffers = (void *)priv->rx_buffers +			   sizeof(*priv->rx_buffers) * priv->rx_ring_size;	/* Allocate TX/RX descriptors */	ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +		    sizeof(struct adm8211_desc) * priv->tx_ring_size;	priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size,					     &priv->rx_ring_dma);	if (!priv->rx_ring) {		kfree(priv->rx_buffers);		priv->rx_buffers = NULL;		priv->tx_buffers = NULL;		return -ENOMEM;	}	priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring +						priv->rx_ring_size);	priv->tx_ring_dma = priv->rx_ring_dma +			    sizeof(struct adm8211_desc) * priv->rx_ring_size;	return 0;}static const struct ieee80211_ops adm8211_ops = {	.tx			= adm8211_tx,	.start			= adm8211_start,	.stop			= adm8211_stop,	.add_interface		= adm8211_add_interface,	.remove_interface	= adm8211_remove_interface,	.config			= adm8211_config,	.config_interface	= adm8211_config_interface,	.configure_filter	= adm8211_configure_filter,	.get_stats		= adm8211_get_stats,	.get_tx_stats		= adm8211_get_tx_stats,	.get_tsf		= adm8211_get_tsft};static int __devinit adm8211_probe(struct pci_dev *pdev,				   const struct pci_device_id *id){	struct ieee80211_hw *dev;	struct adm8211_priv *priv;	unsigned long mem_addr, mem_len;	unsigned int io_addr, io_len;	int err;	u32 reg;	u8 perm_addr[ETH_ALEN];	DECLARE_MAC_BUF(mac);	err = pci_enable_device(pdev);	if (err) {		printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n",		       pci_name(pdev));		return err;	}	io_addr = pci_resource_start(pdev, 0);	io_len = pci_resource_len(pdev, 0);	mem_addr = pci_resource_start(pdev, 1);	mem_len = pci_resource_len(pdev, 1);	if (io_len < 256 || mem_len < 1024) {		printk(KERN_ERR "%s (adm8211): Too short PCI resources\n",		       pci_name(pdev));		goto err_disable_pdev;	}	/* check signature */	pci_read_config_dword(pdev, 0x80 /* CR32 */, &reg);	if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) {		printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n",		       pci_name(pdev), reg);		goto err_disable_pdev;	}	err = pci_request_regions(pdev, "adm8211");	if (err) {		printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n",		       pci_name(pdev));		return err; /* someone else grabbed it? don't disable it */	}	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||	    pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {		printk(KERN_ERR "%s (adm8211): No suitable DMA available\n",		       pci_name(pdev));		goto err_free_reg;	}	pci_set_master(pdev);	dev = ieee80211_alloc_hw(sizeof(*priv), &adm8211_ops);	if (!dev) {		printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n",		       pci_name(pdev));		err = -ENOMEM;		goto err_free_reg;	}	priv = dev->priv;	priv->pdev = pdev;	spin_lock_init(&priv->lock);	SET_IEEE80211_DEV(dev, &pdev->dev);	pci_set_drvdata(pdev, dev);	priv->map = pci_iomap(pdev, 1, mem_len);	if (!priv->map)		priv->map = pci_iomap(pdev, 0, io_len);	if (!priv->map) {		printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",		       pci_name(pdev));		goto err_free_dev;	}	priv->rx_ring_size = rx_ring_size;	priv->tx_ring_size = tx_ring_size;	if (adm8211_alloc_rings(dev)) {		printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n",		       pci_name(pdev));		goto err_iounmap;	}	*(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0));	*(u16 *)&perm_addr[4] =		le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF);	if (!is_valid_ether_addr(perm_addr)) {		printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n",		       pci_name(pdev));		random_ether_addr(perm_addr);	}	SET_IEEE80211_PERM_ADDR(dev, perm_addr);	dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);	dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;	/* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */	dev->channel_change_time = 1000;	dev->max_rssi = 100;	/* FIXME: find better value */	priv->modes[0].mode = MODE_IEEE80211B;	/* channel info filled in by adm8211_read_eeprom */	memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));	priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);	priv->modes[0].rates = priv->rates;	dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */	priv->retry_limit = 3;	priv->ant_power = 0x40;	priv->tx_power = 0x40;	priv->lpf_cutoff = 0xFF;	priv->lnags_threshold = 0xFF;	priv->mode = IEEE80211_IF_TYPE_INVALID;	/* Power-on issue. EEPROM won't read correctly without */	if (pdev->revision >= ADM8211_REV_BA) {		ADM8211_CSR_WRITE(FRCTL, 0);		ADM8211_CSR_READ(FRCTL);		ADM8211_CSR_WRITE(FRCTL, 1);		ADM8211_CSR_READ(FRCTL);		msleep(100);	}	err = adm8211_read_eeprom(dev);	if (err) {		printk(KERN_ERR "%s (adm8211): Can't alloc eeprom buffer\n",		       pci_name(pdev));		goto err_free_desc;	}	priv->channel = priv->modes[0].channels[0].chan;	err = ieee80211_register_hwmode(dev, &priv->modes[0]);	if (err) {		printk(KERN_ERR "%s (adm8211): Can't register hwmode\n",		       pci_name(pdev));		goto err_free_desc;	}	err = ieee80211_register_hw(dev);	if (err) {		printk(KERN_ERR "%s (adm8211): Cannot register device\n",		       pci_name(pdev));		goto err_free_desc;	}	printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n",	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),	       pdev->revision);	return 0; err_free_desc:	pci_free_consistent(pdev,			    sizeof(struct adm8211_desc) * priv->rx_ring_size +			    sizeof(struct adm8211_desc) * priv->tx_ring_size,			    priv->rx_ring, priv->rx_ring_dma);	kfree(priv->rx_buffers); err_iounmap:	pci_iounmap(pdev, priv->map); err_free_dev:	pci_set_drvdata(pdev, NULL);	ieee80211_free_hw(dev); err_free_reg:	pci_release_regions(pdev); err_disable_pdev:	pci_disable_device(pdev);	return err;}static void __devexit adm8211_remove(struct pci_dev *pdev){	struct ieee80211_hw *dev = pci_get_drvdata(pdev);	struct adm8211_priv *priv;	if (!dev)		return;	ieee80211_unregister_hw(dev);	priv = dev->priv;	pci_free_consistent(pdev,			    sizeof(struct adm8211_desc) * priv->rx_ring_size +			    sizeof(struct adm8211_desc) * priv->tx_ring_size,			    priv->rx_ring, priv->rx_ring_dma);	kfree(priv->rx_buffers);	kfree(priv->eeprom);	pci_iounmap(pdev, priv->map);	pci_release_regions(pdev);	pci_disable_device(pdev);	ieee80211_free_hw(dev);}#ifdef CONFIG_PMstatic int adm8211_suspend(struct pci_dev *pdev, pm_message_t state){	struct ieee80211_hw *dev = pci_get_drvdata(pdev);	struct adm8211_priv *priv = dev->priv;	if (priv->mode != IEEE80211_IF_TYPE_INVALID) {		ieee80211_stop_queues(dev);		adm8211_stop(dev);	}	pci_save_state(pdev);	pci_set_power_state(pdev, pci_choose_state(pdev, state));	return 0;}static int adm8211_resume(struct pci_dev *pdev){	struct ieee80211_hw *dev = pci_get_drvdata(pdev);	struct adm8211_priv *priv = dev->priv;	pci_set_power_state(pdev, PCI_D0);	pci_restore_state(pdev);	if (priv->mode != IEEE80211_IF_TYPE_INVALID) {		adm8211_start(dev);		ieee80211_start_queues(dev);	}	return 0;}#endif /* CONFIG_PM */MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table);/* TODO: implement enable_wake */static struct pci_driver adm8211_driver = {	.name		= "adm8211",	.id_table	= adm8211_pci_id_table,	.probe		= adm8211_probe,	.remove		= __devexit_p(adm8211_remove),#ifdef CONFIG_PM	.suspend	= adm8211_suspend,	.resume		= adm8211_resume,#endif /* CONFIG_PM */};static int __init adm8211_init(void){	return pci_register_driver(&adm8211_driver);}static void __exit adm8211_exit(void){	pci_unregister_driver(&adm8211_driver);}module_init(adm8211_init);module_exit(adm8211_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -