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年了,加油继续前行!

你可能感兴趣的:(VOIP)