GCT GDM72xx WiMAX chip (4)
coderetreat のファシリテイト中に usb 限定で掘削を。
とりあえず
struct net_device_ops を基に掘削してみます。定義は以下で
static struct net_device_ops gdm_netdev_ops = { .ndo_open = gdm_wimax_open, .ndo_stop = gdm_wimax_close, .ndo_set_config = gdm_wimax_set_config, .ndo_start_xmit = gdm_wimax_tx, .ndo_get_stats = gdm_wimax_stats, .ndo_set_mac_address = gdm_wimax_set_mac_addr, .ndo_do_ioctl = gdm_wimax_ioctl, };
register_wimax_device 手続きで struct net_device なオブジェクトの netdev_ops 属性にセットされてます。
SET_NETDEV_DEV(dev, pdev); dev->mtu = 1400; dev->netdev_ops = &gdm_netdev_ops; dev->flags &= ~IFF_MULTICAST; memcpy(dev->dev_addr, gdm_wimax_macaddr, sizeof(gdm_wimax_macaddr));
で、もう少し云々されてから register_netdev 手続きに渡されています。register_netdev 手続きは net/core/dev.c で定義されています。コメントによると rtnl なセマフォを云々する形で register_netdevice 手続き呼び出しの wrapper になっているようです。
int register_netdev(struct net_device *dev) { int err; rtnl_lock(); err = register_netdevice(dev); rtnl_unlock(); return err; }
wrap されている register_netdevice 手続きも dev.c で定義されてます。
* Take a completed network device structure and add it to the kernel * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate.
で、register_netdev した後に start_rx_proc という手続きを呼び出してます。これはこないだ見た通り、usb か sdio かで実装なナニが異なる形。
start_rx_proc の定義が以下で
static void start_rx_proc(struct nic *nic) { gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic); }
gdm_wimax_rcv_with_cb の定義が以下。
#define gdm_wimax_rcv_with_cb(n, c, b) \ (n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b)
start_rx_proc 手続きの引数な nic の状態で諸々変わってくる、と。ちなみに nic->phy_dev は register_wimax_device 手続きの引数で渡される phy_dev が設定されてますね。
int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev) { /* snip */ nic->phy_dev = phy_dev;
gdm_usb.c から register_wimax_device 手続きを呼び出しているのは gdm_usb_probe 手続きですね。
以下でオブジェクト生成して初期化して
phy_dev = kzalloc(sizeof(*phy_dev), GFP_KERNEL); if (phy_dev == NULL) { /* snip */ phy_dev->priv_dev = (void *)udev; phy_dev->send_func = gdm_usb_send; phy_dev->rcv_func = gdm_usb_receive;
register_wimax_device 手続き呼び出しています。
ret = register_wimax_device(phy_dev, &intf->dev);
と、いうことで start_rx_proc 手続き呼び出しは諸々を経由して gdm_usb.c の gdm_usb_receive 手続きが呼び出されることになる模様 (sdio は別となるはず)。
gdm_usb_receive 手続き
今日はここ核心で掘削の方向。つうかちょっと気になるナニが一点。手続き先頭で第一引数を云々してます。
static int gdm_usb_receive(void *priv_dev, void (*cb)(void *cb_data, void *data, int len), void *cb_data) { struct usbwm_dev *udev = priv_dev;
この根拠はどこでしょ、と言いつつ諸々確認。元々の呼び出し自体は以下な形で
start_rx_proc(nic);
上記は以下の wrapper で
static void start_rx_proc(struct nic *nic) { gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic); }
さらに上記は下記マクロになってる訳で
#define gdm_wimax_rcv_with_cb(n, c, b) \ (n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b)
最終的に gdm_usb_receive に渡される priv_dev は nic->phy_dev->prov_dev になるのかな。ええと、phy_dev なオブジェクトを生成してるのは gdm_usb.c 側になるはず。
て、gdm_usb_probe 手続き見てみたら、ありました。
phy_dev->priv_dev = (void *)udev; phy_dev->send_func = gdm_usb_send; phy_dev->rcv_func = gdm_usb_receive;
多分上でも引用してるはず。udev もこの手続きで生成してますね。上記引用の直上で以下なナニ。
udev = kzalloc(sizeof(*udev), GFP_KERNEL); if (udev == NULL) { ret = -ENOMEM; goto out; } if (idProduct == 0x7205 || idProduct == 0x7206) udev->padding = GDM7205_PADDING; else udev->padding = 0; phy_dev->priv_dev = (void *)udev;
udev の定義は以下ですね。
struct usbwm_dev *udev = NULL;
gdm_usb_receive 手付きでも同じ型にキャストされてます。む、でも以下な記述がありますね。
struct usbwm_dev *udev = priv_dev; struct usb_device *usbdev = udev->usbdev; struct rx_cxt *rx = &udev->rx; struct usb_rx *r; unsigned long flags; if (!udev->usbdev) { dev_err(&usbdev->dev, "%s: No such device\n", __func__); return -ENODEV; }
属性設定されてる前提だな。register_wimax_device 手続き側で phy_dev に云々してるのかどうなのか。あ、gdm_usb_probe 手続きから呼び出されてる init_usb なのか。udev 渡してますね。
ret = init_usb(udev);
定義は gdm_usb.c な模様。とは言え、usbdev な属性はスルーだな (rx な属性の初期設定はヤッてます)。あ、上記呼び出し直下で以下な式を発見orz
udev->usbdev = usbdev;
この usbdev なソレは interface_to_usbdev 手続きで取得してますね。
struct usb_device *usbdev = interface_to_usbdev(intf);
うーん、gdm_usb_probe から何してるか、をちゃんと確認した方が良さげですね。
gdm_usb_probe 手続き
順に確認。まず、struct usb_device オブジェクトを引数の struct usb_interface オブジェクトから取得しています。
struct usb_device *usbdev = interface_to_usbdev(intf);
む、直下の以下は何だ。
usb_get_dev(usbdev);
定義が drivers/usb/core/usb.c で以下。
struct usb_device *usb_get_dev(struct usb_device *dev) { if (dev) get_device(&dev->dev); return dev; }
戻りは相手にしてないのに一体何だよ、と思ったら手続き定義のコメントが以下で
* Drivers for USB interfaces should normally record such references in * their probe() methods, when they bind to an interface, and release * them by calling usb_put_dev(), in their disconnect() methods.
どうも何かしてるクサい。get_device の中で kobject_get を呼んでます。
return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL;
kobject_get で以下 (一部のみ)。
kref_get(&kobj->kref);
kref_get が以下。
nstatic inline void kref_get(struct kref *kref) { WARN_ON(!atomic_read(&kref->refcount)); atomic_inc(&kref->refcount); }
リファレンスカウント増分させてますね。成程。kobject_get の手続き定義なコメントに記述がありますね。
* kobject_get - increment refcount for object.
ええと struct usb_device オブジェクトの dev 属性 (struct device 型) の kobj な属性の refcount 属性を ++ してるのか。ちなみに kboj な属性のコメントが以下。
* @kobj: A top-level, abstract class from which other classes are derived.
閑話休題。リファレンスカウント++ して以降の暫くはスルーします。
bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue; /*USB description is set up with Little-Endian*/ idVendor = L2H(usbdev->descriptor.idVendor); idProduct = L2H(usbdev->descriptor.idProduct); bcdDevice = L2H(usbdev->descriptor.bcdDevice); dev_info(&intf->dev, "Found GDM USB VID = 0x%04x PID = 0x%04x...\n", idVendor, idProduct); dev_info(&intf->dev, "GCT WiMax driver version %s\n", DRIVER_VERSION); if (idProduct == EMERGENCY_PID) { ret = usb_emergency(usbdev); goto out; } /* Support for EEPROM bootloader */ if (bConfigurationValue == DOWNLOAD_CONF_VALUE || idProduct & B_DOWNLOAD) { ret = usb_boot(usbdev, bcdDevice); goto out; }
で、これ以降で struct phy_dev な領域および struct usbwm_dev な領域を確保しています。
phy_dev = kzalloc(sizeof(*phy_dev), GFP_KERNEL); if (phy_dev == NULL) { ret = -ENOMEM; goto out; } udev = kzalloc(sizeof(*udev), GFP_KERNEL); if (udev == NULL) { ret = -ENOMEM; goto out; }
で、idProduct の値で udev の padding 属性の値をキメて
if (idProduct == 0x7205 || idProduct == 0x7206) udev->padding = GDM7205_PADDING; else udev->padding = 0;
phy_dev の属性の初期設定をして
phy_dev->priv_dev = (void *)udev; phy_dev->send_func = gdm_usb_send; phy_dev->rcv_func = gdm_usb_receive;
init_usb 手続きで udev な領域の初期設定してます。
ret = init_usb(udev); if (ret < 0) goto out;
基本的に、srtruct usbwm_dev 型の tx および rx な属性の初期設定をしてます。で、この後、usbdev 属性に先頭で引数な struct usb_interface オブジェクトから取り出した struct usb_device なオブジェクトを usbdev 属性にセットしておおよその初期設定が終了、という形になっているのかどうか。
udev->usbdev = usbdev;
CONFIG_WIMAX_GDM72XX_USB_PM が #define されているかどうかによりますが、この後は register_wimax_device 手続きが呼び出される形になっています。
とりあえず
これを踏まえて明日以降で gdm_usb_receive を確認してみます。