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
相关产品推荐
相关产品推荐

