8139too

平田さん本 (Linux カーネル解析入門) と共に読んでみることに。

とりあえず

ソースは drivers/net/ethernet/realtek/8139too.c ということで良いのかな。とりあえず、module_init に渡している rtl8139_init_module という手続きが始点になるのか。
ここでは、pci_register_driver という手続きで struct pci_driver なオブジェクトを登録、とあります。

	return pci_register_driver(&rtl8139_pci_driver);

定義は以下なカンジ。テキストと差分は無いですね。

static struct pci_driver rtl8139_pci_driver = {
	.name		= DRV_NAME,
	.id_table	= rtl8139_pci_tbl,
	.probe		= rtl8139_init_one,
	.remove		= __devexit_p(rtl8139_remove_one),
#ifdef CONFIG_PM
	.suspend	= rtl8139_suspend,
	.resume		= rtl8139_resume,
#endif /* CONFIG_PM */
};

ええと、上記構造体オブジェクトの id_table 属性に設定されているナニを確認してみます。

static DEFINE_PCI_DEVICE_TABLE(rtl8139_pci_tbl) = {
	{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
(中略
	{0,}
};
MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);

DEFINE_PCI_DEVICE_TABLE マクロの定義は include/linux/pci.h で以下。

#define DEFINE_PCI_DEVICE_TABLE(_table) \
	const struct pci_device_id _table[] __devinitconst

ええと、struct pci_device_id は include/linux/mod_devicetable.h で定義されてますね。

struct pci_device_id {
	__u32 vendor, device;		/* Vendor and device ID or PCI_ANY_ID*/
	__u32 subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
	__u32 class, class_mask;	/* (class,subclass,prog-if) triplet */
	kernel_ulong_t driver_data;	/* Data private to the driver */
};

最後の属性は何かな、と思ったら以下?

typedef enum {
	RTL8139 = 0,
	RTL8129,
} board_t;

MODULE_DEVICE_TABLE はとりあえずスルーで。

probe 手続き

PCI デバイスが見つかった場合、struct pci_driver の probe 属性に設定されてる関数ポインタな手続きが呼び出されるとのこと。ここが初期化云々を担当する手続きになっている模様です。

static int __devinit rtl8139_init_one (struct pci_dev *pdev,
				       const struct pci_device_id *ent)
{

引数として

  • struct pci_dev なオブジェクト (へのポインタ)
  • struct pci_device_id なオブジェクト (へのポインタ)

が渡される模様。
struct pci_dev 型も include/linux/pci.h で定義されてますがここではスルー。

struct net_device

rtl8139_init_one 手続きから呼び出される rtl8139_init_board 手続きで struct net_device なオブジェクトを作ってカーネルにそれを教えている、とのこと。
このオブジェクトについては基本カーネルが操作するもので、ドライバ固有の諸々については struct net_device の priv という属性を使って生成したオブジェクトを参照しなさい、というルールになってるみたい。

	dev = rtl8139_init_board (pdev);
	if (IS_ERR(dev))
		return PTR_ERR(dev);

	assert (dev != NULL);
	tp = netdev_priv(dev);
	tp->dev = dev;

dev は struct net_device なポインタで、tp は struct rtl8139_private なポインタになっています。priv な属性については直接操作ではなくて上記のように netdev_priv 手続きを使ってポインタを取り出してね、な作法らしい。
もう一つ。rtl8139_init_board 手続きの先頭らへんで以下な操作を行なってます。

	/* dev and priv zeroed in alloc_etherdev */
	dev = alloc_etherdev (sizeof (*tp));
	if (dev == NULL)
		return ERR_PTR(-ENOMEM);

alloc_etherdev についてはコメントにあるように領域確保と初期化をしてくれるようです。とりあえず手元のツリーは GTAGS 作ってないので find-grep してみたらさくっと出てきました。
include/linux/etherdevice.h で定義されているみたい。

extern struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
					    unsigned int rxqs);
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)

実体は alloc_etherdev_mqs らしいんですが、これは net/ethernet/eth.c で定義されている模様です。

struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
				      unsigned int rxqs)
{
	return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs);
}

これはまた。。
alloc_netdev_mqs 手続きは net/core/dev.c で定義されてました。ここで実際の領域確保やら初期化やらをヤッてるみたいですね。
あら、関数ポインタ渡してこの中で呼び出してますね。

 *	Allocates a struct net_device with private data area for driver use
 *	and performs basic initialization.  Also allocates subquue structs
 *	for each queue on the device.
 */
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
		void (*setup)(struct net_device *),
		unsigned int txqs, unsigned int rxqs)
{

ethernet 固有の設定、ということなのか。

とりあえず

週末に以下二冊の NIC なドライバな記述を読みつつ云々する方向で。

ちなみに

checkpatch してみたらエラーがわんさか出てきたのは秘密。