dahdi wctdm24xxp 驅動學習筆記

wctdm24xxp.c

//wctdm24xxp 驅動學習筆記

static struct pci_driver wctdm_driver = {
	.name = "wctdm24xxp",
	.probe = wctdm_init_one,
	.remove = __devexit_p(wctdm_remove_one),
	.shutdown = wctdm_shutdown,
	.suspend = wctdm_suspend,
	.id_table = wctdm_pci_tbl,
};

module_init(wctdm_init);
//驅動註冊過程
wctdm_init
-> res = dahdi_pci_module(&wctdm_driver);
 -> pci_register_driver(&wctdm_driver);
  -> __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
   -> drv->driver.name = drv->name;    // drv->driver 是struct device_driver 結構
      drv->driver.bus = &pci_bus_type; // [1] bus裏的match後面會用到
      drv->driver.owner = owner;       
      drv->driver.mod_name = mod_name; // [2]        
      return driver_register(&drv->driver);    
    -> ret = bus_add_driver(drv);
     -> error = driver_attach(drv);
      -> return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
       -> __driver_attach
        -> if (!driver_match_device(drv, dev)) return 0
         -> return drv->bus->match ? drv->bus->match(dev, drv) : 1;
        -> if (!dev->driver) driver_probe_device(drv, dev);
         -> ret = really_probe(dev, drv);
          -> if (dev->bus->probe) {  //如果dev->bus裏定義了probe函數,則用 dev->bus->probe
		       ret = dev->bus->probe(dev);
		       if (ret)
			   goto probe_failed;
	         } else if (drv->probe) { //否則 看是否定義了drv->probe; 從上面[2]可以看出此處沒有定義
		       ret = drv->probe(dev);
		       if (ret)
			   goto probe_failed;
			 }
			-> 展開dev->bus->probe 先看pci_bus_type 
			struct bus_type pci_bus_type = {
			.name		= "pci",
			.match		= pci_bus_match,
			.uevent		= pci_uevent,
			.probe		= pci_device_probe,
			.remove		= pci_device_remove,
			.shutdown	= pci_device_shutdown,
			.dev_groups	= pci_dev_groups,
			.bus_groups	= pci_bus_groups,
			.drv_groups	= pci_drv_groups,
			.pm		= PCI_PM_OPS_PTR,
		   };
			 pci_device_probe(struct device *dev)
			 -> error = __pci_device_probe(drv, pci_dev);
			  -> error = pci_call_probe(drv, pci_dev, id);
			   -> error = local_pci_probe(&ddi);
			    -> rc = pci_drv->probe(pci_dev, ddi->id); // pci_drv 是struct pci_driver 結構
			    -> 也就是最終調用的是wctdm_driver.probe
// PCI 設備註冊過程
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) //(drivers/pci/probe.c)
{
	struct pci_dev *dev;

	dev = pci_get_slot(bus, devfn);
	if (dev) {
		pci_dev_put(dev);
		return dev;
	}

	dev = pci_scan_device(bus, devfn);
	if (!dev)
		return NULL;

	pci_device_add(dev, bus);

	return dev;
} 
-> pci_device_add(dev, bus);
 -> ret = device_add(&dev->dev);
  -> bus_probe_device(dev);
   -> ret = device_attach(dev);
    -> ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
     -> __device_attach
      -> return driver_probe_device(drv, dev);
       -> ret = really_probe(dev, drv);
        -> ret = dev->bus->probe(dev);
         -> 到這裏和前面一樣了
//probe 函數分悉
.probe = wctdm_init_one
-> return __wctdm_init_one(pdev, ent);
 -> pci_set_drvdata(pdev, wc); // 將wc結構關聯到pci_dev中
    wc->vb.pdev = pdev;
    ret = voicebus_init(&wc->vb, wc->board_name); //voicebus_init
    create_sysfs_files(wc); // 
    voicebus_start(&wc->vb); //
    wctdm_init_span(wc, curspan, curchan, wc->desc->ports, 0, pos);//wctdm24xxp_analog_span_ops 在裏面引用 
     -> wctdm_init_chan()
    wc->ddev = dahdi_create_device(); // 這裏ddev包含一個新的struct device dev
    dahdi_register_device(wc->ddev, &wc->vb.pdev->dev)
    -> ret = _dahdi_register_device(ddev, parent);
     -> ret = dahdi_sysfs_add_device(ddev, parent);
      -> struct device *const dev = &ddev->dev;
         dev->parent = parent;
         dev->bus = &dahdi_device_bus; //[3]
         ret = device_add(dev);  //這個是ddev->dev 也就是wc->ddev->dev
        -> 之後跟上面基本一樣,不過這裏dev->bus->probe 沒有定義,drv也應該沒有,所以不會再probe
        static struct bus_type dahdi_device_bus = {
	     .name = "dahdi_devices",
	      .uevent         = device_uevent,
        #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
	      .dev_attrs = dahdi_device_attrs,
        #else
	      .dev_groups = dahdi_device_groups,
        #endif
     -> list_for_each_entry(s, &ddev->spans, device_node)
		ret = _dahdi_assign_span(s, 0, 0, 1); 
		-> res = span_sysfs_create(span);
		 -> span_device->bus = &spans_bus_type;
			span_device->parent = &span->parent->dev;
			dev_set_name(span_device, "span-%d", span->spanno);
			dev_set_drvdata(span_device, span);
			span_device->release = span_release;
			res = device_register(span_device);

			for (x = 0; x < span->channels; x++) {
				res = chan_sysfs_create(span->chans[x]);
			}
			->  span = chan->span;
				devt = MKDEV(MAJOR(dahdi_channels_devt), chan->channo); 
				dev = &chan->chan_device;
				memset(dev, 0, sizeof(*dev));
				dev->devt = devt; // 與dahdi_init 時cdev_add的dev進行關聯
				dev->bus = &chan_bus_type;
				dev->parent = span->span_device;
				/*
				 * FIXME: the name cannot be longer than KOBJ_NAME_LEN
	 		    */
				dev_set_name(dev, "dahdi!chan!%03d!%03d", span->spanno, chan->chanpos);
				dev_set_drvdata(dev, chan);
				dev->release = chan_release;
				res = device_register(dev); //註冊設備
			
	}
}; 

再來看 dahdi_base.c ,wctdm24xxp.c 要依賴這個模塊(dahdi.ko)

// dahdi_fops 
static const struct file_operations dahdi_fops = {
	.owner   = THIS_MODULE,
	.open    = dahdi_open,
	.release = dahdi_release,
#ifdef HAVE_UNLOCKED_IOCTL
	.unlocked_ioctl  = dahdi_unlocked_ioctl,
#ifdef HAVE_COMPAT_IOCTL
	.compat_ioctl = dahdi_ioctl_compat,
#endif
#else
	.ioctl   = dahdi_ioctl,
#endif
	.poll    = dahdi_poll,
	.read    = dahdi_no_read,
	.write   = dahdi_no_write,
};
//-------------------------------------------------------------------------------

module_init(dahdi_init);
-> static int __init dahdi_init(void)
 -> res = dahdi_sysfs_init(&dahdi_fops);
  -> res = bus_register(&dahdi_device_bus); // [1] 註冊bus
     res = register_chrdev(DAHDI_MAJOR, "dahdi", dahdi_fops); //註冊一個字符設備,暫時不明白用途    
     res = dahdi_sysfs_chan_init(dahdi_fops); // [2] sysfs_chan_init 
   -> res = bus_register(&chan_bus_type); 
      res = driver_register(&chan_driver);
      dahdi_class = class_create(THIS_MODULE, "dahdi"); // dahdi_class 被 fixed_devfiles_create 引用
      res = fixed_devfiles_create(); //Creates /dev/dahdi/{ctl,timer,channel,pseudo}
      res = alloc_chrdev_region(&dahdi_channels_devt,
            0,
            DAHDI_MAX_CHANNELS,
            "dahdi_channels");
      cdev_init(&dahdi_channels_cdev, fops); //dahdi_channels_devt 被 chan_sysfs_create 引用
      res = cdev_add(&dahdi_channels_cdev, dahdi_channels_devt,
            DAHDI_MAX_CHANNELS);
  -> res = bus_register(&spans_bus_type);  // [3] 
     res = driver_register(&dahdi_driver); 

筆記:
1.wctdm24xxp.c (wctdm24xxp.ko)主要註冊了一個PCI 驅動,驅動實現PCI 設備的probe 函數,當系統掃描到匹配的PCI設備時,會調用probe 函數。probe函數進行設備的初始化,生成可以供應用層進行文件操作的字符設備文件。
2.wctdm24xxp.ko 依賴於dahdi.ko (其實還依賴於voice_bus.ko),所以驅動安裝時要先安裝dahdi.ko ,dahdi.ko 創建好/dev/dahdi 下的一些文件,並分配好 dahdi_channels_cdev。

時光如梭,已經是2019年了,加油繼續前行!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章