You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux 4.18中struct usb_device缺失children字段的USB驱动移植求助

Linux 2.6.x到4.18.x USB驱动移植:替代children字段获取设备路由路径

问题背景

我有一个基于Linux 2.6.x内核的旧USB内核模块驱动代码,现在需要移植到4.18.x内核。发现struct usb_device不再包含children[USB_MAXCHILDREN]字段,原有代码依赖遍历该字段进行路由搜索以获取设备路径,导致无法运行,求替代实现方式。

原代码片段:

//---------------------------------------------------------------------------------------------------------
ROUTE GetRoute ( struct usb_device * dev )
//---------------------------------------------------------------------------------------------------------
//  returns route encoded as:    Bus, RootHubPort,Hub1Port,Hub2Port,Hub3Port,Hub4Port,Hub5Port
// 
//    bit numbers in 32-bit word 31-24   23-20     19-16    15-12    11-8     7-4      3-0
//
//    where Bus is 8 bits (1 based), and Hub ports are 4 bits (1-based with 000 meaning leaf node)
//
//    thus a route of all zeros is invalid - and is used to indicate an error
{  
  int i, Port, PortIndex;
  unsigned long shift;
  #define MAX_DEPTH 6 // (including root hub)
  ROUTE u32Route = 0x00000000;
  
  struct usb_device *currentdev;
  struct usb_device *DevsReverseChain[ MAX_DEPTH + 1];  // we put our own dev in here too  - so needs + 1
  int nLevels = 0;  
  
  int PortArray[MAX_DEPTH] = {0}; 
  int PortArrayIndex = 0;

  // build up array of devs till we reach root 
  currentdev = dev;
  for (nLevels = 0; nLevels <= MAX_DEPTH; nLevels++)
  {  
    DevsReverseChain[ nLevels ] = currentdev;
    if (currentdev == currentdev->bus->root_hub)
    {
      //TRACE("GetRoute: got back to root hub, nLevels=%d", nLevels);
      break;
    } 
    currentdev = currentdev->parent; 
  }  
  
  if (nLevels > MAX_DEPTH)                                                   
  {
    ERROR("GetRoute: too many hub levels (MAX I can handle is %d)", MAX_DEPTH);
    return 0; // 0=invalid route
  }
  
  // we now know how many levels there are between root dev and target dev
  // so we can start filling in an array of the port number sequence to get
  // back to the device from the root hub
  //-----------------------------------------------------------------------
  PortArrayIndex = 0;
  for (i = nLevels; i > 0; i--)
  {  
    // Locate port on which our next device down resides
    Port = 0;  // init to invalid
    for(PortIndex=0; PortIndex<8; PortIndex++)
    {
      if ( DevsReverseChain[i]->children[PortIndex] == DevsReverseChain[i-1] )
      {  
        Port = PortIndex + 1;  // linux portnums are 0-based - OURS ARE 1-based!!!!!
        //printk("TRACE GetRoute: good child port=%d
", Port);
        break;
      }
    }
    if (Port != 0)
    { 
      PortArray[PortArrayIndex] = Port; 
      PortArrayIndex++;           
    }
    else
    {
      ERROR("GetRoute: logic error 1 - failed to re-find child from parentlevel %d", i);
      return 0; // 0=invalid route
    }
  }  
  
  // we now know everything we need, so we can encode the route information into u32Route
  // - from the MSB - bus/roothub end
  u32Route = 0x00000000;
  
  u32Route += dev->bus->busnum << 24;  // top byte is bus number (1-based !!)
  
  shift = 20;    // bottom 6 nibbles are the port numbers on the (up to) 6 hubs
  for (i = 0; i < nLevels; i++)
  {             
    u32Route += PortArray[i] << shift;
    shift -= 4;
  }  
  
  //TRACE("GetRoute: final u32Route=0x%lx", u32Route);
      
  return u32Route;
}

解决方案

在Linux 4.18.x内核中,USB子设备管理已从固定数组改为链表结构,同时struct usb_device新增了portnum字段直接记录设备在父hub上的端口号(1-based,刚好匹配你的需求),无需再遍历父设备的子设备列表查找端口。

修改后的代码如下:

//---------------------------------------------------------------------------------------------------------
ROUTE GetRoute(struct usb_device *dev)
//---------------------------------------------------------------------------------------------------------
//  returns route encoded as:    Bus, RootHubPort,Hub1Port,Hub2Port,Hub3Port,Hub4Port,Hub5Port
// 
//    bit numbers in 32-bit word 31-24   23-20     19-16    15-12    11-8     7-4      3-0
//
//    where Bus is 8 bits (1 based), and Hub ports are 4 bits (1-based with 000 meaning leaf node)
//
//    thus a route of all zeros is invalid - and is used to indicate an error
{
    int i;
    unsigned long shift;
    #define MAX_DEPTH 6 // (including root hub)
    ROUTE u32Route = 0x00000000;

    struct usb_device *currentdev;
    struct usb_device *DevsReverseChain[MAX_DEPTH + 1];
    int nLevels = 0;

    int PortArray[MAX_DEPTH] = {0};
    int PortArrayIndex = 0;

    // 构建从目标设备到root hub的反向设备链
    currentdev = dev;
    for (nLevels = 0; nLevels <= MAX_DEPTH; nLevels++) {
        DevsReverseChain[nLevels] = currentdev;
        if (currentdev == currentdev->bus->root_hub) {
            break;
        }
        currentdev = currentdev->parent;
    }

    if (nLevels > MAX_DEPTH) {
        ERROR("GetRoute: too many hub levels (MAX I can handle is %d)", MAX_DEPTH);
        return 0; // 0表示无效路由
    }

    // 直接读取每个子设备的portnum字段,无需遍历父设备子列表
    PortArrayIndex = 0;
    for (i = nLevels; i > 0; i--) {
        // 子设备的portnum本身就是1-based,直接使用
        int Port = DevsReverseChain[i-1]->portnum;
        if (Port != 0) {
            PortArray[PortArrayIndex] = Port;
            PortArrayIndex++;
        } else {
            ERROR("GetRoute: invalid port number for device at level %d", i-1);
            return 0;
        }
    }

    // 编码路由信息
    u32Route = 0x00000000;
    u32Route += dev->bus->busnum << 24; // 最高字节为总线号(1-based)

    shift = 20; // 低6个半字节对应最多6个hub的端口号
    for (i = 0; i < nLevels; i++) {
        u32Route += PortArray[i] << shift;
        shift -= 4;
    }

    //TRACE("GetRoute: final u32Route=0x%lx", u32Route);

    return u32Route;
}

关键改动说明

  • 移除了遍历父设备children数组的逻辑,直接通过DevsReverseChain[i-1]->portnum获取端口号,代码更高效简洁。
  • 内核中portnum字段本身就是1-based,不需要再做PortIndex + 1的转换。
  • 保留了原有的路由编码逻辑,确保输出结果和旧代码一致。

内容的提问来源于stack exchange,提问作者mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 05:33:17