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