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