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
;
62 if (*reason
& AGNX_STAT_X
) {
63 reg
= ioread32(ctl
+ AGNX_INT_STAT
);
64 iowrite32(reg
, ctl
+ AGNX_INT_STAT
);
65 /* FIXME reinit interrupt mask */
66 reg
= 0xc390bf9 & ~IRQ_TX_BEACON
;
67 reg
&= ~IRQ_TX_DISABLE
;
68 iowrite32(reg
, ctl
+ AGNX_INT_MASK
);
69 iowrite32(0x800, ctl
+ AGNX_CIR_BLKCTL
);
72 } /* agnx_interrupt_ack */
74 static irqreturn_t
agnx_interrupt_handler(int irq
, void *dev_id
)
76 struct ieee80211_hw
*dev
= dev_id
;
77 struct agnx_priv
*priv
= dev
->priv
;
78 void __iomem
*ctl
= priv
->ctl
;
79 irqreturn_t ret
= IRQ_NONE
;
82 spin_lock(&priv
->lock
);
84 /* printk(KERN_ERR PFX "Get a interrupt %s\n", __func__); */
86 if (priv
->init_status
!= AGNX_START
)
89 /* FiXME Here has no lock, Is this will lead to race? */
90 irq_reason
= ioread32(ctl
+ AGNX_CIR_BLKCTL
);
91 if (!(irq_reason
& 0x7))
95 priv
->irq_status
= ioread32(ctl
+ AGNX_INT_STAT
);
97 /* printk(PFX "Interrupt reason is 0x%x\n", irq_reason); */
98 /* Make sure the txm and txd flags don't conflict with other unknown
99 interrupt flag, maybe is not necessary */
102 disable_rx_interrupt(priv
);
103 /* TODO Make sure the card finished initialized */
104 agnx_interrupt_ack(priv
, &irq_reason
);
106 if (irq_reason
& AGNX_STAT_RX
)
108 if (irq_reason
& AGNX_STAT_TXD
)
109 handle_txd_irq(priv
);
110 if (irq_reason
& AGNX_STAT_TXM
)
111 handle_txm_irq(priv
);
112 if (irq_reason
& AGNX_STAT_X
)
113 handle_other_irq(priv
);
115 enable_rx_interrupt(priv
);
117 spin_unlock(&priv
->lock
);
119 } /* agnx_interrupt_handler */
123 static int agnx_tx(struct ieee80211_hw
*dev
, struct sk_buff
*skb
)
126 return _agnx_tx(dev
->priv
, skb
);
130 static int agnx_get_mac_address(struct agnx_priv
*priv
)
132 void __iomem
*ctl
= priv
->ctl
;
136 /* Attention! directly read the MAC or other date from EEPROM will
137 lead to cardbus(WGM511) lock up when write to PM PLL register */
138 reg
= agnx_read32(ctl
, 0x3544);
140 reg
= agnx_read32(ctl
, 0x354c);
142 /* Get the mac address */
143 reg
= agnx_read32(ctl
, 0x3544);
147 reg
= cpu_to_le32(reg
);
148 priv
->mac_addr
[0] = ((u8
*)®
)[2];
149 priv
->mac_addr
[1] = ((u8
*)®
)[3];
150 reg
= agnx_read32(ctl
, 0x3548);
152 *((u32
*)(priv
->mac_addr
+ 2)) = cpu_to_le32(reg
);
154 if (!is_valid_ether_addr(priv
->mac_addr
)) {
155 printk(KERN_WARNING PFX
"read mac %pM\n", priv
->mac_addr
);
156 printk(KERN_WARNING PFX
"Invalid hwaddr! Using random hwaddr\n");
157 random_ether_addr(priv
->mac_addr
);
161 } /* agnx_get_mac_address */
163 static int agnx_alloc_rings(struct agnx_priv
*priv
)
168 /* Allocate RX/TXM/TXD rings info */
169 priv
->rx
.size
= AGNX_RX_RING_SIZE
;
170 priv
->txm
.size
= AGNX_TXM_RING_SIZE
;
171 priv
->txd
.size
= AGNX_TXD_RING_SIZE
;
173 len
= priv
->rx
.size
+ priv
->txm
.size
+ priv
->txd
.size
;
175 /* priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL); */
176 priv
->rx
.info
= kzalloc(sizeof(struct agnx_info
) * len
, GFP_ATOMIC
);
179 priv
->txm
.info
= priv
->rx
.info
+ priv
->rx
.size
;
180 priv
->txd
.info
= priv
->txm
.info
+ priv
->txm
.size
;
182 /* Allocate RX/TXM/TXD descriptors */
183 priv
->rx
.desc
= pci_alloc_consistent(priv
->pdev
, sizeof(struct agnx_desc
) * len
,
185 if (!priv
->rx
.desc
) {
186 kfree(priv
->rx
.info
);
190 priv
->txm
.desc
= priv
->rx
.desc
+ priv
->rx
.size
;
191 priv
->txm
.dma
= priv
->rx
.dma
+ sizeof(struct agnx_desc
) * priv
->rx
.size
;
192 priv
->txd
.desc
= priv
->txm
.desc
+ priv
->txm
.size
;
193 priv
->txd
.dma
= priv
->txm
.dma
+ sizeof(struct agnx_desc
) * priv
->txm
.size
;
196 } /* agnx_alloc_rings */
198 static void rings_free(struct agnx_priv
*priv
)
200 unsigned int len
= priv
->rx
.size
+ priv
->txm
.size
+ priv
->txd
.size
;
204 spin_lock_irqsave(&priv
->lock
, flags
);
205 kfree(priv
->rx
.info
);
206 pci_free_consistent(priv
->pdev
, sizeof(struct agnx_desc
) * len
,
207 priv
->rx
.desc
, priv
->rx
.dma
);
208 spin_unlock_irqrestore(&priv
->lock
, flags
);
212 static void agnx_periodic_work_handler(struct work_struct
*work
)
214 struct agnx_priv
*priv
= container_of(work
, struct agnx_priv
, periodic_work
.work
);
215 /* unsigned long flags; */
218 /* fixme: using mutex?? */
219 /* spin_lock_irqsave(&priv->lock, flags); */
221 /* TODO Recalibrate*/
222 /* calibrate_oscillator(priv); */
223 /* antenna_calibrate(priv); */
224 /* agnx_send_packet(priv, 997); */
226 /* if (debug == 3) */
227 /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
229 delay
= msecs_to_jiffies(AGNX_PERIODIC_DELAY
);
230 /* delay = round_jiffies(HZ * 15); */
232 queue_delayed_work(priv
->hw
->workqueue
, &priv
->periodic_work
, delay
);
234 /* spin_unlock_irqrestore(&priv->lock, flags); */
238 static int agnx_start(struct ieee80211_hw
*dev
)
240 struct agnx_priv
*priv
= dev
->priv
;
241 /* unsigned long delay; */
245 err
= agnx_alloc_rings(priv
);
247 printk(KERN_ERR PFX
"Can't alloc RX/TXM/TXD rings\n");
250 err
= request_irq(priv
->pdev
->irq
, &agnx_interrupt_handler
,
251 IRQF_SHARED
, "agnx_pci", dev
);
253 printk(KERN_ERR PFX
"Failed to register IRQ handler\n");
266 priv
->init_status
= AGNX_START
;
267 /* INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); */
268 /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
269 /* queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */
274 static void agnx_stop(struct ieee80211_hw
*dev
)
276 struct agnx_priv
*priv
= dev
->priv
;
279 priv
->init_status
= AGNX_STOP
;
280 /* make sure hardware will not generate irq */
282 free_irq(priv
->pdev
->irq
, dev
);
283 flush_workqueue(priv
->hw
->workqueue
);
284 /* cancel_delayed_work_sync(&priv->periodic_work); */
289 static int agnx_config(struct ieee80211_hw
*dev
, u32 changed
)
291 struct agnx_priv
*priv
= dev
->priv
;
292 struct ieee80211_conf
*conf
= &dev
->conf
;
293 int channel
= ieee80211_frequency_to_channel(conf
->channel
->center_freq
);
296 spin_lock(&priv
->lock
);
297 /* FIXME need priv lock? */
298 if (channel
!= priv
->channel
) {
299 priv
->channel
= channel
;
300 agnx_set_channel(priv
, priv
->channel
);
303 spin_unlock(&priv
->lock
);
307 static void agnx_bss_info_changed(struct ieee80211_hw
*dev
,
308 struct ieee80211_vif
*vif
,
309 struct ieee80211_bss_conf
*conf
,
312 struct agnx_priv
*priv
= dev
->priv
;
313 void __iomem
*ctl
= priv
->ctl
;
316 if (!(changed
& BSS_CHANGED_BSSID
))
319 spin_lock(&priv
->lock
);
321 if (memcmp(conf
->bssid
, priv
->bssid
, ETH_ALEN
)) {
322 agnx_set_bssid(priv
, conf
->bssid
);
323 memcpy(priv
->bssid
, conf
->bssid
, ETH_ALEN
);
324 hash_write(priv
, conf
->bssid
, BSSID_STAID
);
325 sta_init(priv
, BSSID_STAID
);
327 sta_power_init(priv
, BSSID_STAID
);
328 agnx_write32(ctl
, AGNX_BM_MTSM
, 0xff & ~0x1);
330 spin_unlock(&priv
->lock
);
331 } /* agnx_bss_info_changed */
334 static void agnx_configure_filter(struct ieee80211_hw
*dev
,
335 unsigned int changed_flags
,
336 unsigned int *total_flags
,
337 int mc_count
, struct dev_mc_list
*mclist
)
339 unsigned int new_flags
= 0;
341 *total_flags
= new_flags
;
345 static int agnx_add_interface(struct ieee80211_hw
*dev
,
346 struct ieee80211_if_init_conf
*conf
)
348 struct agnx_priv
*priv
= dev
->priv
;
351 spin_lock(&priv
->lock
);
353 if (priv
->mode
!= NL80211_IFTYPE_MONITOR
)
356 switch (conf
->type
) {
357 case NL80211_IFTYPE_STATION
:
358 priv
->mode
= conf
->type
;
364 spin_unlock(&priv
->lock
);
369 static void agnx_remove_interface(struct ieee80211_hw
*dev
,
370 struct ieee80211_if_init_conf
*conf
)
372 struct agnx_priv
*priv
= dev
->priv
;
376 priv
->mode
= NL80211_IFTYPE_MONITOR
;
379 static int agnx_get_stats(struct ieee80211_hw
*dev
,
380 struct ieee80211_low_level_stats
*stats
)
382 struct agnx_priv
*priv
= dev
->priv
;
384 spin_lock(&priv
->lock
);
386 memcpy(stats
, &priv
->stats
, sizeof(*stats
));
387 spin_unlock(&priv
->lock
);
392 static u64
agnx_get_tsft(struct ieee80211_hw
*dev
)
394 void __iomem
*ctl
= ((struct agnx_priv
*)dev
->priv
)->ctl
;
400 tsftl
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPLO
);
401 tsft
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPHI
);
408 static int agnx_get_tx_stats(struct ieee80211_hw
*dev
,
409 struct ieee80211_tx_queue_stats
*stats
)
411 struct agnx_priv
*priv
= dev
->priv
;
414 /* FIXME now we just using txd queue, but should using txm queue too */
415 stats
[0].len
= (priv
->txd
.idx
- priv
->txd
.idx_sent
) / 2;
416 stats
[0].limit
= priv
->txd
.size
- 2;
417 stats
[0].count
= priv
->txd
.idx
/ 2;
422 static struct ieee80211_ops agnx_ops
= {
426 .add_interface
= agnx_add_interface
,
427 .remove_interface
= agnx_remove_interface
,
428 .config
= agnx_config
,
429 .bss_info_changed
= agnx_bss_info_changed
,
430 .configure_filter
= agnx_configure_filter
,
431 .get_stats
= agnx_get_stats
,
432 .get_tx_stats
= agnx_get_tx_stats
,
433 .get_tsf
= agnx_get_tsft
436 static void __devexit
agnx_pci_remove(struct pci_dev
*pdev
)
438 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
439 struct agnx_priv
*priv
;
445 ieee80211_unregister_hw(dev
);
446 pci_iounmap(pdev
, priv
->ctl
);
447 pci_iounmap(pdev
, priv
->data
);
448 pci_release_regions(pdev
);
449 pci_disable_device(pdev
);
451 ieee80211_free_hw(dev
);
454 static int __devinit
agnx_pci_probe(struct pci_dev
*pdev
,
455 const struct pci_device_id
*id
)
457 struct ieee80211_hw
*dev
;
458 struct agnx_priv
*priv
;
461 err
= pci_enable_device(pdev
);
463 dev_err(&pdev
->dev
, "can't enable pci device\n");
467 err
= pci_request_regions(pdev
, "agnx-pci");
469 dev_err(&pdev
->dev
, "can't reserve PCI resources\n");
473 if (pci_set_dma_mask(pdev
, DMA_BIT_MASK(32)) ||
474 pci_set_consistent_dma_mask(pdev
, DMA_BIT_MASK(32))) {
475 dev_err(&pdev
->dev
, "no suitable DMA available\n");
480 pci_set_master(pdev
);
482 dev
= ieee80211_alloc_hw(sizeof(*priv
), &agnx_ops
);
484 dev_err(&pdev
->dev
, "ieee80211 alloc failed\n");
489 memset(priv
, 0, sizeof(*priv
));
490 priv
->mode
= NL80211_IFTYPE_MONITOR
;
493 spin_lock_init(&priv
->lock
);
494 priv
->init_status
= AGNX_UNINIT
;
496 priv
->ctl
= pci_iomap(pdev
, 0, 0);
497 /* dev_dbg(&pdev->dev, "MEM1 mapped address is 0x%p\n", priv->ctl); */
499 dev_err(&pdev
->dev
, "can't map device memory\n");
503 priv
->data
= pci_iomap(pdev
, 1, 0);
505 dev_err(&pdev
->dev
, "can't map device memory\n");
510 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &priv
->revid
);
512 priv
->band
.channels
= (struct ieee80211_channel
*)agnx_channels
;
513 priv
->band
.n_channels
= ARRAY_SIZE(agnx_channels
);
514 priv
->band
.bitrates
= (struct ieee80211_rate
*)agnx_rates_80211g
;
515 priv
->band
.n_bitrates
= ARRAY_SIZE(agnx_rates_80211g
);
517 /* Init ieee802.11 dev */
518 SET_IEEE80211_DEV(dev
, &pdev
->dev
);
519 pci_set_drvdata(pdev
, dev
);
520 dev
->extra_tx_headroom
= sizeof(struct agnx_hdr
);
522 /* FIXME It only include FCS in promious mode but not manage mode */
523 /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS; */
524 dev
->channel_change_time
= 5000;
525 dev
->max_signal
= 100;
529 agnx_get_mac_address(priv
);
531 SET_IEEE80211_PERM_ADDR(dev
, priv
->mac_addr
);
534 /* for (i = 1; i < NUM_DRIVE_MODES; i++) { */
535 /* err = ieee80211_register_hwmode(dev, &priv->modes[i]); */
537 /* printk(KERN_ERR PFX "Can't register hwmode\n"); */
538 /* goto err_iounmap; */
543 dev
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &priv
->band
;
545 err
= ieee80211_register_hw(dev
);
547 dev_err(&pdev
->dev
, "can't register hardware\n");
553 dev_info(&pdev
->dev
, "%s: hwaddr %pM, Rev 0x%02x\n",
554 wiphy_name(dev
->wiphy
),
555 dev
->wiphy
->perm_addr
, priv
->revid
);
559 pci_iounmap(pdev
, priv
->data
);
562 pci_iounmap(pdev
, priv
->ctl
);
565 pci_set_drvdata(pdev
, NULL
);
566 ieee80211_free_hw(dev
);
569 pci_release_regions(pdev
);
571 pci_disable_device(pdev
);
573 } /* agnx_pci_probe*/
577 static int agnx_pci_suspend(struct pci_dev
*pdev
, pm_message_t state
)
579 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
582 ieee80211_stop_queues(dev
);
585 pci_save_state(pdev
);
586 pci_set_power_state(pdev
, pci_choose_state(pdev
, state
));
590 static int agnx_pci_resume(struct pci_dev
*pdev
)
592 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
595 pci_set_power_state(pdev
, PCI_D0
);
596 pci_restore_state(pdev
);
599 ieee80211_wake_queues(dev
);
606 #define agnx_pci_suspend NULL
607 #define agnx_pci_resume NULL
609 #endif /* CONFIG_PM */
612 static struct pci_driver agnx_pci_driver
= {
614 .id_table
= agnx_pci_id_tbl
,
615 .probe
= agnx_pci_probe
,
616 .remove
= __devexit_p(agnx_pci_remove
),
617 .suspend
= agnx_pci_suspend
,
618 .resume
= agnx_pci_resume
,
621 static int __init
agnx_pci_init(void)
624 return pci_register_driver(&agnx_pci_driver
);
627 static void __exit
agnx_pci_exit(void)
630 pci_unregister_driver(&agnx_pci_driver
);
634 module_init(agnx_pci_init
);
635 module_exit(agnx_pci_exit
);