linux ttyusb读写_浅析usb转serial串口设备在linux内核中枚举创建及生成tty设备的全过程...

浅析usb转serial串口设备在linux内核中枚举创建及生成tty设备的全过程1.usb_register和usb_register_driver用来注册一个interface接口驱动for_devices = 0;2.usb_register_device_driver用来注册一个usb设备驱动,for_devices = 1;用来解析设备描述符,进而生成配置描述符下的功能接口,尝试匹配us...
摘要由CSDN通过智能技术生成

浅析usb转serial串口设备在linux内核中枚举创建及生成tty设备的全过程

1.usb_register和usb_register_driver用来注册一个interface接口驱动for_devices = 0;

2.usb_register_device_driver用来注册一个usb设备驱动,for_devices = 1;用来解析设备描述符,

进而生成配置描述符下的功能接口,尝试匹配usb_register_driver注册的接口驱动来驱动该usb设备的功能接口.[luther.gliethttp]

在整个kernel中,只有usb_init即[subsys_initcall(usb_init)]一处调用了usb_register_device_driver函数,

usb_register_device_driver(&usb_generic_driver, THIS_MODULE);所以所有通过hub_thread检测到插入的usb设备也都将调用到

generic_probe设备枚举函数,我们这里需要提到一些usb通信方面的知识,以便我们能够透彻理解kernel中usb代码,

一个插入到HUB上的usb设备使用4种描述符来描述自己,

(1) 设备描述符

(2) 配置描述符

(3) 接口描述符

(4) 端点描述符

一个usb设备只能有1个设备描述符,1个设备描述符可以有多个配置描述符,然后每个配置描述符下面又可以有多个接口描述符用来

具体描述一个设备在该配置下的一个或多个独立功能,每个接口下面又由端点描述符来具体声明该功能接口在usb物理通信中使用哪几个

端点管道来执行usb物理信道的实际收发工作[luther.gliethttp].

所以一个usb设备的具体功能是由接口描述符来描述的,因此我们开发的usb driver也就几乎99.9%都在使用usb_register函数来实现一个

接口对应的驱动,进而驱动usb设备上该接口对应的具体功能,比如UMS.[luther.gliethttp]

当kernel使用generic_probe()函数完成插入到HUB上的usb设备的合法检验之后,将调用设置配置描述符操作usb_set_configuration,

生成该配置描述符下面若干个接口描述符对应的dev设备,

usb_set_configuration

==>device_add(&intf->dev);

// 这样该接口dev将扫描usb_bus_type总线上的所有drivers驱动,kernel尝试为该接口dev找到驱动它的driver.[luther.gliethttp]

如下几个函数中都会调用到usb_set_configuration

usb_authorize_device    // 以sysfs中attr性质存在,这样用户空间的程序就可以通过attr属性文件来强制控制接口驱动的关联.

usb_deauthorize_device

driver_set_config_work

proc_setconfig

set_bConfigurationValue

generic_disconnect

generic_probe

usb设备的检测工作是通过内核线程hub_thread完成的.

usb_hub_init==>khubd_task = kthread_run(hub_thread, NULL, "khubd"); // 创建内核线程hub_thread,监控hub上usb设备的插拔情况

hub_thread

==>hub_events

==>hub_port_connect_change==>udev =usb_alloc_dev // 添加usb设备

==>hub_port_connect_change==>usb_new_device(udev)==>device_add(&udev->dev); // 将检测到的usb设备添加到usb_bus_type总线上,

// 该dev的type值为usb_device_type,最后函数执行device_add==>bus_add_device实现具体添加操作[luther.gliethttp]

// bus_add_device将调用上面usb_register_device_driver(&usb_generic_driver, THIS_MODULE);注册的唯一一个设备描述符解析驱动

// usb_generic_driver==>generic_probe来完成接口设备生成和相应的接口设备驱动关联动作[luther.gliethttp].

usb_add_hcd==>usb_alloc_dev // 添加HCD

usb_alloc_dev

==>dev->dev.bus = &usb_bus_type;设置dev为usb总线上的设备

==>dev->dev.type = &usb_device_type;设置该dev为usb设备而非接口

driver_register或者device_register

调用driver_attach或者bus_attach_device==>device_attach

来为设备尝试匹配驱动或者为驱动尝试添加设备,不论是哪一种情况,都将

执行到:driver_probe_device函数.

int driver_probe_device(struct device_driver *drv, struct device *dev)

{

int ret = 0;

if (!device_is_registered(dev)) // 1.设备已经完成了注册到bus总线工作

return -ENODEV;

if (drv->bus->match && !drv->bus->match(dev, drv)) // 2.执行bus提供的match操作usb_device_match

goto done;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",

drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);

ret = really_probe(dev, drv); // bus的match通过检验,这里做进一步的probe检验,

// 如果bus提供了probe,那么执行bus->probe(dev);

// 否则执行driver提供的probe函数drv->probe(dev);

done:

return ret;

}

usb_register(&mct_u232_driver);

==>usb_register_driver

new_driver->drvwrap.for_devices = 0; // 仅仅用来驱动interface接口,所以上面hub_port_connect_change由usb_alloc_dev生成的usb设备不会调用该usb接口驱动

new_driver->drvwrap.driver.bus = &usb_bus_type;

new_driver->drvwrap.driver.probe = usb_probe_interface; // 当检测到usb设备插入后,将调用usb_probe_interface进行细致处理

// 提供为device_driver提供probe处理函数,因为bus总线usb_bus_type不提供probe操作[luther.gliethttp]

==>driver_register(&new_driver->drvwrap.driver); // 将驱动添加到usb bus总线管理的driver驱动链表上

usb_device_match==>is_usb_device

static inline int is_usb_device(const struct device *dev)

{

return dev->type == &usb_device_type;

}

开看看驱动hub_thread==>usb_alloc_dev创建的插入到HUB上的usb设备的probe函数generic_probe.[luther.gliethttp]

subsys_initcall(usb_init);

==>usb_init

==>usb_register_device_driver(&usb_generic_driver, THIS_MODULE);

struct usb_device_driver usb_generic_driver = {

.name =    "usb",

.probe = generic_probe,

.disconnect = generic_disconnect,

#ifdef    CONFIG_PM

.suspend = generic_suspend,

.resume = generic_resume,

#endif

.supports_autosuspend = 1,

};

==>generic_probe

==>usb_set_configuration // 生成该设置配置描述下的所有接口描述符所描述的接口dev对象

==>ret = device_add(&intf->dev);

int usb_set_configuration(struct usb_device *dev, int configuration)

{

int i, ret;

struct usb_host_config *cp = NULL;

struct usb_interface **new_interfaces = NULL;

int n, nintf;

if (dev->authorized == 0 || configuration == -1)

configuration = 0;

else {

for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {

if (dev->config[i].desc.bConfigurationValue ==

configuration) {

cp = &dev->config[i];

break;

}

}

}

if ((!cp && configuration != 0))

return -EINVAL;

/* The USB spec says configuration 0 means unconfigured.

* But if a device includes a configuration numbered 0,

* we will accept it as a correctly configured state.

* Use -1 if you really want to unconfigure the device.

*/

if (cp && configuration == 0)

dev_warn(&dev->dev, "config 0 descriptor??\n");

/* Allocate memory for new interfaces before doing anything else,

* so that if we run out then nothing will have changed. */

n = nintf = 0;

if (cp) {

nintf = cp->desc.bNumInterfaces;

new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),

GFP_KERNEL);

if (!new_interfaces) {

dev_err(&dev->dev, "Out of memory\n");

return -ENOMEM;

}

for (; n < nintf; ++n) {

new_interfaces[n] = kzalloc(

sizeof(struct usb_interface),

GFP_KERNEL);

if (!new_interfaces[n]) {

dev_err(&dev->dev, "Out of memory\n");

ret = -ENOMEM;

free_interfaces:

while (--n >= 0)

kfree(new_interfaces[n]);

kfree(new_interfaces);

return ret;

}

}

i = dev->bus_mA - cp->desc.bMaxPower * 2;

if (i < 0)

dev_warn(&dev->dev, "new config #%d exceeds power "

"limit by %dmA\n",

configuration, -i);

}

/* Wake up the device so we can send it the Set-Config request */

ret = usb_autoresume_device(dev);

if (ret)

goto free_interfaces;

/* if it's already configured, clear out old state first.

* getting rid of old interfaces means unbinding their drivers.

*/

if (dev->state != USB_STATE_ADDRESS)

usb_disable_device(dev, 1);    /* Skip ep0 */

ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),

USB_REQ_SET_CONFIGURATION, 0, configuration, 0,

NULL, 0, USB_CTRL_SET_TIMEOUT);

if (ret < 0) {

/* All the old state is gone, so what else can we do?

* The device is probably useless now anyway.

*/

cp = NULL;

}

dev->actconfig = cp;

if (!cp) {

usb_set_device_state(dev, USB_STATE_ADDRESS);

usb_autosuspend_device(dev);

goto free_interfaces;

}

usb_set_device_state(dev, USB_STATE_CONFIGURED);

/* Initialize the new interface structures and the

* hc/hcd/usbcore interface/endpoint state.

*/

for (i = 0; i < nintf; ++i) {

struct usb_interface_cache *intfc;

struct usb_interface *intf;

struct usb_host_interface *alt;

cp->interface[i] = intf = new_interfaces[i];

intfc = cp->intf_cache[i];

intf->altsetting = intfc->altsetting;

intf->num_altsetting = intfc->num_altsetting;

intf->intf_assoc = find_iad(dev, cp, i);

kref_get(&intfc->ref);

alt = usb_altnum_to_altsetting(intf, 0);

/* No altsetting 0?  We'll assume the first altsetting.

* We could use a GetInterface call, but if a device is

* so non-compliant that it doesn't have altsetting 0

* then I wouldn't trust its reply anyway.

*/

if (!alt)

alt = &intf->altsetting[0];

intf->cur_altsetting = alt;

usb_enable_interface(dev, intf);

intf->dev.parent = &dev->dev;

intf->dev.driver = NULL;

intf->dev.bus = &usb_bus_type; // 位于usb_bus_type总线

intf->dev.type = &usb_if_device_type; // 为接口设备,这样在usb_device_match中将去和接口驱动去匹配[luther.gliethttp]

intf->dev.dma_mask = dev->dev.dma_mask;

device_initialize(&intf->dev);

mark_quiesced(intf);

sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",

dev->bus->busnum, dev->devpath,

configuration, alt->desc.bInterfaceNumber);

}

kfree(new_interfaces);

if (cp->string == NULL)

cp->string = usb_cache_string(dev, cp->desc.iConfiguration);

/* Now that all the interfaces are set up, register them

* to trigger binding of drivers to interfaces.  probe()

* routines may install different altsettings and may

* claim() any interfaces not yet bound.  Many class drivers

* need that: CDC, audio, video, etc.

*/

for (i = 0; i < nintf; ++i) {

struct usb_interface *intf

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值