http://blog.chinaunix.net/uid-20786208-id-3160786.html

上一节我们已经讲到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;
}
这里我们看到粗体部分为关键函数,新设备默认为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卡热插拔那些事2相关推荐

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

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

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

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

  3. Linux USB 驱动开发—— 热插拔

    转自:https://blog.csdn.net/zqixiao_09/article/details/51056903 学习USB热插拔之前,先学习一些USB的硬件知识. 一.USB基础概念 1.硬 ...

  4. Android usb读卡器sd卡热插拔心得

    Android usb读卡器sd卡热插拔心得 最近跟usb打了一段时间交道,处理了一些storage方面的项目需求,现在记录一些调试思路,同时分享给一些有缘人,希望能够给予一些灵感. 平台是qnx h ...

  5. 手机sim卡插到电脑上网_你知道吗?关于手机SIM卡的一些事

    手机市场上流传着一句话"一入电信深似海,从此手机真难买."为何这样说?三大运营商手机SIM卡看起来都一样,但各种卡想要正确使用起来却有讲究,大家知道吗?此外对于双卡和单卡+micr ...

  6. USB 3G网卡驱动流程

    USB 3G网卡驱动流程 简介 首先介绍一下linux下的整体驱动模式: 本文基于的linux kernel版本为2.6.36 (并且华为EM770W驱动,是由FriendlyARM公司定制的. 所以 ...

  7. 模拟usb设备_高速USB数据采集卡

    高速USB数据采集卡 同步.高速 USB-1602HS&1604HS 系列 该系列设备提供了最高4路模拟输入通道,采样率最高可达2MS/s/Ch,外加最高2路模拟输出,4路计数器和3路编码器测 ...

  8. USB 3G驱动和USB HOST驱动加载

    ********************************LoongEmbedded******************************** 作者:LoongEmbedded(kandi ...

  9. Linux下实现USB口的热插拔

    目前要做一个在嵌入式平台上的USB口的热插拔事件. 经过我现在的分析总结目前有如下方法: 1,定时检查/proc/scsi/scsi文件 此方法只能在PC上,但在嵌入式平台上不可用. 2,netlin ...

最新文章

  1. Spark-Spark setMaster WordCount Demo
  2. sources root pycharm 怎么设置_使用python语言开发ROOT之搭建环境方法探索
  3. python重要吗-毫无基础,商英专业,Python真的有用吗?
  4. 什么是async、await?
  5. Window下git生成SSH Key以及格式转换
  6. 性能测试之性能测试的基础理论
  7. [TCP/IP] TCP如何实现流量控制和拥塞控制
  8. thinkphp3.1迁移php7,ThinkPHP3.1迁移到PHP7的注意事项
  9. php怎么给接口里的方法传参,PHP接口中方法的参数和实现类方法中的参数可以不一致的问题...
  10. cannot mount database in EXCLUSIVE mode
  11. mysql st_contains实现_MySQL实现树状所有子节点查询的方法
  12. extjs Grid(一)
  13. Linux下如何查看定位当前正在运行的Nginx的配置文件
  14. Tensorflow函数映射:py_func和map_fn
  15. R语言 数据整理(reshape2)
  16. 《运算放大器权威指南》读书笔记(三)
  17. PPT转视频——小内存
  18. Ubuntu 18.04 镜像下载
  19. Keil编译*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
  20. 2021年最后一天,学点Selenium玩点新鲜~新的一年,让分布式测试有更多玩法

热门文章

  1. iOS coding多人协作开发工具
  2. 【给程序员英语学习的一些建议】我是乔治老师,我在这里播报。
  3. 三星oneui主屏幕费电_三星One UI初体验,你想要的使用感受都在这里
  4. mysql查询日期:本周、上周、本月、上月
  5. 行星怎么画简单又漂亮,有手就会系列,超级简单!
  6. Python计算向量夹角:向量夹角计算方法详解
  7. 推荐一位北航技术大佬,手握 GitHub 14000 颗小星星
  8. SPSS_Logistic回归分析结果表中的英文字母意思
  9. matlab绘图(1)
  10. Vue2 大型项目升级 Vue3 详细经验总结