浅析usb网络net设备g_ether.ko驱动模块注册登记流程
=========== drivers/usb/gadget/ether.c ===========
生成g_ether.ko可以在如下目录找到
/lib/modules/2.6.31-14-generic/kernel/drivers/usb/gadget/g_ether.ko
static struct usb_composite_driver eth_driver = {
.name = "g_ether",
.dev = &device_desc,
.strings = dev_strings,
.bind = eth_bind,
.unbind = __exit_p(eth_unbind),
};
static int __init init(void)
{
return usb_composite_register(ð_driver);
}
module_init(init);
=========== drivers/usb/gadget/composite.c ===========
usb_composite_register(*driver)
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
composite = driver; // composite = driver就是eth_driver
usb_gadget_register_driver(&composite_driver);
static struct usb_gadget_driver composite_driver = {
.speed = USB_SPEED_HIGH,
.bind = composite_bind,
.unbind = __exit_p(composite_unbind),
.setup = composite_setup,
.disconnect = composite_disconnect,
.suspend = composite_suspend,
.resume = composite_resume,
.driver = {
.owner = THIS_MODULE,
},
};
=========== drivers/usb/gadget/s3c2410_udc.c ===========
usb_gadget_register_driver(&composite_driver);
==> usb_gadget_register_driver( *driver);
struct s3c2410_udc *udc = the_controller;
/* Hook the driver */
udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
// 这里的driver也就是composite_driver
driver->bind (&udc->gadget) // 注册the_controller.gadget[luther.gliehttp]
==> composite_driver -> composite_bind
/* preallocate control response and buffer */
// 为控制管道申请buffer
cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); // s3c2410_ep_ops.s3c2410_udc_alloc_request
具体的gadget内容如下
static struct s3c2410_udc memory = {
.gadget = {
.ops = &s3c2410_ops,
.ep0 = &memory.ep[0].ep,
.name = gadget_name,
.dev = {
.init_name = "gadget",
},
},
/* control endpoint */
.ep[0] = {
.num = 0,
.ep = {
.name = ep0name,
.ops = &s3c2410_ep_ops,
.maxpacket = EP0_FIFO_SIZE,
},
.dev = &memory,
},
/* first group of endpoints */
.ep[1] = {
.num = 1,
.ep = {
.name = "ep1-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
.ep[2] = {
.num = 2,
.ep = {
.name = "ep2-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
.ep[3] = {
.num = 3,
.ep = {
.name = "ep3-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 3,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
.ep[4] = {
.num = 4,
.ep = {
.name = "ep4-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 4,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
}
};
// static struct s3c2410_udc memory = {
// s3c2410_ep_ops.s3c2410_udc_alloc_request
static const struct usb_ep_ops s3c2410_ep_ops = {
.enable = s3c2410_udc_ep_enable,
.disable = s3c2410_udc_ep_disable,
.alloc_request = s3c2410_udc_alloc_request,
.free_request = s3c2410_udc_free_request,
.queue = s3c2410_udc_queue,
.dequeue = s3c2410_udc_dequeue,
.set_halt = s3c2410_udc_set_halt,
};
cdev->driver = composite; // 就是eth_driver[luther.gliehttp]
composite->bind(cdev);就是eth_driver.eth_bind
// 向config配置追加一个接口function
// 一个usb设备可以有多个配置,每个配置又可以包含多个接口,每个接口对应一个实际的
// 功能,包含多个端点[luther.gliehttp]
==> composite->bind就是eth_driver.eth_bind
gether_setup(cdev->gadget, hostaddr); // 创建名为usb%的eth网卡[luther.gliehttp]
++==> net->netdev_ops = ð_netdev_ops; // 设置eth网卡的ops方法集
usb_add_config(cdev, ð_config_driver); // 向composite设备追加一个配置eth_config_driver
==> usb_add_config(*cdev, *config)
list_add_tail(&config->list, &cdev->configs); // 将该配置添加到cdev的配置链表上[luther.gliehttp]
config->bind(config); // eth_config_driver.bind = eth_do_config;
==> eth_do_config(config)
geth_bind_config(c, hostaddr);
geth = kzalloc(sizeof *geth, GFP_KERNEL); // 新建func
geth->port.func.name = "cdc_subset"; // 为接口添加处理func函数
geth->port.func.strings = geth_strings;
geth->port.func.bind = geth_bind;
geth->port.func.unbind = geth_unbind;
geth->port.func.set_alt = geth_set_alt;
geth->port.func.disable = geth_disable;
status = usb_add_function(c, &geth->port.func); // 添加function
==> usb_add_function(c, &geth->port.func); // 向config追加一个function,一个function对应物理上的一个接口
list_add_tail(&function->list, &config->functions); // 将接口添加到配置链表上[luther.gliehttp]
function->bind(config, function); // 执行geth_bind
==> geth_bind(*c, *f) // usb_add_function
geth = func_to_geth(f);
// 从cdev->gadget描述的ep中获取一个合适的in端点[luther.gliehttp]
geth->port.in_ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc);
geth->port.out_ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc);
geth->fs.in = usb_find_endpoint(fs_eth_function,
f->descriptors, &fs_subset_in_desc);
geth->fs.out = usb_find_endpoint(fs_eth_function,
f->descriptors, &fs_subset_out_desc);
看看geth->port.func.set_alt即geth_set_alt什么时候被调用(pc下发使能接口ctrl控制命令)
只有当pc机向嵌入式设备的usb发出USB_REQ_SET_CONFIGURATION控制消息,
执行设备配置描述符时才会调用设置配置函数[luther.gliehttp]
set_config
==> f->set_alt(f, tmp, 0);就是geth_set_alt
==> gether_connect(&geth->port)
dev->port_usb = link; // 即link = &geth->port
alloc_requests(dev, link, qlen(dev->gadget));
// 如下为usb网卡的in和out数据收发端点各自申请n个req,添加到dev->tx_reqs和dev->rx_reqs上,这样
// 就保证了dev->tx_reqs和dev->rx_reqs至少有1个req存在[luther.gliethttp]
++==> prealloc(&dev->tx_reqs, link->in_ep, n); // 为in_ep端点申请n个req,s3c2410_ep_ops.s3c2410_udc_alloc_request
++==> prealloc(&dev->rx_reqs, link->out_ep, n);// 为out_ep端点申请n个req
具体细节可以参看
《关于usb网络net设备g_ether.ko 数据的irq中断接收》看看gadget.ep_list什么时候添加了所有ep的.
static struct platform_driver udc_driver_2410 = {
.driver = {
.name = "s3c2410-usbgadget",
.owner = THIS_MODULE,
},
.probe = s3c2410_udc_probe,
.remove = s3c2410_udc_remove,
.suspend = s3c2410_udc_suspend,
.resume = s3c2410_udc_resume,
};
==> s3c2410_udc_probe
s3c2410_udc_probe
==> s3c2410_udc_reinit
==> list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); // 组织static struct s3c2410_udc memory中的ep[]到gadget.ep_list链表上
最后net->netdev_ops = ð_netdev_ops; // 设置eth网卡的ops方法集
static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_stop,
.ndo_start_xmit = eth_start_xmit,
.ndo_change_mtu = ueth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
1. 打开usb网络设备时将执行eth_open
2. 向usb网络设备发送数据时,将执行eth_start_xmit
3. 从usb接收到网络数据时,执行rx_complete ==> netif_rx(skb);