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 void agnx_bss_info_changed(struct ieee80211_hw
*dev
,
307 struct ieee80211_vif
*vif
,
308 struct ieee80211_bss_conf
*conf
,
311 struct agnx_priv
*priv
= dev
->priv
;
312 void __iomem
*ctl
= priv
->ctl
;
315 if (!(changed
& BSS_CHANGED_BSSID
))
318 spin_lock(&priv
->lock
);
320 if (memcmp(conf
->bssid
, priv
->bssid
, ETH_ALEN
)) {
321 agnx_set_bssid(priv
, conf
->bssid
);
322 memcpy(priv
->bssid
, conf
->bssid
, ETH_ALEN
);
323 hash_write(priv
, conf
->bssid
, BSSID_STAID
);
324 sta_init(priv
, BSSID_STAID
);
326 sta_power_init(priv
, BSSID_STAID
);
327 agnx_write32(ctl
, AGNX_BM_MTSM
, 0xff & ~0x1);
329 spin_unlock(&priv
->lock
);
330 } /* agnx_bss_info_changed */
333 static void agnx_configure_filter(struct ieee80211_hw
*dev
,
334 unsigned int changed_flags
,
335 unsigned int *total_flags
,
336 int mc_count
, struct dev_mc_list
*mclist
)
338 unsigned int new_flags
= 0;
340 *total_flags
= new_flags
;
344 static int agnx_add_interface(struct ieee80211_hw
*dev
,
345 struct ieee80211_if_init_conf
*conf
)
347 struct agnx_priv
*priv
= dev
->priv
;
350 spin_lock(&priv
->lock
);
352 if (priv
->mode
!= NL80211_IFTYPE_MONITOR
)
355 switch (conf
->type
) {
356 case NL80211_IFTYPE_STATION
:
357 priv
->mode
= conf
->type
;
363 spin_unlock(&priv
->lock
);
368 static void agnx_remove_interface(struct ieee80211_hw
*dev
,
369 struct ieee80211_if_init_conf
*conf
)
371 struct agnx_priv
*priv
= dev
->priv
;
375 priv
->mode
= NL80211_IFTYPE_MONITOR
;
378 static int agnx_get_stats(struct ieee80211_hw
*dev
,
379 struct ieee80211_low_level_stats
*stats
)
381 struct agnx_priv
*priv
= dev
->priv
;
383 spin_lock(&priv
->lock
);
385 memcpy(stats
, &priv
->stats
, sizeof(*stats
));
386 spin_unlock(&priv
->lock
);
391 static u64
agnx_get_tsft(struct ieee80211_hw
*dev
)
393 void __iomem
*ctl
= ((struct agnx_priv
*)dev
->priv
)->ctl
;
399 tsftl
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPLO
);
400 tsft
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPHI
);
407 static int agnx_get_tx_stats(struct ieee80211_hw
*dev
,
408 struct ieee80211_tx_queue_stats
*stats
)
410 struct agnx_priv
*priv
= dev
->priv
;
413 /* FIXME now we just using txd queue, but should using txm queue too */
414 stats
[0].len
= (priv
->txd
.idx
- priv
->txd
.idx_sent
) / 2;
415 stats
[0].limit
= priv
->txd
.size
- 2;
416 stats
[0].count
= priv
->txd
.idx
/ 2;
421 static struct ieee80211_ops agnx_ops
= {
425 .add_interface
= agnx_add_interface
,
426 .remove_interface
= agnx_remove_interface
,
427 .config
= agnx_config
,
428 .bss_info_changed
= agnx_bss_info_changed
,
429 .configure_filter
= agnx_configure_filter
,
430 .get_stats
= agnx_get_stats
,
431 .get_tx_stats
= agnx_get_tx_stats
,
432 .get_tsf
= agnx_get_tsft
435 static void __devexit
agnx_pci_remove(struct pci_dev
*pdev
)
437 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
438 struct agnx_priv
*priv
;
444 ieee80211_unregister_hw(dev
);
445 pci_iounmap(pdev
, priv
->ctl
);
446 pci_iounmap(pdev
, priv
->data
);
447 pci_release_regions(pdev
);
448 pci_disable_device(pdev
);
450 ieee80211_free_hw(dev
);
453 static int __devinit
agnx_pci_probe(struct pci_dev
*pdev
,
454 const struct pci_device_id
*id
)
456 struct ieee80211_hw
*dev
;
457 struct agnx_priv
*priv
;
459 DECLARE_MAC_BUF(mac
);
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 %s, Rev 0x%02x\n",
554 wiphy_name(dev
->wiphy
),
555 print_mac(mac
, 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
);