Introduce
NIC
Ring buffer
Ring buffer
Driver
Transmit
receive
DriverISR
DriverISR CPU
Memory
Memory
Pending queue
While complete
Interrupt
Transfer until buffer is empty
Device busy
Code survey
• static int __init ipw_init(void)• static void __exit ipw_exit(void)• static int ipw_pci_resume(struct pci_dev *pdev)• static int ipw_pci_suspend(struct pci_dev *pdev,
pm_message_t state)• static void ipw_pci_remove(struct pci_dev *pdev)• static int ipw_pci_probe(struct pci_dev *pdev, co
nst struct pci_device_id *ent)• static irqreturn_t ipw_isr(int irq, void *data, struc
t pt_regs *regs)• static void ipw_rx(struct ipw_priv *priv)
Code survey• Struct ipw_priv {
/* ieee device used by generic ieee processing code */struct ieee80211_device *ieee;spinlock_t lock;spinlock_t irq_lock;struct mutex mutex; /* basic pci-network driver stuff */
struct pci_dev *pci_dev;struct net_device *net_dev;
#ifdef CONFIG_IPW2200_PROMISCUOUS/* Promiscuous mode */struct ipw_prom_priv *prom_priv;struct net_device *prom_net_dev;
#endif/* pci hardware address support */
• ……………
• See ipw2200.h line 1187
Code survey• static int __init ipw_init(void){
int ret;printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");ret = pci_module_init(&ipw_driver);if (ret) {
IPW_ERROR("Unable to initialize PCI module\n");return ret;
}ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);if (ret) {
IPW_ERROR("Unable to create driver sysfs file\n");pci_unregister_driver(&ipw_driver);return ret;
}return ret;
}
Code survey
• static void __exit ipw_exit(void){
driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);pci_unregister_driver(&ipw_driver);
}
Code surveystatic int ipw_pci_resume(struct pci_dev *pdev){
struct ipw_priv *priv = pci_get_drvdata(pdev);struct net_device *dev = priv->net_dev;u32 val;printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)pci_set_power_state(pdev, 0);
#elsepci_set_power_state(pdev, PCI_D0);
#endifpci_enable_device(pdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)pci_restore_state(pdev, priv->pm_state);
#else pci_restore_state(pdev);#endif
pci_read_config_dword(pdev, 0x40, &val);if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);netif_device_attach(dev);/* Bring the device back up */queue_work(priv->workqueue, &priv->up);return 0;
}
Code surveystatic int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state)#endif{
struct ipw_priv *priv = pci_get_drvdata(pdev);struct net_device *dev = priv->net_dev;printk(KERN_INFO "%s: Going into suspend...\n", dev->name);/* Take down the device; powers it off, etc. */ipw_down(priv);/* Remove the PRESENT state of the device */netif_device_detach(dev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)pci_save_state(pdev, priv->pm_state);
#elsepci_save_state(pdev);
#endifpci_disable_device(pdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)pci_set_power_state(pdev, state);
#elsepci_set_power_state(pdev, pci_choose_state(pdev, state));
#endifreturn 0;
}
Code surveystatic void ipw_pci_remove(struct pci_dev *pdev){
struct ipw_priv *priv = pci_get_drvdata(pdev);struct list_head *p, *q; int i;if (!priv)
return;mutex_lock(&priv->mutex);priv->status |= STATUS_EXIT_PENDING;ipw_down(priv);sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);mutex_unlock(&priv->mutex);unregister_netdev(priv->net_dev);if (priv->rxq) {
ipw_rx_queue_free(priv, priv->rxq);priv->rxq = NULL;
}ipw_tx_queue_free(priv);if (priv->cmdlog) {
kfree(priv->cmdlog);priv->cmdlog = NULL;
}
………… see ipw2200.c line 12360
Code surveystatic int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en
t){
int err = 0;struct net_device *net_dev;void __iomem *base;u32 length, val;struct ipw_priv *priv; int i;net_dev = alloc_ieee80211(sizeof(struct ipw_priv));if (net_dev == NULL) {
err = -ENOMEM;goto out;
} priv = ieee80211_priv(net_dev);priv->ieee = netdev_priv(net_dev);priv->net_dev = net_dev;priv->pci_dev = pdev;ipw_debug_level = debug;spin_lock_init(&priv->lock);spin_lock_init(&priv->irq_lock);
………… see ipw2200.c line 12182
Code survey
static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs){
struct ipw_priv *priv = data;u32 inta, inta_mask;if (!priv)
return IRQ_NONE;spin_lock(&priv->irq_lock);if (!(priv->status & STATUS_INT_ENABLED)) {
/* Shared IRQ */goto none;
}inta = ipw_read32(priv, IPW_INTA_RW);inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
……… see ipw2200.c line 11070
Code surveystatic void ipw_rx(struct ipw_priv *priv){
struct ipw_rx_mem_buffer *rxb;struct ipw_rx_packet *pkt;struct ieee80211_hdr_4addr *header;u32 r, w, i;u8 network_packet;r = ipw_read32(priv, IPW_RX_READ_INDEX);w = ipw_read32(priv, IPW_RX_WRITE_INDEX);i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;while (i != r) {
rxb = priv->rxq->queue[i];if (unlikely(rxb == NULL)) {
printk(KERN_CRIT "Queue not allocated!\n");break;
}priv->rxq->queue[i] = NULL;pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
pkt = (struct ipw_rx_packet *)rxb->skb->data;
………… see ipw2200.c line 8714
Code survey
• Rx theory of operation * Driver sequence: * ipw_rx_queue_alloc() ipw_rx_queue_replenish() ipw_rx_queue_restock() * -- enable interrupts -- *
ISR - ipw_rx()