浅析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;用来解析
·
浅析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设备的功能接口. 在整个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物理信道的实际收发工作. 所以一个usb设备的具体功能是由接口描述符来描述的,因此我们开发的usb driver也就几乎99.9%都在使用usb_register函数来实现一个 接口对应的驱动,进而驱动usb设备上该接口对应的具体功能,比如UMS. 当kernel使用generic_probe()函数完成插入到 HUB上的usb设备的合法检验之后,将调用设置配置描述符操作usb_set_configuration, 生成该配置描述符下面若干个接口描述符对应的dev设备, usb_set_configuration ==> device_add(&intf->dev); // 这样该接口dev将扫描usb_bus_type总线上的所有drivers驱动,kernel尝试为该接口dev找到驱动它的driver. 如下几个函数中都会调用到 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 ==& gt;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实现具体添加操作 // bus_add_device将调用上面 usb_register_device_driver(&usb_generic_driver, THIS_MODULE);注册的唯一一个设备描述符解析驱动 // usb_generic_driver==>generic_probe来完成接口设备生成和相应的接口设备驱动关联动作 . 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操作 ==>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. 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中将去和接口驱动去匹配 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 = cp->interface[i]; dev_dbg(&dev->dev, "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, intf->cur_altsetting->desc.bInterfaceNumber); ret = device_add(&intf->dev); // 将接口设备添加bus总线上同时到sysfs系统中. if (ret != 0) { dev_err(&dev->dev, "device_add(%s) --> %d\n", intf->dev.bus_id, ret); continue; } usb_create_sysfs_intf_files(intf); } usb_autosuspend_device(dev); return 0; } 如下是一个整体代码流程: 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_bus_type ==>usb_device_match static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { /* interface drivers never match devices */ if (!is_usb_device_driver(drv)) return 0; /* TODO: Add real matching code */ return 1; } else { struct usb_interface *intf; struct usb_driver *usb_drv; const struct usb_device_id *id; /* device drivers never match interfaces */ if (is_usb_device_driver(drv)) return 0; intf = to_usb_interface(dev); // 转为接口dev设备 usb_drv = to_usb_driver(drv); // 转为usb驱动 id = usb_match_id(intf, usb_drv->id_table); // 接口设备与usb接口驱动的id_table值表进行匹配尝试 if (id) return 1; id = usb_match_dynamic_id(intf, usb_drv); if (id) return 1; } return 0; } ==>really_probe static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0; atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __FUNCTION__, drv->name, dev->bus_id); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; // 先假定该driver就是驱动本dev的驱动,后面讲做进一步确认 if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __FUNCTION__, dev->bus_id); goto probe_failed; } if (dev->bus->probe) { ret = dev->bus->probe(dev); // 如果bus总线提供probe,那么执行之 if (ret) goto probe_failed; } else if (drv->probe) { ret = drv->probe(dev); // 如果driver提供probe,那么执行之, // 我们这里就是new_driver->drvwrap.driver.probe = usb_probe_interface; if (ret) goto probe_failed; } driver_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __FUNCTION__, dev->bus_id, drv->name); goto done; probe_failed: devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; if (ret != -ENODEV && ret != -ENXIO) { /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, ret); } /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; } ==>usb_probe_interface 即:new_driver->drvwrap.driver.probe = usb_probe_interface; /* called from driver core with dev locked */ static int usb_probe_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf; struct usb_device *udev; const struct usb_device_id *id; int error = -ENODEV; dev_dbg(dev, "%s\n", __FUNCTION__); if (is_usb_device(dev)) /* Sanity check */ return error; intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); if (udev->authorized == 0) { dev_err(&intf->dev, "Device is not authorized for usage\n"); return -ENODEV; } id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); if (id) { dev_dbg(dev, "%s - got id\n", __FUNCTION__); error = usb_autoresume_device(udev); if (error) return error; /* Interface "power state" doesn't correspond to any hardware * state whatsoever. We use it to record when it's bound to * a driver that may start I/0: it's not frozen/quiesced. */ mark_active(intf); intf->condition = USB_INTERFACE_BINDING; /* The interface should always appear to be in use * unless the driver suports autosuspend. */ intf->pm_usage_cnt = !(driver->supports_autosuspend); error = driver->probe(intf, id); // 调用usb_driver驱动定义的probe函数,我们这里就是usb_serial_probe 即:mct_u232_driver.probe if (error) { mark_quiesced(intf); intf->needs_remote_wakeup = 0; intf->condition = USB_INTERFACE_UNBOUND; } else intf->condition = USB_INTERFACE_BOUND; usb_autosuspend_device(udev); } return error; } ==>usb_serial_probe 即:mct_u232_driver.probe函数 int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev (interface); struct usb_serial *serial = NULL; struct usb_serial_port *port; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; struct usb_serial_driver *type = NULL; int retval; int minor; int buffer_size; int i; int num_interrupt_in = 0; int num_interrupt_out = 0; int num_bulk_in = 0; int num_bulk_out = 0; int num_ports = 0; int max_endpoints; lock_kernel(); /* guard against unloading a serial driver module */ type = search_serial_device(interface); // 遍历usb_serial_driver_list链表,搜索与该interface匹配上的串口驱动, // usb_serial_driver_list链表元素由函数usb_serial_driver_list添加 // 我们这里将返回type = &mct_u232_device;[luther.gliethtp] /* static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { const struct usb_device_id *id; struct usb_serial_driver *drv; list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { id = get_iface_id(drv, iface); if (id) return drv; } return NULL; } ==>usb_serial_register // 添加serial驱动到usb_serial_driver_list链表上 static struct usb_serial_driver mct_u232_device = {...}; usb_serial_register(&mct_u232_device); // 注册mct_u232串口驱动到usb_serial_driver_list链表上 int usb_serial_register(struct usb_serial_driver *driver) { int retval; fixup_generic(driver); // 填入driver没有定义的默认方法 if (!driver->description) driver->description = driver->driver.name; // Add this device to our list of devices list_add(&driver->driver_list, &usb_serial_driver_list); // 将mct_u232_device添加到usb_serial_driver_list链表上 retval = usb_serial_bus_register(driver); if (retval) { err("problem %d when registering driver %s", retval, driver->description); list_del(&driver->driver_list); } else info("USB Serial support registered for %s", driver->description); return retval; } int usb_serial_bus_register(struct usb_serial_driver *driver) { int retval; driver->driver.bus = &usb_serial_bus_type; spin_lock_init(&driver->dynids.lock); INIT_LIST_HEAD(&driver->dynids.list); retval = driver_register(&driver->driver); return retval; } */ if (!type) { unlock_kernel(); dbg("none matched"); return -ENODEV; } serial = create_serial (dev, interface, type); // 创建serial串口设备 /* static struct usb_serial * create_serial (struct usb_device *dev, struct usb_interface *interface, struct usb_serial_driver *driver) { struct usb_serial *serial; serial = kzalloc(sizeof(*serial), GFP_KERNEL); // 全0空间 if (!serial) { dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); return NULL; } serial->dev = usb_get_dev(dev); // 该serial对应的usb设备描述符对应的设备结构体 serial->type = driver; // 该serial对应的driver serial->interface = interface; // 该serial对应的interface kref_init(&serial->kref); mutex_init(&serial->disc_mutex); return serial; } */ if (!serial) { unlock_kernel(); dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } /* if this device type has a probe function, call it */ if (type->probe) { // mct_u232_device串口驱动没有probe函数 const struct usb_device_id *id; if (!try_module_get(type->driver.owner)) { unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } id = get_iface_id(type, interface); retval = type->probe(serial, id); module_put(type->driver.owner); if (retval) { unlock_kernel(); dbg ("sub driver rejected device"); kfree (serial); return retval; } } /* descriptor matches, let's find the endpoints needed */ /* check out the endpoints */ iface_desc = interface->cur_altsetting; // 当前接口对应的接口描述符信息 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { // 为该接口dev设备收集端点通信管道 endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_in(endpoint)) { /* we found a bulk in endpoint */ dbg("found bulk in on endpoint %d", i); bulk_in_endpoint[num_bulk_in] = endpoint; // 批量IN端点 ++num_bulk_in; } if (usb_endpoint_is_bulk_out(endpoint)) { /* we found a bulk out endpoint */ dbg("found bulk out on endpoint %d", i); bulk_out_endpoint[num_bulk_out] = endpoint; // 批量OUT端点 ++num_bulk_out; } if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ dbg("found interrupt in on endpoint %d", i); interrupt_in_endpoint[num_interrupt_in] = endpoint; // 中断IN端点 ++num_interrupt_in; } if (usb_endpoint_is_int_out(endpoint)) { /* we found an interrupt out endpoint */ dbg("found interrupt out on endpoint %d", i); interrupt_out_endpoint[num_interrupt_out] = endpoint; // 中断OUT端点 ++num_interrupt_out; } } #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) // 执行PL2303 usb转串口设备的IN端点信息特殊处理 /* BEGIN HORRIBLE HACK FOR PL2303 */ /* this is needed due to the looney way its endpoints are set up */ if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) && (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) || ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) && (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) || ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) && (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) { if (interface != dev->actconfig->interface[0]) { // 如果当前PL2303 usb转串口不等于0接口,dev->actconfig->interface[0] /* check out the endpoints of the other interface*/ iface_desc = dev->actconfig->interface[0]->cur_altsetting; // 那么将0接口中的中断IN端点添加到该serial设备中 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ dbg("found interrupt in for Prolific device on separate interface"); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } } } /* Now make sure the PL-2303 is configured correctly. * If not, give up now and hope this hack will work * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { unlock_kernel(); dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree (serial); return -ENODEV; } } /* END HORRIBLE HACK FOR PL2303 */ #endif #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { // 如果是usb_serial_generic_device驱动,那么批量OUT端点务必要存在,并且可用端点个数就是批量OUT端点个数. unlock_kernel(); dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree (serial); return -EIO; } } #endif if (!num_ports) { // 好,不是usb_serial_generic_device驱动 /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { // 是否需要调用计算函数计算端点个数 if (!try_module_get(type->driver.owner)) { unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } num_ports = type->calc_num_ports (serial); module_put(type->driver.owner); } if (!num_ports) num_ports = type->num_ports; // 由usb转串口接口驱动定义端点个数:mct_u232_device定义num_ports为 1 } serial->num_ports = num_ports; // 端点个数 serial->num_bulk_in = num_bulk_in; // 批量IN端点个数 serial->num_bulk_out = num_bulk_out; // 批量OUT端点个数 serial->num_interrupt_in = num_interrupt_in; // 中断IN端点个数 serial->num_interrupt_out = num_interrupt_out; // 中断OUT端点个数 #if 0 /* check that the device meets the driver's requirements */ if ((type->num_interrupt_in != NUM_DONT_CARE && type->num_interrupt_in != num_interrupt_in) || (type->num_interrupt_out != NUM_DONT_CARE && type->num_interrupt_out != num_interrupt_out) || (type->num_bulk_in != NUM_DONT_CARE && type->num_bulk_in != num_bulk_in) || (type->num_bulk_out != NUM_DONT_CARE && type->num_bulk_out != num_bulk_out)) { dbg("wrong number of endpoints"); kfree(serial); return -EIO; } #endif /* found all that we need */ dev_info(&interface->dev, "%s converter detected\n", type->description); /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = max(num_bulk_in, num_bulk_out); max_endpoints = max(max_endpoints, num_interrupt_in); max_endpoints = max(max_endpoints, num_interrupt_out); max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; unlock_kernel(); dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); // 申请4种端点集合结构体struct usb_serial_port if (!port) goto probe_error; port->serial = serial; spin_lock_init(&port->lock); mutex_init(&port->mutex); INIT_WORK(&port->work, usb_serial_port_work); // 设置工作队列work_queue serial->port[i] = port; } /* set up the endpoint information */ for (i = 0; i < num_bulk_in; ++i) { endpoint = bulk_in_endpoint[i]; port = serial->port[i]; port->read_urb = usb_alloc_urb (0, GFP_KERNEL); // 申请URB控制结构体 if (!port->read_urb) { dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); port->bulk_in_size = buffer_size; // 端点大小 port->bulk_in_endpointAddress = endpoint->bEndpointAddress; // 端点地址 port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); // 端点管道数据缓冲区 if (!port->bulk_in_buffer) { dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n"); goto probe_error; } // 填充上面申请到的read_urb URB控制结构体 usb_fill_bulk_urb (port->read_urb, dev, usb_rcvbulkpipe (dev, endpoint->bEndpointAddress), port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, // 在mct_u232_device中定义的批量读回调函数 port); } for (i = 0; i < num_bulk_out; ++i) { endpoint = bulk_out_endpoint[i]; port = serial->port[i]; port->write_urb = usb_alloc_urb(0, GFP_KERNEL);// 申请URB控制结构体 if (!port->write_urb) { dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); port->bulk_out_size = buffer_size; port->bulk_out_endpointAddress = endpoint->bEndpointAddress; port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->bulk_out_buffer) { dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n"); goto probe_error; } // 填充上面申请到的write_urb URB控制结构体 usb_fill_bulk_urb (port->write_urb, dev, usb_sndbulkpipe (dev, endpoint->bEndpointAddress), port->bulk_out_buffer, buffer_size, serial->type->write_bulk_callback,// 在mct_u232_device中定义的批量写回调函数 port); } if (serial->type->read_int_callback) { for (i = 0; i < num_interrupt_in; ++i) { endpoint = interrupt_in_endpoint[i]; port = serial->port[i]; port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);// 申请URB控制结构体 if (!port->interrupt_in_urb) { dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); port->interrupt_in_endpointAddress = endpoint->bEndpointAddress; port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->interrupt_in_buffer) { dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n"); goto probe_error; } // 填充上面申请到的interrupt_in_urb URB控制结构体 usb_fill_int_urb (port->interrupt_in_urb, dev, usb_rcvintpipe (dev, endpoint->bEndpointAddress), port->interrupt_in_buffer, buffer_size, serial->type->read_int_callback, port, // 在mct_u232_device中定义的INT中断读回调函数 endpoint->bInterval); } } else if (num_interrupt_in) { dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined"); } if (serial->type->write_int_callback) { for (i = 0; i < num_interrupt_out; ++i) { endpoint = interrupt_out_endpoint[i]; port = serial->port[i]; port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);// 申请URB控制结构体 if (!port->interrupt_out_urb) { dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); port->interrupt_out_size = buffer_size; port->interrupt_out_endpointAddress = endpoint->bEndpointAddress; port->interrupt_out_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->interrupt_out_buffer) { dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n"); goto probe_error; } // 填充上面申请到的interrupt_out_urb URB控制结构体 usb_fill_int_urb (port->interrupt_out_urb, dev, usb_sndintpipe (dev, endpoint->bEndpointAddress), port->interrupt_out_buffer, buffer_size, serial->type->write_int_callback, port,// 在mct_u232_device中定义的INT中断写回调函数 endpoint->bInterval); } } else if (num_interrupt_out) { dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined"); } /* if this device type has an attach function, call it */ if (type->attach) { // mct_u232_device定义了attach方法的实现 mct_u232_startup if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); goto probe_error; } retval = type->attach (serial); module_put(type->driver.owner); if (retval < 0) goto probe_error; if (retval > 0) { /* quietly accept this device, but don't bind to a serial port * as it's about to disappear */ goto exit; } } if (get_free_serial (serial, num_ports, &minor) == NULL) { // 申请次设备号,同时:serial->port[j++]->number = i; dev_err(&interface->dev, "No more free serial devices\n"); goto probe_error; } serial->minor = minor; // 该serial的次设备号为minor /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; port->dev.parent = &interface->dev; // 接口当然为端点端口的父object port->dev.driver = NULL; port->dev.bus = &usb_serial_bus_type; // port位于usb_serial_bus_type总线 port->dev.release = &port_release; snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number); dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id); retval = device_register(&port->dev); // 登记注册该port对应的dev设备信息,同样在bus总线usb_serial_bus_type上执行match动作. if (retval) dev_err(&port->dev, "Error registering port device, " "continuing\n"); } usb_serial_console_init (debug, minor); exit: /* success */ usb_set_intfdata (interface, serial); return 0; probe_error: for (i = 0; i < num_bulk_in; ++i) { port = serial->port[i]; if (!port) continue; usb_free_urb(port->read_urb); kfree(port->bulk_in_buffer); } for (i = 0; i < num_bulk_out; ++i) { port = serial->port[i]; if (!port) continue; usb_free_urb(port->write_urb); kfree(port->bulk_out_buffer); } for (i = 0; i < num_interrupt_in; ++i) { port = serial->port[i]; if (!port) continue; usb_free_urb(port->interrupt_in_urb); kfree(port->interrupt_in_buffer); } for (i = 0; i < num_interrupt_out; ++i) { port = serial->port[i]; if (!port) continue; usb_free_urb(port->interrupt_out_urb); kfree(port->interrupt_out_buffer); } /* free up any memory that we allocated */ for (i = 0; i < serial->num_port_pointers; ++i) kfree(serial->port[i]); kfree (serial); return -EIO; } ==>usb_serial_bus_type总线驱动port各种端点端口组合结构体 device_register(&port->dev); // 登记注册该port对应的dev设备信息,同样在bus总线usb_serial_bus_type上执行match动作. struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, .drv_attrs = drv_attrs, }; ==>usb_serial_device_match static int usb_serial_device_match (struct device *dev, struct device_driver *drv) { struct usb_serial_driver *driver; const struct usb_serial_port *port; /* * drivers are already assigned to ports in serial_probe so it's * a simple check here. */ port = to_usb_serial_port(dev); if (!port) return 0; driver = to_usb_serial_driver(drv); if (driver == port->serial->type) // 等于mct_u232_device驱动,那么返回1 // port->serial在serial = create_serial (dev, interface, type); 中创建. // serial->type = driver; // 该serial对应的driver return 1; return 0; } ==>usb_serial_device_probe static int usb_serial_device_probe (struct device *dev) { struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; int minor; port = to_usb_serial_port(dev); if (!port) { retval = -ENODEV; goto exit; } driver = port->serial->type; if (driver->port_probe) { // mct_u232_device没有port_probe if (!try_module_get(driver->driver.owner)) { dev_err(dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } retval = driver->port_probe (port); module_put(driver->driver.owner); if (retval) goto exit; } retval = device_create_file(dev, &dev_attr_port_number); // 创建sysfs文件系统中对应的文件 if (retval) goto exit; minor = port->number; // 在上面的get_free_serial函数中执行了serial->port[j++]->number = i;赋值操作,所以可以为 ttyUSB0,ttyUSB1,... // port->number就是serial_table[port->number]数组索引号 tty_register_device (usb_serial_tty_driver, minor, dev); // 注册次设备号为minor的tty设备,该/dev/ttyUSBx设备由usb_serial_tty_driver驱动程序管理 dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d\n", driver->description, minor); exit: return retval; } ==>tty_register_device(usb_serial_tty_driver, minor, dev); // usb_serial_tty_driver在usb_serial_init, 即:module_init(usb_serial_init); // usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; // tty_set_operations(usb_serial_tty_driver, &serial_ops); // tty_register_driver(usb_serial_tty_driver);==>list_add(&driver->tty_drivers, &tty_drivers);将自己添加到tty_drivers链表中 struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; if (index >= driver->num) { printk(KERN_ERR "Attempt to register invalid tty line number " " (%d).\n", index); return ERR_PTR(-EINVAL); } if (driver->type == TTY_DRIVER_TYPE_PTY) pty_line_name(driver, index, name); else tty_line_name(driver, index, name); // 非pty设备 return device_create(tty_class, device, dev, name); // 创建sysfs文件系统下的文件,同时uevent到用户空间,创建/dev/ttyUSB0... 等 // 对/dev/ttyUSB0...等操作方法为tty_fops // /dev/ttyUSB0...等在SERIAL_TTY_MAJOR ~ SERIAL_TTY_MAJOR + SERIAL_TTY_MINORS之间的设备号读写操作均由 tty_fops // 方法集提供, // tty_register_driver(usb_serial_tty_driver); // 比如open // tty_open==>tty->driver->open 即:serial_ops.serial_open } ==>tty_register_driver(usb_serial_tty_driver); // 注册驱动/dev/xxx字符设备的tty驱动程序 dev = MKDEV(driver->major, driver->minor_start); error = register_chrdev_region(dev, driver->num, driver->name); // 设备号从dev到dev+driver->num个字符设备都将由该driver驱动 cdev_init(&driver->cdev, &tty_fops); // 注册该MAJOR到MINOR之间的/dev/xxx字符设备节点对应的操作函数集为 tty_fops cdev_add(&driver->cdev, dev, driver->num); // 添加到字符管理数值中 static const struct file_operations tty_fops = { .llseek = no_llseek, .read = tty_read, .write = tty_write, .poll = tty_poll, .ioctl = tty_ioctl, .compat_ioctl = tty_compat_ioctl, .open = tty_open, .release = tty_release, .fasync = tty_fasync, }; ==>cdev_add int cdev_add(struct cdev *p, dev_t dev, unsigned count) { p->dev = dev; p->count = count; return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); // 将&driver->cdev添加到cdev_map字符设备驱动管理数组中,以备下面sys_open时 kobj_lookup使用 } 看看系统调用open函数 open("/dev/ttyUSB0") ==>chrdev_open // sys_open将调用字符设备驱动函数集中open函数chrdev_open const struct file_operations def_chr_fops = { .open = chrdev_open, }; ==>kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); // 搜索上面cdev_add登记的usb_serial_tty_driver驱动 调用exact_match返回&driver->cdev.kobj new = container_of(kobj, struct cdev, kobj); inode->i_cdev = p = new; // 由上面cdev_init(&driver->cdev, &tty_fops); 初始化cdev->ops = &tty_fops filp->f_op = fops_get(p->ops); // 获取驱动方法集 filp->f_op->open(inode,filp); ==>tty_open同时在tty_drivers链表上调用get_tty_driver函数搜索, "/dev/ttyUSB0"设备节点号对应的tty_drivers,比如搜索到usb_serial_tty_driver驱动, 那么它就是tty->driver了.同时生成tty:init_dev(driver, index, &tty);其中index表示该字符设备为驱动管理的第index索引处设备. 之后init_dev==>tty = alloc_tty_struct(); ==>initialize_tty_struct(tty); // 初始化该tty的ldisc等于tty_ldisc_N_TTY即tty->ldisc = &tty_ldisc_N_TTY; tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));为tty->ldisc绑定线路规程 console_init==>注册tty_ldisc_N_TTY线路规程 & nbsp; tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); struct tty_ldisc tty_ldisc_N_TTY = { .magic = TTY_LDISC_MAGIC, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, .flush_buffer = n_tty_flush_buffer, .chars_in_buffer = n_tty_chars_in_buffer, .read = read_chan, .write = write_chan, .ioctl = n_tty_ioctl, .set_termios = n_tty_set_termios, .poll = normal_poll, .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup }; ==>tty->driver = driver; ==>tty->index = idx; // 该tty在driver中的索引值 ==>tty_line_name(driver, idx, tty->name); ==>driver->ttys[idx] = tty; // dirver管理的第index个设备指针 ==>(tty->ldisc.open)(tty); // 调用tty_ldisc_N_TTY.open即n_tty_open函数 之后filp->private_data = tty; 之后tty->driver->open ==>tty-> driver->open就是usb_serial_tty_driver.open 即:serial_ops.serial_open ==>serial_open // 执行设备实际打开操作 static int serial_open (struct tty_struct *tty, struct file * filp) { struct usb_serial *serial; struct usb_serial_port *port; unsigned int portNumber; int retval; dbg("%s", __FUNCTION__); /* get the serial object associated with this tty pointer */ serial = usb_serial_get_by_index(tty->index); // 就是 return serial_table[index];因为driver的串口索引就等于serial_table数组的索引. if (!serial) { tty->driver_data = NULL; return -ENODEV; } portNumber = tty->index - serial->minor; // 端口号为当前dev设备的串口索引index减去该serial设备登记的起始索引值,比如一个 // serial设备可以有多个port,比如有3个,那么portNumber就可能等于0,1或者2. port = serial->port[portNumber]; // 获取'/dev/ttyUSBx'对应的port if (!port) { retval = -ENODEV; goto bailout_kref_put; } if (mutex_lock_interruptible(&port->mutex)) { retval = -ERESTARTSYS; goto bailout_kref_put; } ++port->open_count; /* set up our port structure making the tty driver * remember our port object, and us it */ tty->driver_data = port; // 驱动driver_data似有数据为port port->tty = tty; // 该port服务于该tty if (port->open_count == 1) { // 第1次打开 /* lock this module before we call it * this may fail, which means we must bail out, * safe because we are called with BKL held */ if (!try_module_get(serial->type->driver.owner)) { retval = -ENODEV; goto bailout_mutex_unlock; } retval = usb_autopm_get_interface(serial->interface); if (retval) goto bailout_module_put; /* only call the device specific open if this * is the first time the port is opened */ retval = serial->type->open(port, filp); // 执行mct_u232_device.open 即:mct_u232_open if (retval) goto bailout_interface_put; } mutex_unlock(&port->mutex); return 0; // ok,至此sys_open工作就算彻底完成了 bailout_interface_put: usb_autopm_put_interface(serial->interface); bailout_module_put: module_put(serial->type->driver.owner); bailout_mutex_unlock: port->open_count = 0; tty->driver_data = NULL; port->tty = NULL; mutex_unlock(&port->mutex); bailout_kref_put: usb_serial_put(serial); return retval; } tty_write ==>do_tty_write(ld->write, tty, file, buf, count);调用线路规程tty_ldisc_N_TTY的write函数write_chan ==> write_chan ==>tty->driver->write(tty, b, nr);就是上面的usb_serial_tty_driver.write 即:serial_ops.serial_write ==>serial_write将调用port-& gt;serial->type->write(port, buf, count);就是mct_u232_device的write函数 在usb_serial_register(&mct_u232_device);中将使用 fixup_generic(driver);函数填充mct_u232_device未定义的操作函数集. 所以mct_u232_device的write函数为usb_serial_generic_write ==> mct_u232_device.write即:usb_serial_generic_write ==> usb_serial_generic_write ==>usb_submit_urb(port->write_urb, GFP_ATOMIC); // 提交一个URB ==>usb_hcd_submit_urb(urb, mem_flags); ==>hcd->driver->urb_enqueue(hcd, urb, mem_flags); tty_read ==>(ld->read)(tty, file, buf, count);调用线路规程tty_ldisc_N_TTY的read函数read_chan ==> read_chan 在mct_u232_device中定义了mct_u232_read_int_callback,即中断IN回调函数,当usb转串口设备从usb接口接收到数据之后, 它将执行mct_u232_read_int_callback回调函数, static void mct_u232_read_int_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct mct_u232_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int retval; int status = urb->status; unsigned long flags; switch (status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); return; default: dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); goto exit; } if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } dbg("%s - port %d", __FUNCTION__, port->number); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* * Work-a-round: handle the 'usual' bulk-in pipe here */ if (urb->transfer_buffer_length > 2) { int i; tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); // 将从usb接收到的数据放入tty缓冲区中 } tty_flip_buffer_push(tty); // 唤醒pending着的read_chan函数,这样tty就收到数据了 } goto exit; } /* * The interrupt-in pipe signals exceptional conditions (modem line * signal changes and errors). data[0] holds MSR, data[1] holds LSR. */ spin_lock_irqsave(&priv->lock, flags); priv->last_msr = data[MCT_U232_MSR_INDEX]; /* Record Control Line states */ mct_u232_msr_to_state(&priv->control_state, priv->last_msr); #if 0 /* Not yet handled. See belin_sa.c for further information */ /* Now to report any errors */ priv->last_lsr = data[MCT_U232_LSR_INDEX]; /* * fill in the flip buffer here, but I do not know the relation * to the current/next receive buffer or characters. I need * to look in to this before committing any code. */ if (priv->last_lsr & MCT_U232_LSR_ERR) { tty = port->tty; /* Overrun Error */ if (priv->last_lsr & MCT_U232_LSR_OE) { } /* Parity Error */ if (priv->last_lsr & MCT_U232_LSR_PE) { } /* Framing Error */ if (priv->last_lsr & MCT_U232_LSR_FE) { } /* Break Indicator */ if (priv->last_lsr & MCT_U232_LSR_BI) { } } #endif spin_unlock_irqrestore(&priv->lock, flags); exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", __FUNCTION__, retval); } todo ... mct_u232_device 驱动位于usb_serial_bus_type总线上,mct_u232_driver驱动位于usb_bus_type总线上,当hub发现usb新 硬件之后,会首先调用usb_bus_type总线上的mct_u232_driver驱动的probe(),也就是 usb_serial_probe(),在usb_serial_probe()中,程序会遍历usb_serial_driver_list驱动链表的 所有驱动,并usb_serial_driver_list尝试和发现的新硬件进行匹配,在计算匹配的过程中会调 用,drv->bus->match,即:usb_serial_bus_type->match()和 dev->bus->probe或者drv->probe 即:usb_serial_device_probe(),这样设备就和分别 处在两条独立总线上的mct_u232_driver驱动以及mct_u232_device驱动关联上了 |
更多推荐
已为社区贡献5条内容
所有评论(0)