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 printk(KERN_WARNING PFX
"read mac %pM\n", priv
->mac_addr
);
154 printk(KERN_WARNING PFX
"Invalid hwaddr! Using random hwaddr\n");
155 random_ether_addr(priv
->mac_addr
);
159 } /* agnx_get_mac_address */
161 static int agnx_alloc_rings(struct agnx_priv
*priv
)
166 /* Allocate RX/TXM/TXD rings info */
167 priv
->rx
.size
= AGNX_RX_RING_SIZE
;
168 priv
->txm
.size
= AGNX_TXM_RING_SIZE
;
169 priv
->txd
.size
= AGNX_TXD_RING_SIZE
;
171 len
= priv
->rx
.size
+ priv
->txm
.size
+ priv
->txd
.size
;
173 /* priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL); */
174 priv
->rx
.info
= kzalloc(sizeof(struct agnx_info
) * len
, GFP_ATOMIC
);
177 priv
->txm
.info
= priv
->rx
.info
+ priv
->rx
.size
;
178 priv
->txd
.info
= priv
->txm
.info
+ priv
->txm
.size
;
180 /* Allocate RX/TXM/TXD descriptors */
181 priv
->rx
.desc
= pci_alloc_consistent(priv
->pdev
, sizeof(struct agnx_desc
) * len
,
183 if (!priv
->rx
.desc
) {
184 kfree(priv
->rx
.info
);
188 priv
->txm
.desc
= priv
->rx
.desc
+ priv
->rx
.size
;
189 priv
->txm
.dma
= priv
->rx
.dma
+ sizeof(struct agnx_desc
) * priv
->rx
.size
;
190 priv
->txd
.desc
= priv
->txm
.desc
+ priv
->txm
.size
;
191 priv
->txd
.dma
= priv
->txm
.dma
+ sizeof(struct agnx_desc
) * priv
->txm
.size
;
194 } /* agnx_alloc_rings */
196 static void rings_free(struct agnx_priv
*priv
)
198 unsigned int len
= priv
->rx
.size
+ priv
->txm
.size
+ priv
->txd
.size
;
202 spin_lock_irqsave(&priv
->lock
, flags
);
203 kfree(priv
->rx
.info
);
204 pci_free_consistent(priv
->pdev
, sizeof(struct agnx_desc
) * len
,
205 priv
->rx
.desc
, priv
->rx
.dma
);
206 spin_unlock_irqrestore(&priv
->lock
, flags
);
210 static void agnx_periodic_work_handler(struct work_struct
*work
)
212 struct agnx_priv
*priv
= container_of(work
, struct agnx_priv
, periodic_work
.work
);
213 /* unsigned long flags; */
216 /* fixme: using mutex?? */
217 /* spin_lock_irqsave(&priv->lock, flags); */
219 /* TODO Recalibrate*/
220 /* calibrate_oscillator(priv); */
221 /* antenna_calibrate(priv); */
222 /* agnx_send_packet(priv, 997); /
224 /* if (debug == 3) */
225 /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
227 delay
= msecs_to_jiffies(AGNX_PERIODIC_DELAY
);
228 /* delay = round_jiffies(HZ * 15); */
230 queue_delayed_work(priv
->hw
->workqueue
, &priv
->periodic_work
, delay
);
232 /* spin_unlock_irqrestore(&priv->lock, flags); */
236 static int agnx_start(struct ieee80211_hw
*dev
)
238 struct agnx_priv
*priv
= dev
->priv
;
239 /* unsigned long delay; */
243 err
= agnx_alloc_rings(priv
);
245 printk(KERN_ERR PFX
"Can't alloc RX/TXM/TXD rings\n");
248 err
= request_irq(priv
->pdev
->irq
, &agnx_interrupt_handler
,
249 IRQF_SHARED
, "agnx_pci", dev
);
251 printk(KERN_ERR PFX
"Failed to register IRQ handler\n");
264 priv
->init_status
= AGNX_START
;
265 /* INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); */
266 /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
267 /* queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */
272 static void agnx_stop(struct ieee80211_hw
*dev
)
274 struct agnx_priv
*priv
= dev
->priv
;
277 priv
->init_status
= AGNX_STOP
;
278 /* make sure hardware will not generate irq */
280 free_irq(priv
->pdev
->irq
, dev
);
281 flush_workqueue(priv
->hw
->workqueue
);
282 /* cancel_delayed_work_sync(&priv->periodic_work); */
287 static int agnx_config(struct ieee80211_hw
*dev
, u32 changed
)
289 struct agnx_priv
*priv
= dev
->priv
;
290 struct ieee80211_conf
*conf
= &dev
->conf
;
291 int channel
= ieee80211_frequency_to_channel(conf
->channel
->center_freq
);
294 spin_lock(&priv
->lock
);
295 /* FIXME need priv lock? */
296 if (channel
!= priv
->channel
) {
297 priv
->channel
= channel
;
298 agnx_set_channel(priv
, priv
->channel
);
301 spin_unlock(&priv
->lock
);
305 static void agnx_bss_info_changed(struct ieee80211_hw
*dev
,
306 struct ieee80211_vif
*vif
,
307 struct ieee80211_bss_conf
*conf
,
310 struct agnx_priv
*priv
= dev
->priv
;
311 void __iomem
*ctl
= priv
->ctl
;
314 if (!(changed
& BSS_CHANGED_BSSID
))
317 spin_lock(&priv
->lock
);
319 if (memcmp(conf
->bssid
, priv
->bssid
, ETH_ALEN
)) {
320 agnx_set_bssid(priv
, conf
->bssid
);
321 memcpy(priv
->bssid
, conf
->bssid
, ETH_ALEN
);
322 hash_write(priv
, conf
->bssid
, BSSID_STAID
);
323 sta_init(priv
, BSSID_STAID
);
325 sta_power_init(priv
, BSSID_STAID
);
326 agnx_write32(ctl
, AGNX_BM_MTSM
, 0xff & ~0x1);
328 spin_unlock(&priv
->lock
);
329 } /* agnx_bss_info_changed */
332 static void agnx_configure_filter(struct ieee80211_hw
*dev
,
333 unsigned int changed_flags
,
334 unsigned int *total_flags
,
335 int mc_count
, struct dev_mc_list
*mclist
)
337 unsigned int new_flags
= 0;
339 *total_flags
= new_flags
;
343 static int agnx_add_interface(struct ieee80211_hw
*dev
,
344 struct ieee80211_if_init_conf
*conf
)
346 struct agnx_priv
*priv
= dev
->priv
;
349 spin_lock(&priv
->lock
);
351 if (priv
->mode
!= NL80211_IFTYPE_MONITOR
)
354 switch (conf
->type
) {
355 case NL80211_IFTYPE_STATION
:
356 priv
->mode
= conf
->type
;
362 spin_unlock(&priv
->lock
);
367 static void agnx_remove_interface(struct ieee80211_hw
*dev
,
368 struct ieee80211_if_init_conf
*conf
)
370 struct agnx_priv
*priv
= dev
->priv
;
374 priv
->mode
= NL80211_IFTYPE_MONITOR
;
377 static int agnx_get_stats(struct ieee80211_hw
*dev
,
378 struct ieee80211_low_level_stats
*stats
)
380 struct agnx_priv
*priv
= dev
->priv
;
382 spin_lock(&priv
->lock
);
384 memcpy(stats
, &priv
->stats
, sizeof(*stats
));
385 spin_unlock(&priv
->lock
);
390 static u64
agnx_get_tsft(struct ieee80211_hw
*dev
)
392 void __iomem
*ctl
= ((struct agnx_priv
*)dev
->priv
)->ctl
;
398 tsftl
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPLO
);
399 tsft
= ioread32(ctl
+ AGNX_TXM_TIMESTAMPHI
);
406 static int agnx_get_tx_stats(struct ieee80211_hw
*dev
,
407 struct ieee80211_tx_queue_stats
*stats
)
409 struct agnx_priv
*priv
= dev
->priv
;
412 /* FIXME now we just using txd queue, but should using txm queue too */
413 stats
[0].len
= (priv
->txd
.idx
- priv
->txd
.idx_sent
) / 2;
414 stats
[0].limit
= priv
->txd
.size
- 2;
415 stats
[0].count
= priv
->txd
.idx
/ 2;
420 static struct ieee80211_ops agnx_ops
= {
424 .add_interface
= agnx_add_interface
,
425 .remove_interface
= agnx_remove_interface
,
426 .config
= agnx_config
,
427 .bss_info_changed
= agnx_bss_info_changed
,
428 .configure_filter
= agnx_configure_filter
,
429 .get_stats
= agnx_get_stats
,
430 .get_tx_stats
= agnx_get_tx_stats
,
431 .get_tsf
= agnx_get_tsft
434 static void __devexit
agnx_pci_remove(struct pci_dev
*pdev
)
436 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
437 struct agnx_priv
*priv
;
443 ieee80211_unregister_hw(dev
);
444 pci_iounmap(pdev
, priv
->ctl
);
445 pci_iounmap(pdev
, priv
->data
);
446 pci_release_regions(pdev
);
447 pci_disable_device(pdev
);
449 ieee80211_free_hw(dev
);
452 static int __devinit
agnx_pci_probe(struct pci_dev
*pdev
,
453 const struct pci_device_id
*id
)
455 struct ieee80211_hw
*dev
;
456 struct agnx_priv
*priv
;
459 err
= pci_enable_device(pdev
);
461 dev_err(&pdev
->dev
, "can't enable pci device\n");
465 err
= pci_request_regions(pdev
, "agnx-pci");
467 dev_err(&pdev
->dev
, "can't reserve PCI resources\n");
471 if (pci_set_dma_mask(pdev
, DMA_BIT_MASK(32)) ||
472 pci_set_consistent_dma_mask(pdev
, DMA_BIT_MASK(32))) {
473 dev_err(&pdev
->dev
, "no suitable DMA available\n");
478 pci_set_master(pdev
);
480 dev
= ieee80211_alloc_hw(sizeof(*priv
), &agnx_ops
);
482 dev_err(&pdev
->dev
, "ieee80211 alloc failed\n");
487 memset(priv
, 0, sizeof(*priv
));
488 priv
->mode
= NL80211_IFTYPE_MONITOR
;
491 spin_lock_init(&priv
->lock
);
492 priv
->init_status
= AGNX_UNINIT
;
494 priv
->ctl
= pci_iomap(pdev
, 0, 0);
495 /* dev_dbg(&pdev->dev, "MEM1 mapped address is 0x%p\n", priv->ctl); */
497 dev_err(&pdev
->dev
, "can't map device memory\n");
501 priv
->data
= pci_iomap(pdev
, 1, 0);
503 dev_err(&pdev
->dev
, "can't map device memory\n");
508 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &priv
->revid
);
510 priv
->band
.channels
= (struct ieee80211_channel
*)agnx_channels
;
511 priv
->band
.n_channels
= ARRAY_SIZE(agnx_channels
);
512 priv
->band
.bitrates
= (struct ieee80211_rate
*)agnx_rates_80211g
;
513 priv
->band
.n_bitrates
= ARRAY_SIZE(agnx_rates_80211g
);
515 /* Init ieee802.11 dev */
516 SET_IEEE80211_DEV(dev
, &pdev
->dev
);
517 pci_set_drvdata(pdev
, dev
);
518 dev
->extra_tx_headroom
= sizeof(struct agnx_hdr
);
520 /* FIXME It only include FCS in promious mode but not manage mode */
521 /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS; */
522 dev
->channel_change_time
= 5000;
523 dev
->max_signal
= 100;
527 agnx_get_mac_address(priv
);
529 SET_IEEE80211_PERM_ADDR(dev
, priv
->mac_addr
);
532 /* for (i = 1; i < NUM_DRIVE_MODES; i++) { */
533 /* err = ieee80211_register_hwmode(dev, &priv->modes[i]); */
535 /* printk(KERN_ERR PFX "Can't register hwmode\n"); */
536 /* goto err_iounmap; */
541 dev
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &priv
->band
;
543 err
= ieee80211_register_hw(dev
);
545 dev_err(&pdev
->dev
, "can't register hardware\n");
551 dev_info(&pdev
->dev
, "%s: hwaddr %pM, Rev 0x%02x\n",
552 wiphy_name(dev
->wiphy
),
553 dev
->wiphy
->perm_addr
, priv
->revid
);
557 pci_iounmap(pdev
, priv
->data
);
560 pci_iounmap(pdev
, priv
->ctl
);
563 pci_set_drvdata(pdev
, NULL
);
564 ieee80211_free_hw(dev
);
567 pci_release_regions(pdev
);
569 pci_disable_device(pdev
);
571 } /* agnx_pci_probe*/
575 static int agnx_pci_suspend(struct pci_dev
*pdev
, pm_message_t state
)
577 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
580 ieee80211_stop_queues(dev
);
583 pci_save_state(pdev
);
584 pci_set_power_state(pdev
, pci_choose_state(pdev
, state
));
588 static int agnx_pci_resume(struct pci_dev
*pdev
)
590 struct ieee80211_hw
*dev
= pci_get_drvdata(pdev
);
593 pci_set_power_state(pdev
, PCI_D0
);
594 pci_restore_state(pdev
);
597 ieee80211_wake_queues(dev
);
604 #define agnx_pci_suspend NULL
605 #define agnx_pci_resume NULL
607 #endif /* CONFIG_PM */
610 static struct pci_driver agnx_pci_driver
= {
612 .id_table
= agnx_pci_id_tbl
,
613 .probe
= agnx_pci_probe
,
614 .remove
= __devexit_p(agnx_pci_remove
),
615 .suspend
= agnx_pci_suspend
,
616 .resume
= agnx_pci_resume
,
619 static int __init
agnx_pci_init(void)
622 return pci_register_driver(&agnx_pci_driver
);
625 static void __exit
agnx_pci_exit(void)
628 pci_unregister_driver(&agnx_pci_driver
);
632 module_init(agnx_pci_init
);
633 module_exit(agnx_pci_exit
);