17
Linux Device Driver Final project present 王王王

Linux Device Driver Final project present 王昶升. Outline Introduce Code survey demo

  • View
    220

  • Download
    2

Embed Size (px)

Citation preview

Linux Device Driver

Final project present

王昶升

Outline

• Introduce

• Code survey

• demo

Introduce

• Intel(R) PRO/Wireless 2200BG• http://ipw2200.sf.net/

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()

demo

• VMware上使用 ipw2200

END

Any question?