2 * Airgo MIMO wireless driver
4 * Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
6 * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
7 * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/init.h>
15 #include <linux/etherdevice.h>
16 #include <linux/pci.h>
17 #include <linux/delay.h>
24 MODULE_AUTHOR("Li YanBo <dreamfly281@gmail.com>");
25 MODULE_DESCRIPTION("Airgo MIMO PCI wireless driver");
26 MODULE_LICENSE("GPL");
28 static struct pci_device_id agnx_pci_id_tbl
[] __devinitdata
= {
29 { PCI_DEVICE(0x17cb, 0x0001) }, /* Beklin F5d8010, Netgear WGM511 etc */
30 { PCI_DEVICE(0x17cb, 0x0002) }, /* Netgear Wpnt511 */
34 MODULE_DEVICE_TABLE(pci
, agnx_pci_id_tbl
);
37 static inline void agnx_interrupt_ack(struct agnx_priv
*priv
, u32
*reason
)
39 void __iomem
*ctl
= priv
->ctl
;
42 if (*reason
& AGNX_STAT_RX
) {
43 /* Mark complete RX */
44 reg
= ioread32(ctl
+ AGNX_CIR_RXCTL
);
46 iowrite32(reg
, ctl
+ AGNX_CIR_RXCTL
);
47 /* disable Rx interrupt */
49 if (*reason
& AGNX_STAT_TX
) {
50 reg
= ioread32(ctl
+ AGNX_CIR_TXDCTL
);
52 iowrite32(reg
, ctl
+ AGNX_CIR_TXDCTL
);
53 *reason
|= AGNX_STAT_TXD
;
55 reg
= ioread32(ctl
+ AGNX_CIR_TXMCTL
);
57 iowrite32(reg
, ctl
+ AGNX_CIR_TXMCTL
);
58 *reason
|= AGNX_STAT_TXM
;
61 /* if (*reason & AGNX_STAT_X) {
62 reg = ioread32(ctl + AGNX_INT_STAT);
63 iowrite32(reg, ctl + AGNX_INT_STAT);
64 /* FIXME reinit interrupt mask *\/
65 reg = 0xc390bf9 & ~IRQ_TX_BEACON;
66 reg &= ~IRQ_TX_DISABLE;
67 iowrite32(reg, ctl + AGNX_INT_MASK);
68 iowrite32(0x800, ctl + AGNX_CIR_BLKCTL);
70 } /* agnx_interrupt_ack */
72 static irqreturn_t
agnx_interrupt_handler(int irq
, void *dev_id
)
74 struct ieee80211_hw
*dev
= dev_id
;
75 struct agnx_priv
*priv
= dev
->priv
;
76 void __iomem
*ctl
= priv
->ctl
;
77 irqreturn_t ret
= IRQ_NONE
;
80 spin_lock(&priv
->lock
);
82 /* printk(KERN_ERR PFX "Get a interrupt %s\n", __func__); */
84 if (priv
->init_status
!= AGNX_START
)
87 /* FiXME Here has no lock, Is this will lead to race? */
88 irq_reason
= ioread32(ctl
+ AGNX_CIR_BLKCTL
);
89 if (!(irq_reason
& 0x7))
93 priv
->irq_status
= ioread32(ctl
+ AGNX_INT_STAT
);
95 /* printk(PFX "Interrupt reason is 0x%x\n", irq_reason); */
96 /* Make sure the txm and txd flags don't conflict with other unknown
97 interrupt flag, maybe is not necessary */
100 disable_rx_interrupt(priv
);
101 /* TODO Make sure the card finished initialized */
102 agnx_interrupt_ack(priv
, &irq_reason
);
104 if (irq_reason
& AGNX_STAT_RX
)
106 if (irq_reason
& AGNX_STAT_TXD
)
107 handle_txd_irq(priv
);
108 if (irq_reason
& AGNX_STAT_TXM
)
109 handle_txm_irq(priv
);
110 if (irq_reason
& AGNX_STAT_X
)
111 handle_other_irq(priv
);
113 enable_rx_interrupt(priv
);
115 spin_unlock(&priv
->lock
);
117 } /* agnx_interrupt_handler */
121 static int agnx_tx(struct ieee80211_hw
*dev
, struct sk_buff
*skb
)
124 return _agnx_tx(dev
->priv
, skb
);
128 static int agnx_get_mac_address(struct agnx_priv
*priv
)
130 void __iomem
*ctl
= priv
->ctl
;
134 /* Attention! directly read the MAC or other date from EEPROM will
135 lead to cardbus(WGM511) lock up when write to PM PLL register */
136 reg
= agnx_read32(ctl
, 0x3544);
138 reg
= agnx_read32(ctl
, 0x354c);
140 /* Get the mac address */
141 reg
= agnx_read32(ctl
, 0x3544);
145 reg
= cpu_to_le32(reg
);
146 priv
->mac_addr
[0] = ((u8
*)®
)[2];
147 priv
->mac_addr
[1] = ((u8
*)®
)[3];
148 reg
= agnx_read32(ctl
, 0x3548);
150 *((u32
*)(priv
->mac_addr
+ 2)) = cpu_to_le32(reg
);
152 if (!is_valid_ether_addr(priv
->mac_addr
)) {
153 DECLARE_MAC_BUF(mbuf
);
154 printk(KERN_WARNING PFX
"read mac %s\n", print_mac(mbuf
, priv
->mac_addr
));
155 printk(KERN_WARNING PFX
"Invalid hwaddr! Using random hwaddr\n");
156 random_ether_addr(priv
->mac_addr
);
160 } /* agnx_get_mac_address */
162 static int agnx_alloc_rings(struct agnx_priv
*priv
)
167 /* Allocate RX/TXM/TXD rings info */
168 priv
->rx
.size
= AGNX_RX_RING_SIZE
;
169 priv
->txm
.size
= AGNX_TXM_RING_SIZE
;
170 priv
->txd
.size
= AGNX_TXD_RING_SIZE
;
172 len
= priv
->rx
.size
+ priv
->txm
.size
+ priv
->txd
.size
;
174 /* priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL); */
175 priv
->rx
.info
= kzalloc(sizeof(struct agnx_info
) * len
, GFP_ATOMIC
);
178 priv
->txm
.info
= priv
->rx
.info
+ priv
->rx
.size
;
179 priv
->txd
.info
= priv
->txm
.info
+ priv
->txm
.size
;
181 /* Allocate RX/TXM/TXD descriptors */
182 priv
->rx
.desc
= pci_alloc_consistent(priv
->pdev
, sizeof(struct agnx_desc
) * len
,
184 if (!priv
->rx
.desc
) {
185 kfree(priv
->rx
.info
);
189 priv
->txm
.desc
= priv
->rx
.desc
+ priv
->rx
.size
;
190 priv
->txm
.dma
= priv
->rx
.dma
+ sizeof(struct agnx_desc
) * priv
->rx
.size
;
191 priv
->txd
.desc
= priv
->txm
.desc
+ priv
->txm
.size
;
192 priv
->txd
.dma
= priv
->txm
.dma
+ sizeof(struct agnx_desc
) * priv
->txm
.size
;
195 } /* agnx_alloc_rings */
197 static void rings_free(struct agnx_priv
*priv
)
199 unsigned int len
= priv
->rx
.size
+ priv
->txm
.size
+ priv
->txd
.size
;
203 spin_lock_irqsave(&priv
->lock
, flags
);
204 kfree(priv
->rx
.info
);
205 pci_free_consistent(priv
->pdev
, sizeof(struct agnx_desc
) * len
,
206 priv
->rx
.desc
, priv
->rx
.dma
);
207 spin_unlock_irqrestore(&priv
->lock
, flags
);
211 static void agnx_periodic_work_handler(struct work_struct
*work
)
213 struct agnx_priv
*priv
= container_of(work
, struct agnx_priv
, periodic_work
.work
);
214 /* unsigned long flags; */
217 /* fixme: using mutex?? */
218 /* spin_lock_irqsave(&priv->lock, flags); */
220 /* TODO Recalibrate*/
221 /* calibrate_oscillator(priv); */
222 /* antenna_calibrate(priv); */
223 /* agnx_send_packet(priv, 997); /
225 /* if (debug == 3) */
226 /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
228 delay
= msecs_to_jiffies(AGNX_PERIODIC_DELAY
);
229 /* delay = round_jiffies(HZ * 15); */
231 queue_delayed_work(priv
->hw
->workqueue
, &priv
->periodic_work
, delay
);
233 /* spin_unlock_irqrestore(&priv->lock, flags); */
237 static int agnx_start(struct ieee80211_hw
*dev
)
239 struct agnx_priv
*priv
= dev
->priv
;
240 /* unsigned long delay; */
244 err
= agnx_alloc_rings(priv
);
246 printk(KERN_ERR PFX
"Can't alloc RX/TXM/TXD rings\n");
249 err
= request_irq(priv
->pdev
->irq
, &agnx_interrupt_handler
,
250 IRQF_SHARED
, "agnx_pci", dev
);
252 printk(KERN_ERR PFX
"Failed to register IRQ handler\n");
265 priv
->init_status
= AGNX_START
;
266 /* INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); */
267 /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
268 /* queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */
273 static void agnx_stop(struct ieee80211_hw
*dev
)
275 struct agnx_priv
*priv
= dev
->priv
;
278 priv
->init_status
= AGNX_STOP
;
279 /* make sure hardware will not generate irq */
281 free_irq(priv
->pdev
->irq
, dev
);
282 flush_workqueue(priv
->hw
->workqueue
);
283 /* cancel_delayed_work_sync(&priv->periodic_work); */
288 static int agnx_config(struct ieee80211_hw
*dev
, u32 changed
)
290 struct agnx_priv
*priv
= dev
->priv
;
291 struct ieee80211_conf
*conf
= &dev
->conf
;
292 int channel
= ieee80211_frequency_to_channel(conf
->channel
->center_freq
);
295 spin_lock(&priv
->lock
);
296 /* FIXME need priv lock? */
297 if (channel
!= priv
->channel
) {
298 priv
->channel
= channel
;
299 agnx_set_channel(priv
, priv
->channel
);
302 spin_unlock(&priv
->lock
);
306 static int agnx_config_interface(struct ieee80211_hw
*dev
,
307 struct ieee80211_vif
*vif
,
308 struct ieee80211_if_conf
*conf
)
310 struct agnx_priv
*priv
= dev
->priv
;
311 void __iomem
*ctl
= priv
->ctl
;
314 spin_lock(&priv
->lock
);
316 if (memcmp(conf
->bssid
, priv
->bssid
, ETH_ALEN
)) {
317 agnx_set_bssid(priv
, conf
->bssid
);
318 memcpy(priv
->bssid
, conf
->bssid
, ETH_ALEN
);
319 hash_write(priv
, conf
->bssid
, BSSID_STAID
);
320 sta_init(priv
, BSSID_STAID
);
322 sta_power_init(priv
, BSSID_STAID
);
323 agnx_write32(ctl
, AGNX_BM_MTSM
, 0xff & ~0x1);
325 spin_unlock(&priv
->lock
);
327 } /* agnx_config_interface */
330 static void agnx_configure_filter(struct ieee80211_hw
*dev
,
331 unsigned int changed_flags
,
332 unsigned int *total_flags
,
333 int mc_count
, struct dev_mc_list
*mclist
)
335 unsigned int new_flags
= 0;
337 *total_flags
= new_flags
;
341 static int agnx_add_interface(struct ieee80211_hw
*dev
,
342 struct ieee80211_if_init_conf
*conf
)
344 struct agnx_priv
*priv
= dev
->priv
;
347 spin_lock(&priv
->lock
);
349 if (priv
->mode
!= NL80211_IFTYPE_MONITOR
)
352 switch (conf
->type
) {
353 case NL80211_IFTYPE_STATION
:
354 priv
->mode
= conf
->type
;
360 spin_unlock(&priv
->lock
);
365 static void agnx_remove_interface(struct ieee80211_hw
*dev
,
366 struct ieee80211_if_init_conf
*conf
)
368 struct agnx_priv
*priv
= dev
->priv
;
372 priv
->mode
= NL80211_IFTYPE_MONITOR
;
375 static int agnx_get_stats(struct ieee80211_hw
*dev
,
376 struct ieee80211_low_level_stats
*stats
)
378 struct agnx_priv
*priv
= dev
->priv
;
380 spin_lock(&priv
->lock
);
382 memcpy(stats
, &priv
->stats
, sizeof(*stats
));
383 spin_unlock(&priv
->lock
);
388 static u64
agnx_get_tsft(struct ieee80211_hw
*dev
)
390 void __iomem
*ctl
= ((struct agnx_priv
*)dev
->priv
)->ctl
;
396 tsftl
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPLO
);
397 tsft
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPHI
);
404 static int agnx_get_tx_stats(struct ieee80211_hw
*dev
,
405 struct ieee80211_tx_queue_stats
*stats
)
407 struct agnx_priv
*priv
= dev
->priv
;
410 /* FIXME now we just using txd queue, but should using txm queue too */
411 stats
[0].len
= (priv
->txd
.idx
- priv
->txd
.idx_sent
) / 2;
412 stats
[0].limit
= priv
->txd
.size
- 2;
413 stats
[0].count
= priv
->txd
.idx
/ 2;
418 static struct ieee80211_ops agnx_ops
= {
422 .add_interface
= agnx_add_interface
,
423 .remove_interface
= agnx_remove_interface
,
424 .config
= agnx_config
,
425 .config_interface
= agnx_config_interface
,
426 .configure_filter
= agnx_configure_filter
,
427 .get_stats
= agnx_get_stats
,
428 .get_tx_stats
= agnx_get_tx_stats
,
429 .get_tsf
= agnx_get_tsft
432 static void __devexit
agnx_pci_remove(struct pci_dev
*pdev
)
434 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
435 struct agnx_priv
*priv
;
441 ieee80211_unregister_hw(dev
);
442 pci_iounmap(pdev
, priv
->ctl
);
443 pci_iounmap(pdev
, priv
->data
);
444 pci_release_regions(pdev
);
445 pci_disable_device(pdev
);
447 ieee80211_free_hw(dev
);
450 static int __devinit
agnx_pci_probe(struct pci_dev
*pdev
,
451 const struct pci_device_id
*id
)
453 struct ieee80211_hw
*dev
;
454 struct agnx_priv
*priv
;
455 u32 mem_addr0
, mem_len0
;
456 u32 mem_addr1
, mem_len1
;
458 DECLARE_MAC_BUF(mac
);
460 err
= pci_enable_device(pdev
);
462 printk(KERN_ERR PFX
"Can't enable new PCI device\n");
466 /* get pci resource */
467 mem_addr0
= pci_resource_start(pdev
, 0);
468 mem_len0
= pci_resource_len(pdev
, 0);
469 mem_addr1
= pci_resource_start(pdev
, 1);
470 mem_len1
= pci_resource_len(pdev
, 1);
471 printk(KERN_DEBUG PFX
"Memaddr0 is %x, length is %x\n", mem_addr0
, mem_len0
);
472 printk(KERN_DEBUG PFX
"Memaddr1 is %x, length is %x\n", mem_addr1
, mem_len1
);
474 err
= pci_request_regions(pdev
, "agnx-pci");
476 printk(KERN_ERR PFX
"Can't obtain PCI resource\n");
480 if (pci_set_dma_mask(pdev
, DMA_BIT_MASK(32)) ||
481 pci_set_consistent_dma_mask(pdev
, DMA_BIT_MASK(32))) {
482 printk(KERN_ERR PFX
"No suitable DMA available\n");
486 pci_set_master(pdev
);
487 printk(KERN_DEBUG PFX
"pdev->irq is %d\n", pdev
->irq
);
489 dev
= ieee80211_alloc_hw(sizeof(*priv
), &agnx_ops
);
491 printk(KERN_ERR PFX
"ieee80211 alloc failed\n");
497 memset(priv
, 0, sizeof(*priv
));
498 priv
->mode
= NL80211_IFTYPE_MONITOR
;
501 spin_lock_init(&priv
->lock
);
502 priv
->init_status
= AGNX_UNINIT
;
504 /* Map mem #1 and #2 */
505 priv
->ctl
= pci_iomap(pdev
, 0, mem_len0
);
506 /* printk(KERN_DEBUG PFX"MEM1 mapped address is 0x%p\n", priv->ctl); */
508 printk(KERN_ERR PFX
"Can't map device memory\n");
511 priv
->data
= pci_iomap(pdev
, 1, mem_len1
);
512 printk(KERN_DEBUG PFX
"MEM2 mapped address is 0x%p\n", priv
->data
);
514 printk(KERN_ERR PFX
"Can't map device memory\n");
518 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &priv
->revid
);
520 priv
->band
.channels
= (struct ieee80211_channel
*)agnx_channels
;
521 priv
->band
.n_channels
= ARRAY_SIZE(agnx_channels
);
522 priv
->band
.bitrates
= (struct ieee80211_rate
*)agnx_rates_80211g
;
523 priv
->band
.n_bitrates
= ARRAY_SIZE(agnx_rates_80211g
);
525 /* Init ieee802.11 dev */
526 SET_IEEE80211_DEV(dev
, &pdev
->dev
);
527 pci_set_drvdata(pdev
, dev
);
528 dev
->extra_tx_headroom
= sizeof(struct agnx_hdr
);
530 /* FIXME It only include FCS in promious mode but not manage mode */
531 /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS; */
532 dev
->channel_change_time
= 5000;
533 dev
->max_signal
= 100;
537 agnx_get_mac_address(priv
);
539 SET_IEEE80211_PERM_ADDR(dev
, priv
->mac_addr
);
542 /* for (i = 1; i < NUM_DRIVE_MODES; i++) { */
543 /* err = ieee80211_register_hwmode(dev, &priv->modes[i]); */
545 /* printk(KERN_ERR PFX "Can't register hwmode\n"); */
546 /* goto err_iounmap; */
551 dev
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &priv
->band
;
553 err
= ieee80211_register_hw(dev
);
555 printk(KERN_ERR PFX
"Can't register hardware\n");
562 printk(PFX
"%s: hwaddr %s, Rev 0x%02x\n", wiphy_name(dev
->wiphy
),
563 print_mac(mac
, dev
->wiphy
->perm_addr
), priv
->revid
);
567 pci_iounmap(pdev
, priv
->data
);
570 pci_iounmap(pdev
, priv
->ctl
);
573 pci_set_drvdata(pdev
, NULL
);
574 ieee80211_free_hw(dev
);
577 pci_release_regions(pdev
);
579 pci_disable_device(pdev
);
581 } /* agnx_pci_probe*/
585 static int agnx_pci_suspend(struct pci_dev
*pdev
, pm_message_t state
)
587 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
590 ieee80211_stop_queues(dev
);
593 pci_save_state(pdev
);
594 pci_set_power_state(pdev
, pci_choose_state(pdev
, state
));
598 static int agnx_pci_resume(struct pci_dev
*pdev
)
600 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
603 pci_set_power_state(pdev
, PCI_D0
);
604 pci_restore_state(pdev
);
607 ieee80211_wake_queues(dev
);
614 #define agnx_pci_suspend NULL
615 #define agnx_pci_resume NULL
617 #endif /* CONFIG_PM */
620 static struct pci_driver agnx_pci_driver
= {
622 .id_table
= agnx_pci_id_tbl
,
623 .probe
= agnx_pci_probe
,
624 .remove
= __devexit_p(agnx_pci_remove
),
625 .suspend
= agnx_pci_suspend
,
626 .resume
= agnx_pci_resume
,
629 static int __init
agnx_pci_init(void)
632 return pci_register_driver(&agnx_pci_driver
);
635 static void __exit
agnx_pci_exit(void)
638 pci_unregister_driver(&agnx_pci_driver
);
642 module_init(agnx_pci_init
);
643 module_exit(agnx_pci_exit
);