转载了一个比较详细的关于USB 3G上网卡的讲解,原文地址:
http://blog.chinaunix.net/uid-20786208-id-3157021.html


USB 3G卡热插拔那些事1——原理框架

这里我们先讲讲USB热插拔事件的处理工作。—–Khubd守护进程。
-Khubd守护进程它是一个守护进程,来检查usb port的事件通知HCD和usb core,然后做相应的处理。
驱动目录drivers/usb/*
usb/serial usb 串行设备驱动 (例如usb 3G卡、蓝牙等)
usb/storage usb 大储量磁盘驱动(u盘)
usb/host usb host usb主机控制器驱动(嵌入式otg:dwc_otg)
usb/core usb 核心一些处理代码,所有的驱动相关处理都在这里,也都注册到它里面。
usb/usb-skeleton.c 经典的usb客户驱动框架,可以参考。
当然还有其他这里不再说明。

下面贴出USB的整体驱动框架:

这里我们主要分析khub的工作原理: 硬件层次是hub的工作,如何和host及其设备间通信及相应事件
看usb/core/hub.c

int usb_hub_init(void)
{if (usb_register(&hub_driver) < 0) {printk(KERN_ERR "%s: can't register hub driver\n",usbcore_name);return -1;}khubd_task = kthread_run(hub_thread, NULL, "khubd");if (!IS_ERR(khubd_task))return 0;/* Fall through if kernel_thread failed */usb_deregister(&hub_driver);printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);return -1;
}

这里我们只关心kthread_run(hub_thread, NULL, “khubd”); 然后我们看hub_thread函数

static int hub_thread(void *__unused)
{do {hub_events();wait_event_interruptible(khubd_wait,!list_empty(&hub_event_list) ||kthread_should_stop());try_to_freeze();} while (!kthread_should_stop() || !list_empty(&hub_event_list));pr_debug("%s: khubd exiting\n", usbcore_name);return 0;
}

这里我们看到了hub_events()函数。然后设置运行状态,如果有事件就加入hub_event_list
自此khubd运行起来了。
这里我们同样贴出它的函数调用流程图。

通过流程图我们可以清晰的明白,当usb设备插入usb接口后,khubd运行,它检测到port状态的变化
调用hub_port_connect_change(),如果是新设备那么usb_allco_dev,然后调用usb_new_device来进行配置使usb设备可以正常工作。详细流程请看源码。

USB 3G卡热插拔那些事2 ——usb_new_device

我们已经讲到usb_new_device来初始化设备配置,然后让设备工作,我们知道这之前,首先hub检测到端口电流变化,然后分配usb设备地址,申请设备,获取设备一些描述性信息(这些信息有助于以后总线match和probe函数来check是否支持这个设备和找到相应的驱动)。这里我们首先展开usb_new_device这个函数看看它到底做了什么工作。

/*** usb_new_device - perform initial device setup (usbcore-internal)* @udev: newly addressed device (in ADDRESS state)** This is called with devices which have been enumerated, but not yet* configured.  The device descriptor is available, but not descriptors* for any device configuration.  The caller must have locked either* the parent hub (if udev is a normal device) or else the* usb_bus_list_lock (if udev is a root hub).  The parent's pointer to* udev has already been installed, but udev is not yet visible through* sysfs or other filesystem code.** Returns 0 for success (device is configured and listed, with its* interfaces, in sysfs); else a negative errno value.** This call is synchronous, and may not be used in an interrupt context.** Only the hub driver or root-hub registrar should ever call this.*/
int usb_new_device(struct usb_device *udev)
{int err;int c;err = usb_get_configuration(udev);if (err < 0) {dev_err(&udev->dev, "can't read configurations, error %d\n",err);goto fail;}/* read the standard strings and cache them if present */udev->product = usb_cache_string(udev, udev->descriptor.iProduct);udev->manufacturer = usb_cache_string(udev,udev->descriptor.iManufacturer);udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);/* Tell the world! */dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, ""SerialNumber=%d\n",udev->descriptor.iManufacturer,udev->descriptor.iProduct,udev->descriptor.iSerialNumber);show_string(udev, "Product", udev->product);show_string(udev, "Manufacturer", udev->manufacturer);show_string(udev, "SerialNumber", udev->serial);#ifdef  CONFIG_USB_OTG/** OTG-aware devices on OTG-capable root hubs may be able to use SRP,* to wake us after we've powered off VBUS; and HNP, switching roles* "host" to "peripheral".  The OTG descriptor helps figure this out.*/if (!udev->bus->is_b_host&& udev->config&& udev->parent == udev->bus->root_hub) {struct usb_otg_descriptor   *desc = 0;struct usb_bus          *bus = udev->bus;/* descriptor may appear anywhere in config */if (__usb_get_extra_descriptor (udev->rawdescriptors[0],le16_to_cpu(udev->config[0].desc.wTotalLength),USB_DT_OTG, (void **) &desc) == 0) {if (desc->bmAttributes & USB_OTG_HNP) {unsigned        port1 = udev->portnum;struct usb_device   *root = udev->parent;dev_info(&udev->dev,"Dual-Role OTG device on %sHNP port\n",(port1 == bus->otg_port)? "" : "non-");/* enable HNP before suspend, it's simpler */if (port1 == bus->otg_port)bus->b_hnp_enable = 1;err = usb_control_msg(udev,usb_sndctrlpipe(udev, 0),USB_REQ_SET_FEATURE, 0,bus->b_hnp_enable? USB_DEVICE_B_HNP_ENABLE: USB_DEVICE_A_ALT_HNP_SUPPORT,0, NULL, 0, USB_CTRL_SET_TIMEOUT);if (err < 0) {/* OTG MESSAGE: report errors here,* customize to match your product.*/dev_info(&udev->dev,"can't set HNP mode; %d\n",err);bus->b_hnp_enable = 0;}}}}if (!is_targeted(udev)) {/* Maybe it can talk to us, though we can't talk to it.* (Includes HNP test device.)*/if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {static int __usb_suspend_device(struct usb_device *,int port1);err = __usb_suspend_device(udev, udev->bus->otg_port);if (err < 0)dev_dbg(&udev->dev, "HNP fail, %d\n", err);}err = -ENODEV;goto fail;}
#endif/* put device-specific files into sysfs */err = device_add (&udev->dev);if (err) {dev_err(&udev->dev, "can't device_add, error %d\n", err);goto fail;}usb_create_sysfs_dev_files (udev);usb_lock_device(udev);/* choose and set the configuration. that registers the interfaces* with the driver core, and lets usb device drivers bind to them.*/c = choose_configuration(udev);if (c >= 0) {err = usb_set_configuration(udev, c);if (err) {dev_err(&udev->dev, "can't set config #%d, error %d\n",c, err);/* This need not be fatal.  The user can try to* set other configurations. */}}/* USB device state == configured ... usable */usb_notify_add_device(udev);usb_unlock_device(udev);
return 0;fail:usb_set_device_state(udev, USB_STATE_NOTATTACHED);
    return err;
}

这里我们主要看usb_get_configuration(udev)device_add (&udev->dev)usb_create_sysfs_dev_files(udev)choose_configuration(udev)usb_set_configuration(udev, c)为关键函数,新设备默认为host控制器总线下从设备。首先从外设获取配置信息
usb_get_configuration(),然后是device_add()这里完成了设备的注册,当然包括设备总线的注册,以及在设备模型中的注册,而真正热插拔事件处理函数是uevent(在lld3中是hotplug函数,不过看2.6以后的内核全部为uevent),这个函数指针初始化是在总线bus_type初始化的时候初始化的,在usb.c文件中代码如下:

struct bus_type usb_bus_type = {.name =     "usb",.match =    usb_device_match,.uevent =   usb_uevent,.suspend =  usb_generic_suspend,.resume =   usb_generic_resume,
};

我们知道在一个usb设备check的过程中,当设备被注册进usb core后,就是设备的总线的一系列的函数的工作(包括match、probe、uevent)。uevent它的作用就是把内核的一些环境变量传递到用户空间,以便通知用户空间做出相应的事件。
这里我们简单说一下match函数:

int usb_device_match(struct device *dev, struct device_driver *drv)
{struct usb_interface *intf;struct usb_driver *usb_drv;const struct usb_device_id *id;/* check for generic driver, which we don't match any device with */if (drv == &usb_generic_driver)return 0;intf = to_usb_interface(dev);usb_drv = to_usb_driver(drv);id = usb_match_id(intf, usb_drv->id_table);if (id)return 1;id = usb_match_dynamic_id(intf, usb_drv);if (id)return 1;return 0;
}

这里我们只需要关注usb_match_id()这个函数即可,让我们可以真正明白一个热插拔设备识别和检测的机制是如何运作的。这里还要说明一下首先总线检验总线是否支持这个设备,如果支持那么才去找相应的驱动是否支持它,如果支持就和他bind在一起,那么这个设备就可以工作了。我们可以通过/proc来查看usb设备的信息:
#cat /proc/bus/usb/devices
当然我们知道3G卡插入usb口,首先识别出来的是U盘,即加载的是storage驱动,那么我们需要通过usb_modemswitch工具来把它转换成modem模式 (就是usb 串行工作模式 / *usb 串行设备 */),它会把总线初始化为usb_serial_bus,并加载usb serial驱动(usb/serial目录下option.c) 而这个通知事件就是通过上边提过的uevent这个函数来完成。如果直接是usb serial设备那么它会直接识别为usb serial总线,并加载相应的驱动。例如有些U盘还附带bluetooth的功能,bluetooth就是串行设备。那么下一节我们将分析usb serial相关驱动。

USB 3G上网卡讲解之一相关推荐

  1. USB 3G上网卡讲解之三

    USB 3G卡热插拔那些事4--pppd 在上一节中我们知道3G卡设备驱动已经加载好了,并且和ttyUSB*已经绑定成功,意味着我们可以拨号了,和3G卡内部3G模块通信了,而我们知道3G模块通信是tt ...

  2. 使用USB 3G上网卡+树莓派搭建接受短信自动转发邮箱的服务

    背景:人在国外刚下飞机   咳咳,人在国外,国内很多网络,电话服务都需要短信验证,一直以来都用的双卡手机来解决这个问题.最近换了单卡手机,琢磨着3g上网卡应该可以接受短信,再配合7D24H运行的树莓派 ...

  3. 3G上网卡2_编程自动切换模式学习笔记

    为什么要切换模式: 3G上网卡自带程序,接到PC后先作为移动硬盘使用,安装程序后切换为modem 如何自动切换模式 1. 编写控制程序自动使用各种型号3G上网卡 a. usb_modeswitch - ...

  4. 中兴AC2746 usb接口的3G上网卡

    嵌入式linux是2.6.24版的.主机是AT9261(arm926ej-s内核)的开发板. 买是市面上常见的中兴AC2746 usb接口的3G上网卡.在windows下使用极方便,可是在linux下 ...

  5. openwrt使用3G上网卡

    尊敬的大大.感谢你抽空指导我 我的设备是db120 mu350 和广东无限卡 版本是OpenWrt Backfire 10.03.336 DIY full 一.        没有安装到kmod-us ...

  6. 联通3g上网卡 linux驱动,驱动天空 - 网络设备 - 联通3G上网卡WCDMA

    2015/3/6 14:19:001451 ·D-Link DWM-157联通3G上网卡 网络协议:[3G]UMTS,HSPA+:[2G]GSM,EDGE,GPRS 传输速率:下行最大14.4Mbps ...

  7. 3G上网卡在Liunx系统上实现上网的过程

    1 前言 最近因项目需要将3G 上网卡挂接到Linux的网关平台,经过一段时间的研究,基本将整个挂 接过程弄清,在此贴出来与大家共享  2 正文 首先,我们来了解一下3G上网卡的组成: USB+USB ...

  8. Linux中移植3G上网卡

    本文所用到的源码下载地址如下: libusb-1.0.9.tar.bz2         下载地址点击这里! usb-modeswitch-2.0.1.tar.bz2   下载地址点击这里! usb- ...

  9. FL2440 3G上网卡拨号上网,并实现mdev自动挂载

    ___________________________________ 主机操作系统:Centos 6.5 交叉编译器环境:arm-linux-gcc-4.5.4 开发板平台: FL2440     ...

最新文章

  1. oracle io profile,ORACLE 中 PROFILE的管理
  2. Matlab2013a安装简单教程以及遇到的问题解决(反复提示激活问题)
  3. mysql备份数据库命令
  4. for(;;)是什么,for(;;)的作用
  5. java中日历类:Calendar
  6. servlet为什么要别名呢_servlet --2
  7. json接收与发送(转自csdnblog)
  8. ai第二次热潮:思维的转变_基于属性的建议:科技创业公司如何使用AI来转变在线评论和建议
  9. 淘宝技术这十年(淘宝技术大学校长解密淘宝十年)
  10. 语音转文字的测试用例
  11. BZOJ 1213 HNOI2004 高精度开根 二分+高(Py)精(thon)度
  12. 很全很强大的图形学相关的论文和源码
  13. Bada学习-多任务模式
  14. 余承东 鸿蒙不是手机,余承东解密华为鸿蒙OS2.0:不是手机操作系统的简单替代-社会-文章-小虾米...
  15. 一只特立独行的“猿”
  16. C语言/C++常见习题问答集锦(四十三) 之持之以恒
  17. 这种鱼被吃了也拼命求生!刺穿捕食者的胃想跑出来
  18. 时间运算函数 CATT_ADD_TO_TIME
  19. RTThread中falut定位方法
  20. htc升级鸿蒙,厉害了!这4款HTC手机将升级至安卓9.0:全是U系列

热门文章

  1. [OpenCV实战]29 使用OpenCV实现红眼自动去除
  2. Java Math.tan()/Math.tanh()具有什么功能呢?
  3. 如何设计接口协议,实现一个优秀SDK
  4. Wordpress搭建(初学者)
  5. 哪些Apple设备支持这次系统更新?来看你的旧Apple设备支持最新系统吗
  6. 股票入门基础知识21:什么是股息收益率(DY)
  7. 手机管理应用研究【3】—— 垃圾清理篇
  8. 论文插图用计算机绘制,论文中插图和表格的绘制种类
  9. 基于Gitlab Issues为导向的分支管理
  10. 数据恢复基础和进阶教程(三)