Chinaunix首页 | 论坛 | 博客
  • 博客访问: 62271
  • 博文数量: 28
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-30 01:24
文章分类
文章存档

2017年(1)

2016年(5)

2015年(22)

我的朋友

分类:

2015-10-13 09:54:34

浅析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);
阅读(2739) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~