This is the first post in a series about the 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 devices and cfg80211 devices for ioctl.
Starting with the 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 of the USB ops that the 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 because it has important 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 the 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, 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;