This is the first post in a series about TP-link TL-WN722N wifi adapter. it’s a cool little gadget that provides wifi over USB. This post is about usb registration from the linux driver.

Let’s dive into the deep end which is the USB driver.The usb interface would eventually register network device and cfg80211 devices for ioctl

starting with entry point in the driver

module_init(rtw_drv_entry);
module_exit(rtw_drv_halt);

rtw_drv_entry calls usb_register to register this driver (short and sweet).

static int __init rtw_drv_entry(void)
{
	ret = usb_register(&usb_drv.usbdrv);

Note that usb_drv is global inside that file and defined as follows:

struct rtw_usb_drv {
	struct usb_driver usbdrv;
	int drv_registered;
	u8 hw_type;
};

struct rtw_usb_drv usb_drv = {
	.usbdrv.name = (char *)DRV_NAME,
	.usbdrv.probe = rtw_drv_init,
	.usbdrv.disconnect = rtw_dev_remove,
	.usbdrv.id_table = rtw_usb_id_tbl,
	.usbdrv.suspend =  rtw_suspend,
	.usbdrv.resume = rtw_resume,

Well, that was easy! not so fast. This is just the registration the usb ops that USB core will call to probe the devices.

in rtw_drv_init

	if (rtw_os_ndevs_init(dvobj) != _SUCCESS)
		goto free_if_vir;

rtw_os_ndevs_init is important beause it has import init methods rtw_os_ndevs_register and rtw_os_ndevs_alloc

	if (rtw_os_ndevs_alloc(dvobj) != _SUCCESS)
		goto exit;

	if (rtw_os_ndevs_register(dvobj) != _SUCCESS)
		goto os_ndevs_free;

in rtw_os_ndevs_alloc, there is rtw_os_ndev_alloc called

status = rtw_os_ndev_alloc(adapter);

in rtw_os_ndev_alloc

ndev = rtw_init_netdev(adapter);

in rtw_init_netdev, rtw_hook_if_ops is called.

rtw_hook_if_ops(pnetdev);

in rtw_hook_if_ops the device ops are assigned.

void rtw_hook_if_ops(struct net_device *ndev)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
	ndev->netdev_ops = &rtw_netdev_ops;
#else
	ndev->init = rtw_ndev_init;
	ndev->uninit = rtw_ndev_uninit;
	ndev->open = netdev_open;
	ndev->stop = netdev_close;
	ndev->hard_start_xmit = rtw_xmit_entry;
	ndev->set_mac_address = rtw_net_set_mac_address;
	ndev->get_stats = rtw_net_get_stats;
	ndev->do_ioctl = rtw_ioctl;
#endif
}

and rtw_netdev_ops defines the net device ops for rtw device

static const struct net_device_ops rtw_netdev_ops = {
	.ndo_init = rtw_ndev_init,
	.ndo_uninit = rtw_ndev_uninit,
	.ndo_open = netdev_open,
	.ndo_stop = netdev_close,
	.ndo_start_xmit = rtw_xmit_entry,

in the second important call is rtw_os_ndevs_register, there is rtw_os_ndev_register called

	if (rtw_os_ndev_register(adapter, name) != _SUCCESS)

in rtw_os_ndev_register

	if (rtnl_lock_needed)
		ret = (register_netdev(ndev) == 0) ? _SUCCESS : _FAIL;
	else
		ret = (register_netdevice(ndev) == 0) ? _SUCCESS : _FAIL;