usb摄像头驱动-core层USB集线器(Hub)驱动

news/2024/4/19 0:46:43

usb摄像头驱动-core层USB集线器(Hub)驱动


文章目录

  • usb摄像头驱动-core层USB集线器(Hub)驱动
  • usb_hub_init
  • hub_probe
  • hub_event
  • port_event
  • hub_port_connect_change
  • hub_port_connect
  • usb_new_device
  • announce_device


在这里插入图片描述

在USB摄像头驱动中,hub.c文件扮演着USB集线器(Hub)驱动的角色。USB集线器是用于连接多个USB设备的设备,它提供了额外的USB端口,并负责数据传输的分配和管理。hub.c文件中的内容主要涉及USB集线器的初始化、事件处理、数据传输和管理等功能。以下是该文件中常见的功能和作用的概括:

  1. 集线器的初始化和设备连接管理:

    • 检测和识别连接到集线器的USB设备。
    • 分配和配置集线器的USB端口。
    • 跟踪已连接设备的状态和属性,如端口状态、速度等。
    • 处理设备的插拔事件,并通知相应的驱动程序进行设备的初始化或释放。
  2. 端口状态和速度管理:

    • 监控集线器端口的状态变化,如设备插入或拔出。
    • 管理端口的电源状态、连接状态和速度信息。
    • 处理集线器和设备之间的速度协商和协议转换。
  3. 数据传输和分配:

    • 为连接到集线器的设备分配传输带宽。
    • 管理端口和传输通道的分配和释放。
    • 处理数据的转发和路由,确保正确的数据传输路径。
  4. 集线器事件和通知处理:

    • 监听和处理集线器和端口相关的事件,如连接状态变化、错误状态等。
    • 向上层驱动程序和应用程序发送事件通知,以便它们可以做出相应的处理。
  5. 集线器电源管理:

    • 管理集线器的电源控制,如启用/禁用电源、进入/退出睡眠状态等。
    • 处理集线器的电源管理策略,如自动挂起、节能模式等。

总体而言,hub.c文件中的内容实现了USB摄像头驱动中与USB集线器相关的功能,包括集线器的初始化、事件处理、数据传输和管理等。它负责管理USB集线器和连接的USB设备之间的通信,并确保数据的正确传输和设备的正常运行。

/driver/usb/core/hub.c

usb_hub_init

在内核中,这个函数通常在系统启动期间的初始化阶段被调用。具体来说,它会在USB子系统初始化期间被调用。
这个函数的主要作用是初始化USB hub驱动程序。USB hub是一种用于扩展USB接口的设备,它允许将多个USB设备连接到单个USB端口上。USB hub驱动程序负责管理和控制USB hub设备,并处理与USB设备的连接、断开、通信等操作。
在函数内部,它会注册USB hub驱动程序,使得内核能够正确识别和处理连接到USB hub的设备。它还分配一个工作队列(workqueue),用于处理USB hub相关的后台任务,例如处理连接和断开USB设备的事件。
总之,这个函数在内核中的作用是初始化USB hub驱动程序,确保USB hub设备能够正常工作并与其他USB设备进行通信。它是USB子系统中重要的初始化函数之一。

static struct usb_driver hub_driver = {.name =        "hub", // 驱动程序名称.probe =    hub_probe, // 探测函数.disconnect =    hub_disconnect, // 断开连接函数.suspend =    hub_suspend, // 暂停函数.resume =    hub_resume, // 恢复函数.reset_resume =    hub_reset_resume, // 重置恢复函数.pre_reset =    hub_pre_reset, // 重置前函数.post_reset =    hub_post_reset, // 重置后函数.unlocked_ioctl = hub_ioctl, // ioctl函数.id_table =    hub_id_table, // 设备表.supports_autosuspend =    1, // 支持自动挂起
};
// 初始化USB hub驱动程序
int usb_hub_init(void)
{// 注册USB hub驱动程序if (usb_register(&hub_driver) < 0) {printk(KERN_ERR "%s: 无法注册hub驱动程序\n",usbcore_name);return -1;}/** 工作队列需要是可冻结的,以避免干扰USB-PERSIST端口移交。* 否则,它可能会在EHCI控制器将其端口移交给附属全速控制器之前看到一个全速设备已经消失。*/hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);if (hub_wq)return 0;/* 如果kernel_thread失败,则跳过 */usb_deregister(&hub_driver);pr_err("%s: 无法为USB hub分配工作队列\n", usbcore_name);return -1;
}

这个函数是用于初始化USB hub驱动程序的。下面是对函数的分析:

  1. 首先,通过调用usb_register(&hub_driver)来注册USB hub驱动程序。usb_register函数返回一个小于0的值表示注册失败。如果注册失败,会打印错误信息并返回-1。
  2. 接下来,函数尝试为USB hub分配一个工作队列(workqueue)。工作队列是用于异步执行后台任务的机制。它使用alloc_workqueue函数进行分配,并设置为可冻结(WQ_FREEZABLE)。如果成功分配工作队列,函数将返回0。
  3. 如果无法分配工作队列,说明内核线程(kernel_thread)失败。在这种情况下,函数调用usb_deregister(&hub_driver)来取消注册之前注册的USB hub驱动程序,以避免不完整的初始化。然后打印错误信息并返回-1。

总体而言,这个函数的目标是注册USB hub驱动程序并分配一个工作队列。如果其中任何一个步骤失败,函数将返回-1,表示初始化过程出现问题。
/driver/usb/core/hub.c

hub_probe

这个函数是一个USB hub驱动程序中的probe函数,它在与USB hub设备匹配时被调用。下面是对该函数的作用的解释:
作用:

  1. 该函数用于处理USB hub设备的探测和初始化过程。当一个USB设备与这个驱动程序匹配时,就会调用该函数。

  2. 在probe函数中,可以执行与特定设备相关的初始化任务,例如配置设备、分配资源、注册设备接口等。

  3. 通过该函数,驱动程序可以与内核USB子系统进行交互,以确保设备正确识别并能够与其他子系统进行通信。

  4. 在probe函数中,还可以注册设备的操作函数和回调函数,以处理设备的读写操作、事件处理等。

总之,这个函数的作用是处理与USB hub设备的探测和初始化相关的任务,以确保设备能够正常工作并与其他子系统进行通信。它是USB hub驱动程序中重要的函数之一。

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{struct usb_host_interface *desc; // USB主机接口描述符struct usb_endpoint_descriptor *endpoint; // USB端点描述符struct usb_device *hdev; // USB设备struct usb_hub *hub; // USB集线器desc = intf->cur_altsetting; // 获取当前USB接口的描述符hdev = interface_to_usbdev(intf); // 获取USB设备/** Set default autosuspend delay as 0 to speedup bus suspend,* based on the below considerations:** - Unlike other drivers, the hub driver does not rely on the*   autosuspend delay to provide enough time to handle a wakeup*   event, and the submitted status URB is just to check future*   change on hub downstream ports, so it is safe to do it.** - The patch might cause one or more auto supend/resume for*   below very rare devices when they are plugged into hub*   first time:**      devices having trouble initializing, and disconnect*      themselves from the bus and then reconnect a second*      or so later**      devices just for downloading firmware, and disconnects*      themselves after completing it**   For these quite rare devices, their drivers may change the*   autosuspend delay of their parent hub in the probe() to one*   appropriate value to avoid the subtle problem if someone*   does care it.** - The patch may cause one or more auto suspend/resume on*   hub during running 'lsusb', but it is probably too*   infrequent to worry about.** - Change autosuspend delay of hub can avoid unnecessary auto*   suspend timer for hub, also may decrease power consumption*   of USB bus.** - If user has indicated to prevent autosuspend by passing*   usbcore.autosuspend = -1 then keep autosuspend disabled.*/
#ifdef CONFIG_PMif (hdev->dev.power.autosuspend_delay >= 0)pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
#endif/** Hubs have proper suspend/resume support, except for root hubs* where the controller driver doesn't have bus_suspend and* bus_resume methods.*/if (hdev->parent) {     /* 普通设备 */usb_enable_autosuspend(hdev); // 启用自动挂起} else {            /* 根集线器 */const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver;if (drv->bus_suspend && drv->bus_resume)usb_enable_autosuspend(hdev); // 启用自动挂起}if (hdev->level == MAX_TOPO_LEVEL) { // 如果设备层级过深dev_err(&intf->dev,"Unsupported bus topology: hub nested too deep\n"); // 输出错误信息return -E2BIG; // 返回错误码}#ifdef  CONFIG_USB_OTG_BLACKLIST_HUBif (hdev->parent) {dev_warn(&intf->dev, "ignoring external hub\n");return -ENODEV;}
#endif/* Some hubs have a subclass of 1, which AFAICT according to the *//*  specs is not defined, but it works */if ((desc->desc.bInterfaceSubClass != 0) &&(desc->desc.bInterfaceSubClass != 1)) { // 如果子类不为0或1
descriptor_error:dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); // 输出错误信息return -EIO; // 返回错误码}/* Multiple endpoints? What kind of mutant ninja-hub is this? */ // 多个端点?这是什么神奇的集线器?if (desc->desc.bNumEndpoints != 1) // 如果端点数不为1goto descriptor_error; // 跳转到错误处理endpoint = &desc->endpoint[0].desc; // 获取端点描述符/* If it's not an interrupt in endpoint, we'd better punt! */ // 如果不是中断端点,我们最好放弃!if (!usb_endpoint_is_int_in(endpoint)) // 如果不是中断输入端点goto descriptor_error; // 跳转到错误处理/* We found a hub */ // 我们找到了一个集线器dev_info (&intf->dev, "USB hub found\n"); // 输出信息hub = kzalloc(sizeof(*hub), GFP_KERNEL); // 分配内存if (!hub) { // 如果分配失败dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); // 输出调试信息return -ENOMEM; // 返回错误码}kref_init(&hub->kref); // 初始化引用计数hub->intfdev = &intf->dev; // 设置接口设备hub->hdev = hdev; // 设置USB设备INIT_DELAYED_WORK(&hub->leds, led_work); // 初始化延迟工作INIT_DELAYED_WORK(&hub->init_work, NULL); // 初始化延迟工作INIT_WORK(&hub->events, hub_event); // 初始化工作usb_get_intf(intf); // 获取接口usb_get_dev(hdev); // 获取USB设备usb_set_intfdata (intf, hub); // 设置接口数据intf->needs_remote_wakeup = 1; // 设置需要远程唤醒pm_suspend_ignore_children(&intf->dev, true); // 忽略子设备的挂起if (hdev->speed == USB_SPEED_HIGH) // 如果速度为高速highspeed_hubs++; // 高速集线器数加1if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND) // 如果驱动信息中包含检查端口自动挂起的标志hub->quirk_check_port_auto_suspend = 1; // 设置检查端口自动挂起的标志if (hub_configure(hub, endpoint) >= 0) // 如果配置集线器成功return 0; // 返回0hub_disconnect (intf); // 断开集线器return -ENODEV; // 返回错误码
}
  1. 获取USB接口描述符和USB设备。

  2. 根据设备类型和层级判断设备是否为普通设备或根集线器,并根据情况启用自动挂起功能。

  3. 验证USB hub设备的描述符是否有效,包括子类和端点的检查。

  4. 分配内存并初始化USB hub结构体,设置相关参数和工作队列。

  5. 设置接口数据和设备引用计数,设置需要远程唤醒,并忽略子设备的挂起。

  6. 根据设备的速度和驱动信息进行相应处理,例如统计高速集线器数和设置检查端口自动挂起的标志。

  7. 如果配置集线器成功,返回0;否则断开集线器并返回错误码。

总之,这个函数的主要功能是初始化USB hub设备并进行相关设置,以确保设备能够正常工作。它涉及到USB设备描述符的验证、内存分配、参数设置等操作,是USB hub驱动程序中关键的探测和初始化函数之一
line1811:

INIT_WORK(&hub->events, hub_event); // 初始化工作

这行代码创建了一个名为events的工作结构体,并将其初始化为待处理的工作任务。hub_event函数是在这个工作任务被调度时将会执行的函数。
通过初始化工作结构体,可以将特定的函数(例如hub_event)与一个工作队列相关联,以便在适当的时机异步执行这个函数。这对于处理USB hub设备的事件或异步操作非常有用,因为可以将这些任务放入工作队列中,并在适当的时候由内核调度执行,而不会阻塞其他任务的执行。
总之,INIT_WORK(&hub->events, hub_event);这行代码的作用是初始化一个工作结构体,并将其与hub_event函数关联,以便在适当的时机异步执行hub_event函数的任务。

hub_event

hub_probe->hub_event

在内核中,static void hub_event(struct work_struct *work)函数是USB hub驱动程序中的一个工作函数,用于处理USB hub设备的事件。
这个函数在特定的工作队列中被调度执行,以处理与USB hub相关的事件。通常,在USB hub设备发生状态变化、端口插拔、速度变更等事件时,内核会调度执行这个函数。

static void hub_event(struct work_struct *work)
{struct usb_device *hdev; // USB设备struct usb_interface *intf; // USB接口struct usb_hub *hub; // USB集线器struct device *hub_dev; // 集线器设备u16 hubstatus; // 集线器状态u16 hubchange; // 集线器状态改变int i, ret;hub = container_of(work, struct usb_hub, events); // 获取USB集线器hdev = hub->hdev; // 获取USB设备hub_dev = hub->intfdev; // 获取集线器设备intf = to_usb_interface(hub_dev); // 获取USB接口dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",hdev->state, hdev->maxchild,/* NOTE: expects max 15 ports... */(u16) hub->change_bits[0],(u16) hub->event_bits[0]); // 打印调试信息/* Lock the device, then check to see if we were* disconnected while waiting for the lock to succeed. */usb_lock_device(hdev); // 锁定USB设备if (unlikely(hub->disconnected)) // 如果集线器已经断开连接goto out_hdev_lock;/* If the hub has died, clean up after it */if (hdev->state == USB_STATE_NOTATTACHED) { // 如果USB设备未连接hub->error = -ENODEV; // 设置错误码hub_quiesce(hub, HUB_DISCONNECT); // 关闭集线器goto out_hdev_lock;}/* Autoresume */ret = usb_autopm_get_interface(intf); // 自动恢复if (ret) { // 如果恢复失败dev_dbg(hub_dev, "Can't autoresume: %d\n", ret); // 打印调试信息goto out_hdev_lock;}/* If this is an inactive hub, do nothing */if (hub->quiescing) // 如果集线器正在关闭goto out_autopm;if (hub->error) { // 如果集线器出现错误dev_dbg(hub_dev, "resetting for error %d\n", hub->error); // 打印调试信息ret = usb_reset_device(hdev); // 重置USB设备if (ret) { // 如果重置失败dev_dbg(hub_dev, "error resetting hub: %d\n", ret); // 打印调试信息goto out_autopm;}hub->nerrors = 0;hub->error = 0;}/* deal with port status changes */ // 处理端口状态变化for (i = 1; i <= hdev->maxchild; i++) { // 遍历所有端口struct usb_port *port_dev = hub->ports[i - 1]; // 获取端口设备if (test_bit(i, hub->event_bits) // 如果端口事件位被设置|| test_bit(i, hub->change_bits) // 或者端口状态改变位被设置|| test_bit(i, hub->wakeup_bits)) { // 或者端口唤醒位被设置/** The get_noresume and barrier ensure that if* the port was in the process of resuming, we* flush that work and keep the port active for* the duration of the port_event().  However,* if the port is runtime pm suspended* (powered-off), we leave it in that state, run* an abbreviated port_event(), and move on.*/ // 这里的注释不需要翻译pm_runtime_get_noresume(&port_dev->dev); // 获取端口设备的运行时电源管理pm_runtime_barrier(&port_dev->dev); // 等待端口设备的运行时电源管理完成usb_lock_port(port_dev); // 锁定端口设备port_event(hub, i); // 处理端口事件usb_unlock_port(port_dev); // 解锁端口设备pm_runtime_put_sync(&port_dev->dev); // 释放端口设备的运行时电源管理}}/* 处理集线器状态变化 */if (test_and_clear_bit(0, hub->event_bits) == 0);   /* 什么也不做 */else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)dev_err(hub_dev, "get_hub_status failed\n"); // 打印调试信息else {if (hubchange & HUB_CHANGE_LOCAL_POWER) { // 如果本地电源改变dev_dbg(hub_dev, "power change\n"); // 打印调试信息clear_hub_feature(hdev, C_HUB_LOCAL_POWER); // 清除本地电源特性if (hubstatus & HUB_STATUS_LOCAL_POWER)/* FIXME: Is this always true? */hub->limited_power = 1; // 设置有限电源elsehub->limited_power = 0; // 取消有限电源}if (hubchange & HUB_CHANGE_OVERCURRENT) { // 如果过流改变u16 status = 0;u16 unused;dev_dbg(hub_dev, "over-current change\n"); // 打印调试信息clear_hub_feature(hdev, C_HUB_OVER_CURRENT); // 清除过流特性msleep(500);    /* Cool down */ // 等待500mshub_power_on(hub, true); // 打开集线器电源hub_hub_status(hub, &status, &unused); // 获取集线器状态if (status & HUB_STATUS_OVERCURRENT)dev_err(hub_dev, "over-current condition\n"); // 打印调试信息}}out_autopm:/* 平衡上面的usb_autopm_get_interface() */usb_autopm_put_interface_no_suspend(intf);
out_hdev_lock:usb_unlock_device(hdev); // 解锁USB设备/* 平衡kick_hub_wq()中的内容并允许自动挂起 */usb_autopm_put_interface(intf);kref_put(&hub->kref, hub_release);
}
  • 获取USB设备、USB接口、USB集线器和集线器设备的指针。

  • 打印调试信息,包括USB设备的状态、端口数量、状态变化位和事件位。

  • 锁定USB设备,检查设备是否已经断开连接。

  • 如果USB设备未连接,设置错误码并关闭USB集线器。

  • 执行自动恢复操作,自动恢复USB接口的运行状态。

  • 如果集线器正在关闭,直接退出。

  • 如果集线器出现错误,重置USB设备。

  • 遍历集线器的所有端口,处理端口状态变化的事件。

  • 处理集线器状态变化的事件,包括本地电源改变和过流改变。

  • 释放锁定的USB设备和端口,并进行自动挂起。

  • 释放USB集线器的引用计数,并执行相应的清理操作。

总之,这个函数负责处理USB hub设备的各种事件,包括端口状态变化和集线器状态变化。它通过锁定设备、执行必要的操作以及释放资源来确保USB hub的正常运行。

段代码处理USB hub的端口状态变化事件。它通过遍历所有的端口,检查端口的事件位、状态改变位和唤醒位是否被设置,如果设置了任意一个位,则执行相应的处理操作。

  /* deal with port status changes */ // 处理端口状态变化for (i = 1; i <= hdev->maxchild; i++) { // 遍历所有端口struct usb_port *port_dev = hub->ports[i - 1]; // 获取端口设备if (test_bit(i, hub->event_bits) // 如果端口事件位被设置|| test_bit(i, hub->change_bits) // 或者端口状态改变位被设置|| test_bit(i, hub->wakeup_bits)) { // 或者端口唤醒位被设置/** The get_noresume and barrier ensure that if* the port was in the process of resuming, we* flush that work and keep the port active for* the duration of the port_event().  However,* if the port is runtime pm suspended* (powered-off), we leave it in that state, run* an abbreviated port_event(), and move on.*/ // 这里的注释不需要翻译pm_runtime_get_noresume(&port_dev->dev); // 获取端口设备的运行时电源管理pm_runtime_barrier(&port_dev->dev); // 等待端口设备的运行时电源管理完成usb_lock_port(port_dev); // 锁定端口设备port_event(hub, i); // 处理端口事件usb_unlock_port(port_dev); // 解锁端口设备pm_runtime_put_sync(&port_dev->dev); // 释放端口设备的运行时电源管理}
}

具体的处理步骤如下:

  1. 使用变量i从1遍历到hdev->maxchild,表示遍历所有的端口。
  2. 获取当前端口的设备指针,存储在变量port_dev中,hub->ports[i - 1]表示获取USB hub中的第i个端口设备。
  3. 如果当前端口的事件位、状态改变位或唤醒位被设置,即调用test_bit()函数进行判断。
  4. 在满足上述条件的情况下,执行以下操作:
  • 调用pm_runtime_get_noresume()函数获取端口设备的运行时电源管理,确保在处理端口事件期间保持端口处于活动状态。
  • 调用pm_runtime_barrier()函数等待端口设备的运行时电源管理操作完成。
  • 调用usb_lock_port()函数锁定端口设备,以确保在处理端口事件期间其他操作不会干扰。
  • 调用port_event()函数处理端口事件,将USB hub和端口号作为参数传递给该函数。
  • 调用usb_unlock_port()函数解锁端口设备。
  • 调用pm_runtime_put_sync()函数释放端口设备的运行时电源管理。

这段代码的作用是针对每个端口处理其状态变化的事件。它获取并锁定端口设备,执行相应的事件处理函数,并在处理完成后释放端口设备,同时处理端口的运行时电源管理,确保在处理事件期间端口保持活动状态。

port_event

hub_probe->hub_event->port_event
port_event()函数用于处理USB hub的端口事件,它会在特定情况下被调用。
函数签名中的__must_hold(&port_dev->status_lock)表示该函数在调用之前必须获取端口设备的status_lock锁,并在函数执行期间持有该锁。这是为了确保在处理端口事件期间不会有其他线程同时修改端口的状态,保证数据的一致性和正确性。
具体来说,port_event()函数的作用如下:

  1. 接收USB hub和端口号作为参数,即hub和port1。
  2. 获取与port1对应的端口设备的指针。
  3. 根据端口设备的状态进行相应的处理,例如检测连接状态、重置端口、配置设备等。
  4. 更新端口设备的状态,包括连接状态、速度、带宽等信息。
  5. 根据端口的状态变化执行相应的操作,例如通知驱动程序、发送事件通知等。

port_event()函数会在以下情况下被调用:

  • 当USB hub检测到某个端口的事件发生时,例如设备连接、断开、速度变化等。

  • 当USB hub的状态发生变化时,需要通知端口设备进行相应的处理。

  • 当需要对特定端口进行配置或重置操作时。

总而言之,port_event()函数是用于处理USB hub端口事件的核心函数,它在特定的事件发生时被调用,并负责处理和更新与端口相关的操作和状态信息。

// 处理端口事件
static void port_event(struct usb_hub *hub, int port1)__must_hold(&port_dev->status_lock)
{// 是否需要连接变化int connect_change;// 获取端口设备struct usb_port *port_dev = hub->ports[port1 - 1];// 获取端口下的 USB 设备struct usb_device *udev = port_dev->child;// 获取 USB hub 设备struct usb_device *hdev = hub->hdev;// 端口状态和变化u16 portstatus, portchange;// 测试端口是否有变化connect_change = test_bit(port1, hub->change_bits);// 清除事件位和唤醒位clear_bit(port1, hub->event_bits);clear_bit(port1, hub->wakeup_bits);// 获取端口状态和变化if (hub_port_status(hub, port1, &portstatus, &portchange) < 0)return;// 如果连接状态发生变化if (portchange & USB_PORT_STAT_C_CONNECTION) {// 清除连接状态变化标志usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);// 标记需要连接变化connect_change = 1;}// 如果启用状态发生变化if (portchange & USB_PORT_STAT_C_ENABLE) {// 如果不需要连接变化if (!connect_change)// 打印启用状态变化信息dev_dbg(&port_dev->dev, "enable change, status %08x\n",portstatus);// 清除启用状态变化标志usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);/** EM interference sometimes causes badly shielded USB devices* to be shutdown by the hub, this hack enables them again.* Works at least with mouse driver.*/// 如果端口未启用且存在 USB 设备if (!(portstatus & USB_PORT_STAT_ENABLE)&& !connect_change && udev) {// 打印信息dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n");// 标记需要连接变化connect_change = 1;}}// 如果端口过流if (portchange & USB_PORT_STAT_C_OVERCURRENT) {u16 status = 0, unused;dev_dbg(&port_dev->dev, "over-current change\n"); // 打印调试信息usb_clear_port_feature(hdev, port1,USB_PORT_FEAT_C_OVER_CURRENT); // 清除端口过流标志msleep(100);    /* Cool down */ // 等待100mshub_power_on(hub, true); // 打开集线器电源hub_port_status(hub, port1, &status, &unused); // 获取端口状态if (status & USB_PORT_STAT_OVERCURRENT) // 如果端口过流dev_err(&port_dev->dev, "over-current condition\n"); // 打印错误信息}// 如果端口复位if (portchange & USB_PORT_STAT_C_RESET) {dev_dbg(&port_dev->dev, "reset change\n"); // 打印调试信息usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET); // 清除端口复位标志}// 如果端口处于SS.Inactive状态if ((portchange & USB_PORT_STAT_C_BH_RESET)&& hub_is_superspeed(hdev)) {dev_dbg(&port_dev->dev, "warm reset change\n"); // 打印调试信息usb_clear_port_feature(hdev, port1,USB_PORT_FEAT_C_BH_PORT_RESET); // 清除端口复位标志}// 如果端口连接状态发生变化if (portchange & USB_PORT_STAT_C_LINK_STATE) {dev_dbg(&port_dev->dev, "link state change\n"); // 打印调试信息usb_clear_port_feature(hdev, port1,USB_PORT_FEAT_C_PORT_LINK_STATE); // 清除端口连接状态标志}// 如果端口配置错误if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {dev_warn(&port_dev->dev, "config error\n"); // 打印警告信息usb_clear_port_feature(hdev, port1,USB_PORT_FEAT_C_PORT_CONFIG_ERROR); // 清除端口配置错误标志}// 如果端口未启用if (!pm_runtime_active(&port_dev->dev))return;// 处理远程唤醒if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))connect_change = 1;/** 如果端口处于SS.Inactive状态,进行热复位*/if (hub_port_warm_reset_required(hub, port1, portstatus)) {dev_dbg(&port_dev->dev, "do warm reset\n"); // 打印调试信息if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)|| udev->state == USB_STATE_NOTATTACHED) {if (hub_port_reset(hub, port1, NULL,HUB_BH_RESET_TIME, true) < 0)hub_port_disable(hub, port1, 1);} else {usb_unlock_port(port_dev);usb_lock_device(udev);usb_reset_device(udev);usb_unlock_device(udev);usb_lock_port(port_dev);connect_change = 0;}}// 如果连接状态发生变化if (connect_change)hub_port_connect_change(hub, port1, portstatus, portchange); // 处理连接状态变化
}

该函数用于处理USB hub的端口事件,并且需要持有端口设备的status_lock锁。
函数内容的概括如下:
获取与给定端口号port1对应的端口设备port_dev。
获取端口设备下的USB设备udev以及USB hub设备hdev。
检测端口是否发生连接状态变化,并清除相应的事件位和唤醒位。

获取端口的状态和状态变化。

根据状态变化进行不同的处理:

如果连接状态发生变化,清除连接状态变化标志,并标记需要连接变化。

如果启用状态发生变化,清除启用状态变化标志,并根据特定情况处理端口启用状态变化。

如果端口发生过流,清除过流标志,等待一段时间后重新打开集线器电源,并根据端口状态判断是否存在过流情况。

如果端口发生复位,清除复位标志。

如果端口处于SS.Inactive状态并且为超速设备,清除端口复位标志。

如果端口连接状态发生变化,清除连接状态变化标志。

如果端口发生配置错误,清除配置错误标志。

如果端口设备未处于活动状态,则返回。

处理远程唤醒情况,如果成功处理,则标记需要连接变化。

如果端口处于SS.Inactive状态,进行热复位操作:

如果USB设备不存在、端口未连接或USB设备处于未连接状态,则执行集线器端口复位操作或禁用端口。

否则,对USB设备进行复位操作。

如果连接状态发生变化,处理连接状态变化。

综上所述,该函数根据端口事件的不同情况,执行相应的处理操作,包括处理连接状态变化、启用状态变化、过流情况、复位等,以确保USB hub端口的正常工作。
如果连接状态发生变化,调用端口连接变化处理函数hub_port_connect_change

// 如果连接状态发生变化
if (connect_change)
hub_port_connect_change(hub, port1, portstatus, portchange); // 处理连接状态变化

hub_port_connect_change

hub_probe->hub_event->port_event->hub_port_connect_change
该函数用于处理USB hub端口的连接状态变化,并且需要持有端口设备的status_lock锁。
函数的作用是在端口连接状态变化时执行相应的处理操作,包括连接设备、断开设备、通知驱动程序等。
函数被调用的时机是在port_event()函数中,当检测到端口的连接状态发生变化时,会调用hub_port_connect_change()函数进行处理。

// USB hub 端口连接变化处理函数
static void hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange)__must_hold(&port_dev->status_lock)
{// 获取端口设备struct usb_port *port_dev = hub->ports[port1 - 1];// 获取端口下的 USB 设备struct usb_device *udev = port_dev->child;// 状态int status = -ENODEV;// 打印端口状态和变化信息dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,portchange, portspeed(hub, portstatus));// 如果 USB hub 有指示灯if (hub->has_indicators) {// 设置端口指示灯为自动模式set_port_led(hub, port1, HUB_LED_AUTO);// 设置端口指示灯状态为自动模式hub->indicator[port1-1] = INDICATOR_AUTO;}#ifdef  CONFIG_USB_OTG/* during HNP, don't repeat the debounce */// 如果是 HNP 模式if (hub->hdev->bus->is_b_host)// 清除连接状态和启用状态变化标志portchange &= ~(USB_PORT_STAT_C_CONNECTION |USB_PORT_STAT_C_ENABLE);
#endif// 如果端口已连接且存在 USB 设备且 USB 设备状态不是未连接状态if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&udev->state != USB_STATE_NOTATTACHED) {// 如果端口已启用if (portstatus & USB_PORT_STAT_ENABLE) {status = 0;     /* Nothing to do */
#ifdef CONFIG_PM// 如果 USB 设备状态是挂起状态且持久化使能} else if (udev->state == USB_STATE_SUSPENDED &&udev->persist_enabled) {/* 对于挂起的设备,将其视为远程唤醒事件。 */// 解锁端口usb_unlock_port(port_dev);// 远程唤醒 USB 设备status = usb_remote_wakeup(udev);// 锁定端口usb_lock_port(port_dev);
#endif} else {/* Don't resuscitate */;}}// 清除连接状态变化标志clear_bit(port1, hub->change_bits);// 如果成功重新验证连接if (status == 0)return;// 解锁端口usb_unlock_port(port_dev);// USB hub 端口连接处理hub_port_connect(hub, port1, portstatus, portchange);// 锁定端口usb_lock_port(port_dev);
}

函数内容的具体作用如下:
获取与给定端口号port1对应的端口设备port_dev和端口下的USB设备udev。
打印端口的状态和变化信息。

如果USB hub具有指示灯功能,将端口的指示灯设置为自动模式。

根据配置选项和HNP模式的情况,对端口状态变化标志进行调整。

根据端口的连接状态和USB设备的状态执行以下操作:

如果端口已连接且存在USB设备且USB设备的状态不是未连接状态:

如果端口已启用,表示连接状态正常,无需进行任何操作。
如果USB设备处于挂起状态且启用了持久化功能,将其视为远程唤醒事件,通过调用usb_remote_wakeup()函数远程唤醒USB设备。
清除连接状态变化标志。

如果成功重新验证连接(即状态为0),直接返回,无需进行后续处理。

解锁端口设备。

调用hub_port_connect()函数处理USB hub端口的连接,包括连接设备、初始化设备信息等。
锁定端口设备。

综上所述,hub_port_connect_change()函数在USB hub端口的连接状态变化时被调用,用于处理设备的连接和断开操作,并进行相应的指示灯设置、HNP模式处理和远程唤醒等操作。

hub_port_connect

hub_probe->hub_event->port_event->hub_port_connect_change->hub_port_connect
hub_port_connect()函数用于处理USB hub端口的连接操作。
函数的作用是在端口连接状态发生变化时,根据连接状态和变化信息执行相应的操作,包括连接设备、初始化设备信息、设置电源属性等。
该函数会被调用的时机包括以下情况:
当检测到端口的连接状态发生变化,并且需要进行连接操作时,会调用该函数进行处理。

// 当前端口上有设备连接时,执行此函数
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,u16 portchange)
{int status, i;unsigned unit_load;struct usb_device *hdev = hub->hdev; // 获取hub所在的设备struct usb_hcd *hcd = bus_to_hcd(hdev->bus); // 获取hub所在的HCDstruct usb_port *port_dev = hub->ports[port1 - 1]; // 获取当前端口的portstruct usb_device *udev = port_dev->child; // 获取当前端口上的设备static int unreliable_port = -1; // 记录连接不稳定的端口// 如果当前端口上已经有设备连接,则断开连接if (udev) {if (hcd->usb_phy && !hdev->parent)usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);usb_disconnect(&port_dev->child);}// 如果当前端口上没有设备连接,或者连接状态发生了变化,则清除removed_bitsif (!(portstatus & USB_PORT_STAT_CONNECTION) ||(portchange & USB_PORT_STAT_C_CONNECTION))clear_bit(port1, hub->removed_bits);// 如果连接状态或者使能状态发生了变化,则进行debounceif (portchange & (USB_PORT_STAT_C_CONNECTION |USB_PORT_STAT_C_ENABLE)) {status = hub_port_debounce_be_stable(hub, port1);if (status < 0) {if (status != -ENODEV &&port1 != unreliable_port &&printk_ratelimit())dev_err(&port_dev->dev, "connect-debounce failed\n");portstatus &= ~USB_PORT_STAT_CONNECTION;unreliable_port = port1;} else {portstatus = status;}}/* 如果debounce失败,或者没有设备连接,或者设备已经被移除,则直接返回 */if (!(portstatus & USB_PORT_STAT_CONNECTION) ||test_bit(port1, hub->removed_bits)) {/** 如果端口可供电,但是当前端口的电源关闭了,且端口没有被占用,则重新开启电源* (例如,根集线器被重置),但是只有当端口没有被其他设备占用时才能重新开启电源。*/if (hub_is_port_power_switchable(hub)&& !port_is_power_on(hub, portstatus)&& !port_dev->port_owner)set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);if (portstatus & USB_PORT_STAT_ENABLE)goto done;return;}if (hub_is_superspeed(hub->hdev))unit_load = 150;elseunit_load = 100;status = 0;for (i = 0; i < SET_CONFIG_TRIES; i++) {/* 为每次尝试重新分配内存,因为对于前一个内存的引用可能会以各种方式逃逸 */udev = usb_alloc_dev(hdev, hdev->bus, port1);if (!udev) {dev_err(&port_dev->dev,"couldn't allocate usb_device\n");goto done;}usb_set_device_state(udev, USB_STATE_POWERED);udev->bus_mA = hub->mA_per_port;udev->level = hdev->level + 1;udev->wusb = hub_is_wusb(hub);/* 只有USB 3.0设备连接到超级速度集线器。 */if (hub_is_superspeed(hub->hdev))udev->speed = USB_SPEED_SUPER;elseudev->speed = USB_SPEED_UNKNOWN;choose_devnum(udev);if (udev->devnum <= 0) {status = -ENOTCONN; /* 不要重试 */goto loop;}/* 重置(非USB 3.0设备)并获取描述符 */usb_lock_port(port_dev);status = hub_port_init(hub, udev, port1, i);usb_unlock_port(port_dev);if (status < 0)goto loop;/* 检测设备的quirks */usb_detect_quirks(udev);if (udev->quirks & USB_QUIRK_DELAY_INIT)msleep(1000);/* 连续的总线供电集线器不可靠;它们可能会违反电压降预算。如果新的子设备有“供电”LED,则用户应该注意到我们没有启用它(无需阅读syslog),即使父设备没有每个端口的LED也可以。 */if (udev->descriptor.bDeviceClass == USB_CLASS_HUB&& udev->bus_mA <= unit_load) {u16 devstat;status = usb_get_status(udev, USB_RECIP_DEVICE, 0,&devstat);if (status) {dev_dbg(&udev->dev, "get status %d ?\n", status);goto loop_disable;}if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {dev_err(&udev->dev,"can't connect bus-powered hub ""to this port\n");if (hub->has_indicators) {hub->indicator[port1-1] =INDICATOR_AMBER_BLINK;queue_delayed_work(system_power_efficient_wq,&hub->leds, 0);}status = -ENOTCONN; /* 不要重试 */goto loop_disable;}}/* check for devices running slower than they could */if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 // 如果设备支持 USB 2.0 或更高版本&& udev->speed == USB_SPEED_FULL // 如果设备速度为全速&& highspeed_hubs != 0) // 如果存在高速 USB hubcheck_highspeed (hub, udev, port1); // 检查是否需要升级到高速/* Store the parent's children[] pointer.  At this point* udev becomes globally accessible, although presumably* no one will look at it until hdev is unlocked.*/ // 存储父设备的 children[] 指针。此时,udev 变为全局可访问,尽管可能没有人会在 hdev 解锁之前查看它。status = 0;mutex_lock(&usb_port_peer_mutex);/* We mustn't add new devices if the parent hub has* been disconnected; we would race with the* recursively_mark_NOTATTACHED() routine.*/ // 如果父 USB hub 已断开连接,则不能添加新设备;我们将与 recursively_mark_NOTATTACHED() 例程竞争。spin_lock_irq(&device_state_lock);if (hdev->state == USB_STATE_NOTATTACHED) // 如果父 USB hub 已断开连接status = -ENOTCONN; // 设置状态为未连接elseport_dev->child = udev; // 将 udev 存储到 port_dev 的 child 中spin_unlock_irq(&device_state_lock);mutex_unlock(&usb_port_peer_mutex);/* Run it through the hoops (find a driver, etc) */ // 运行它通过 hoops(查找驱动程序等)if (!status) {status = usb_new_device(udev); // 新建 USB 设备if (status) { // 如果新建设备失败mutex_lock(&usb_port_peer_mutex);spin_lock_irq(&device_state_lock);port_dev->child = NULL; // 将 port_dev 的 child 设置为 NULLspin_unlock_irq(&device_state_lock);mutex_unlock(&usb_port_peer_mutex);} else { // 如果新建设备成功if (hcd->usb_phy && !hdev->parent) // 如果存在 USB 物理层并且 hdev 不是根 USB hubusb_phy_notify_connect(hcd->usb_phy, udev->speed); // 通知 USB 物理层连接成功}}// 获取 USB hub 剩余电源预算status = hub_power_remaining(hub);if (status)dev_dbg(hub->intfdev, "%dmA power budget left\n", status);return;loop_disable:// 禁用 USB hub 端口hub_port_disable(hub, port1, 1);
loop:// 重新初始化 USB 设备的端点 0usb_ep0_reinit(udev);// 释放 USB 设备编号release_devnum(udev);// 释放 USB 设备hub_free_dev(udev);// 释放 USB 设备引用计数usb_put_dev(udev);// 如果状态为未连接或不支持,则跳出循环if ((status == -ENOTCONN) || (status == -ENOTSUPP))break;}// 如果存在父 USB hub 或者驱动程序没有移交端口或者驱动程序移交端口失败if (hub->hdev->parent ||!hcd->driver->port_handed_over ||!(hcd->driver->port_handed_over)(hcd, port1)) {// 如果状态不是未连接或未定义if (status != -ENOTCONN && status != -ENODEV)// 打印错误信息dev_err(&port_dev->dev,"unable to enumerate USB device\n");}done:// 禁用 USB hub 端口hub_port_disable(hub, port1, 1);// 如果驱动程序释放端口并且 hdev 不是根 USB hubif (hcd->driver->relinquish_port && !hub->hdev->parent)// 驱动程序释放端口hcd->driver->relinquish_port(hcd, port1);}

hub_port_connect()函数的作用是处理USB hub端口的连接操作。
函数首先检查当前端口上是否已经连接了USB设备,如果有,会断开连接。接下来,检查连接状态和变化信息,进行去抖动操作。如果连接状态或使能状态发生了变化,则进行去抖动以确保稳定连接。
如果端口没有连接或设备已被移除,则会执行相应的操作并返回。
如果端口连接正常,则根据USB hub的类型和设备的属性进行初始化设置。然后为USB设备分配设备号、初始化端点等操作。
如果设备是USB 2.0设备且连接到高速USB hub上,则检查设备是否可以以更高的速度运行。
然后,将新连接的设备添加到父USB hub的子设备列表中,并通知USB物理层设备连接成功。
最后,禁用端口并释放相关资源,如果驱动程序支持端口释放,则进行相应的处理。
总体而言,hub_port_connect()函数用于处理USB hub端口的连接操作,包括断开连接、去抖动、初始化设备和端口等操作。它是USB hub驱动程序中的重要函数之一。

usb_new_device

hub_probe->hub_event->port_event->hub_port_connect_change->hub_port_connect->usb_new_device
usb_new_device()函数的作用是为USB设备进行初始化并与合适的驱动程序进行匹配。
该函数在以下情况下被调用:
当一个USB设备被连接到USB总线上时,USB核心会检测到设备的存在并创建一个
usb_device结构体来表示该设备。
当设备被检测到后,USB核心会调用
usb_new_device()函数为该设备进行初始化,并为设备分配资源。
初始化过程中,USB核心会遍历已加载的驱动程序,尝试将设备与合适的驱动程序进行匹配。
如果找到了适合的驱动程序,USB核心会调用该驱动程序的
probe()函数来完成设备的特定初始化和配置。

int usb_new_device(struct usb_device *udev)
{int err;if (udev->parent) {/* 初始化非根集线器设备唤醒为禁用状态;* 设备(非)配置控制唤醒能力* sysfs power/wakeup 控制唤醒启用/禁用*/device_init_wakeup(&udev->dev, 0);}/* 告诉运行时-PM框架设备处于活动状态 */pm_runtime_set_active(&udev->dev);pm_runtime_get_noresume(&udev->dev);pm_runtime_use_autosuspend(&udev->dev);pm_runtime_enable(&udev->dev);/* 默认情况下,禁止所有设备的自动挂起。它将被允许在绑定期间用于集线器。 */usb_disable_autosuspend(udev);err = usb_enumerate_device(udev);   /* 读取描述符 */if (err < 0)goto fail;dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",udev->devnum, udev->bus->busnum,(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));/* 导出usbdev设备节点供libusb使用 */udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));/* 告诉世界! */announce_device(udev);if (udev->serial)add_device_randomness(udev->serial, strlen(udev->serial)); // 添加设备随机性if (udev->product)add_device_randomness(udev->product, strlen(udev->product)); // 添加设备随机性if (udev->manufacturer)add_device_randomness(udev->manufacturer,strlen(udev->manufacturer)); // 添加设备随机性device_enable_async_suspend(&udev->dev); // 启用异步挂起/* 检查集线器或固件是否将此端口标记为不可移除 */if (udev->parent)set_usb_port_removable(udev); // 设置USB端口是否可移除/* 注册设备。设备驱动程序负责配置设备并调用添加设备通知器链(由usbfs和可能的其他程序使用)。 */err = device_add(&udev->dev); // 添加设备if (err) {dev_err(&udev->dev, "can't device_add, error %d\n", err); // 添加设备失败goto fail;}/* 为子设备和USB端口设备之间创建链接文件 */if (udev->parent) {struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); // 获取父集线器int port1 = udev->portnum; // 获取端口号struct usb_port *port_dev = hub->ports[port1 - 1]; // 获取端口设备err = sysfs_create_link(&udev->dev.kobj,&port_dev->dev.kobj, "port"); // 创建链接文件if (err)goto fail;err = sysfs_create_link(&port_dev->dev.kobj,&udev->dev.kobj, "device"); // 创建链接文件if (err) {sysfs_remove_link(&udev->dev.kobj, "port"); // 移除链接文件goto fail;}if (!test_and_set_bit(port1, hub->child_usage_bits)) // 如果端口未被使用pm_runtime_get_sync(&port_dev->dev); // 获取端口设备}(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); // 创建端点设备usb_mark_last_busy(udev); // 标记设备最后一次活动时间pm_runtime_put_sync_autosuspend(&udev->dev); // 唤醒设备并挂起return err; // 返回错误码fail:usb_set_device_state(udev, USB_STATE_NOTATTACHED); // 设置设备状态为未连接pm_runtime_disable(&udev->dev); // 禁用设备运行时pm_runtime_set_suspended(&udev->dev); // 设置设备运行时为挂起状态return err; // 返回错误码
}

该函数的主要目的是初始化USB设备并进行一系列配置和设置。以下是该函数的概括:
如果设备不是根集线器设备,将设备唤醒功能禁用。
设置设备为活动状态,并启用运行时电源管理。
禁用设备的自动挂起。
调用
usb_enumerate_device()函数读取设备描述符。
导出USB设备节点供其他程序使用。
发送设备连接通知。
如果设备有序列号、产品名称或制造商信息,添加设备随机性。
启用异步挂起。
如果设备有父集线器,设置USB端口是否可移除。
注册设备并添加到设备链表中。
如果设备有父集线器,创建链接文件以连接子设备和USB端口设备。
创建端点设备。
标记设备的最后一次活动时间。
唤醒设备并挂起,启用自动挂起。
如果发生错误,设置设备状态为未连接,并禁用设备运行时。
函数返回错误码来指示操作的成功与否。
总的来说,这个函数负责对USB设备进行初始化、配置和设置,并在必要时与父集线器和其他设备建立链接。

announce_device

hub_probe->hub_event->port_event->hub_port_connect_change->hub_port_connect->usb_new_device->announce_device

发现新的 USB 设备时,打印设备信息

/*** announce_device - 发现新的 USB 设备时,打印设备信息* @udev: 新发现的 USB 设备*/
static void announce_device(struct usb_device *udev)
{dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",le16_to_cpu(udev->descriptor.idVendor),le16_to_cpu(udev->descriptor.idProduct));dev_info(&udev->dev,"New USB 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); // 打印设备的序列号
}

接如usb摄像头时对应打印信息如下

在这里插入图片描述


http://www.ppmy.cn/news/73381.html

相关文章

二分查找怎么写? 你真的弄懂二分查找了吗

大家好&#xff0c;我是三叔&#xff0c;很高兴这期又和大家见面了&#xff0c;一个奋斗在互联网的打工人。 二分查找是一种高效的查找算法&#xff0c;也是Java中最基础的算法之一&#xff0c;常用于已排序数组中的元素查找。本篇博客将介绍二分查找的原理、应用场景以及实现…

多目标优化算法求解无人机三维路径规划

一、无人机模型 无人机三维路径规划是无人机在执行任务过程中的非常关键的环节&#xff0c;无人机三维路径规划的主要目的是在满足任务需求和自主飞行约束的基础上&#xff0c;计算出发点和目标点之间的最佳航路。 1.1路径成本 无人机三维路径规划的首要目标是寻找起飞点和目…

tomcat加载顺序

一、 1、启动一个WEB项目的时候&#xff0c;WEB容器会去读取它的配置文件web.xml&#xff0c;读取<listener>和<context-param>两个结点。 2、紧急着&#xff0c;容创建一个ServletContext&#xff08;servlet上下文&#xff09;&#xff0c;这个web项目的所有部…

C++应届生程序员进入公司需要注意的五个细节,希望对大家有帮助

今天想跟大家分享一下应届C程序员实习生在进入公司后需要注意哪些问题。 C程序员是一种非常重要的职业&#xff0c;主要负责使用C语言编写各种软件程序。C是一种面向对象的编程语言&#xff0c;常用于开发操作系统、游戏引擎、嵌入式系统、图像处理等领域。因此&#xff0c;C程…

秘塔写作猫

秘塔写作猫是集AI智能写作、多人协作、改写润色、文本校对等功能为一体的AI原生创作平台&#xff0c;可以帮助不同群体大幅提升写作效率和生产力。 接下来小编就带大家了解一下该软件具体的一些功能&#xff0c;不论你是学生、上班族还是自媒体从业者等&#xff0c;该工具绝对可…

【Linux】ko文件查询内部信息方法

objdump命令 在 Linux 中&#xff0c;可以使用 objdump 命令来反汇编 ko 文件并查看其中的宏定义值。 以下是如何使用 objdump 命令查看 ko 文件中的宏定义值的示例&#xff1a; objdump -d <ko文件> | grep <宏名称>其中&#xff0c;-d 参数表示反汇编目标文件…

【物联网技术对生活的影响与展望】

随着科技日新月异的发展&#xff0c;物联网&#xff08;IoT&#xff09;技术正在快速地影响着我们的生活。它是将各种设备和物品连接在一起&#xff0c;通过互联网使它们可以相互交流和传递数据的技术。它的应用范围广泛&#xff0c;可以涵盖从智能家居到工业网络的各个领域。 …

2-《Java进阶》

[TOC](2-《Java进阶》 一. java多线程&#xff08;非常重要&#xff09;1.1. 线程java多线程实现方式主要有&#xff1a;1.继承Thread 2.实现Runnable3.实现CallableRunnable 与 Callable的区别&#xff1a;1.2. 线程的状态有哪些&#xff1f;1.3. 线程的状态转换及控制1.4. Ja…

ES6中Promise对象

1.Promise 说明&#xff1a;Promise是异步编程的一种解决方案。简而言之&#xff0c;也就是存者未来发生的事件的容器。 Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。 特点&#xff1a;对象的状态不受外界影响。Promise对象代表一个异步操作&#xff0c;存…

Linux MISC 驱动实验

misc 的意思是混合、杂项的&#xff0c;因此 MISC 驱动也叫做杂项驱动&#xff0c;也就是当我们板子上的某 些外设无法进行分类的时候就可以使用 MISC 驱动。MISC 驱动其实就是最简单的字符设备驱 动&#xff0c;通常嵌套在 platform 总线驱动中&#xff0c;实现复杂的驱动。 M…

Less和sass安装及使用

CSS预处理器 由来 CSS本身不是一种编程语言。你可以用它开发网页样式&#xff0c;但是没法用它编程。换句话说&#xff0c;CSS基本上是设计师的工具&#xff0c;不是程序员的工具。它并不像其它程序语言&#xff0c;比如说JavaScript等&#xff0c;有自己的变量、常量、条件语…

C#中使用git将项目代码上传到远程仓库的操作

一、远程仓库创建操作&#xff08;远程仓库使用的是gitHub&#xff09; 1、登录GitHub官网&#xff0c;注册登录账号后&#xff0c;点击创建仓库 2、仓库名称命名&#xff0c;如下所示&#xff1a; 3、创建成功如下所示&#xff1a;获得https协议&#xff08;https://github.c…

JuiceFS 在多云存储架构中的应用 | 深势科技分享

2020 年末&#xff0c;谷歌旗下 DeepMind 研发的 AI 程序 AlphaFold2 在国际蛋白质结构预测竞赛上取得惊人的准确度&#xff0c;使得 “AI 预测蛋白质结构” 这一领域受到了空前的关注。今天我们邀请到同领域企业&#xff0c;深势科技为大家分享其搭建基础平台时的实践与思考。…

在阿里做了6年软件测试,4月无情被辞,想给划水的兄弟提个醒

先简单交代一下背景吧&#xff0c;某不知名 985 的本硕&#xff0c;17 年毕业加入阿里&#xff0c;以“人员优化”的名义无情被裁员&#xff0c;之后跳槽到了有赞&#xff0c;一直从事软件测试的工作。之前没有实习经历&#xff0c;算是6年的工作经验吧。 这6年之间完成了一次…

python 图片保存成视频

&#x1f468;‍&#x1f4bb;个人简介&#xff1a; 深度学习图像领域工作者 &#x1f389;工作总结链接&#xff1a;https://blog.csdn.net/qq_28949847/article/details/128552785 链接中主要是个人工作的总结&#xff0c;每个链接都是一些常用demo&#xff0c…

洛谷 池塘计数 floor-fill BFS 模板题

&#x1f351; OJ专栏 &#x1f351; P1596 Lake Counting 题面翻译 由于近期的降雨&#xff0c;雨水汇集在农民约翰的田地不同的地方。我们用一个 N M ( 1 ≤ N ≤ 100 , 1 ≤ M ≤ 100 ) N\times M(1\leq N\leq 100, 1\leq M\leq 100) NM(1≤N≤100,1≤M≤100) 的网格图表…

Qt——Qt控件之显示窗口-QLabel标签控件的使用总结(例程:QLabel显示文本标签及图片)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》

【CSS 选择器应用在QSS】第二天

CSS 选择器应用在QSS 【1】元素选择器&#xff08;元素通用性&#xff09;【2】id 选择器&#xff08;唯一性&#xff09;【2.1】CSS【2.2】QSS 【3】类选择器【3.1】CSS【3.2】QSS 【4】类选择器&#xff08;只针对指定元素&#xff09;【4.1】CSS【4.2】QSS 【5】通用选择器【…

语音合成工具_bark

1 介绍 多语言的文字转语音模型。 地址: https://github.com/suno-ai/bark 2 模型原理 Bark通过三个Transformer模型&#xff0c;将文本转换为音频。 2.1 文本到语义Token 输入&#xff1a;由Hugging Face的BERT标记器分词的文本 输出&#xff1a;编码生成音频的语义Token…

【面试高频 time: 2023-5-18】做分布式文件存储,如何保证分布式存储的高性能与高可用?

大家可以想到基本就是副本备份、双活、多活这种架构 在系统中通过复制协议将数据同步到多个存储节点&#xff0c;并确 保多个副本之间的数据⼀致性&#xff0c;当某个存储节点出故障 时&#xff0c;系统能够⾃动将服务切换到其他的副本 在分布式存储中⾼性能与⾼可⽤是⽭盾的&…