原创 Linux那些事儿之我是Hub(15)一个都不能少

2010-7-13 07:08 2857 5 5 分类: MCU/ 嵌入式

烟波江声里,何处是江南.一晃神,一转眼,我们就这样垂垂老去.可是我们直到现在还根本就没有看明白hub驱动究竟是怎么工作的.但我相信,红莲即将绽放,双星终会汇聚,命运的轮转已经开始,我们只需耐心的等待.


2686行,苦苦追寻之后,终于发现从这里开始针对端口进行分析了,有几个端口就对几个端口进行分析,分析每一个端口的状态变化,一个都不能少,很显然,这就是我们期待看到的代码,马上我们就可以知道,当我们把一个usb设备插入usb端口之后究竟会发生什么,知道usb设备提供的那些接口函数究竟是如何被调用的,特别是那个probe函数.这一刻,红领巾迎着太阳,阳光洒在海面上,水中鱼儿望着我们,悄悄的听我们愉快的歌唱,小船儿轻轻飘荡在水中,迎面吹来了凉爽的风!


bNbrports是前面我们获得的hub descriptor的一个成员,表征这个hub有几个端口.很显然,月可无光,星可无语,usb设备却不可以没有描述符.这里就是遍历每一个端口.busy_bits是struct usb_hub的一个成员,unsigned long busy_bits[1],接下来的event_bits也是,change_bits也是,unsigned long event_bits[1],unsigned long change_bits[1],test_bit()我们太熟悉了,在usb-storage里面到处都是,只不过当时我们测试的是us->flags里面的某个flag是否设置了,而这里我们要测试的有三个东东,首先测试busy_bits,这个flag实际上只有在reset和resume的函数内部才会设置,所以这里我们先不用管,而这里的意思是,如果眼下这个端口正在执行reset或者resume操作,那么咱们就跳过去,不予理睬.


2689行,测试change_bits.结合2690,2691,2692行一起看.如果这个端口对应的change_bits没有设置,event_bits没有设置过,hub->activating也为0,那么这里就执行continue,不过我们想都不用想,因为我们就是从hub_activate进来的.我们来的时候activating就是设置成了1的,所以这里的continue我们是不用执行的.换言之,我们继续往下走.


2694行,hub_port_status(),portstatus和portchange是我们在hub_events()伊始定义的两个变量,u16 portstatus,u16 portchange,即两个都是16位.尽管说了N遍了,但是我还是得说第N+1遍,这个函数仍然是来自drivers/usb/core/hub.c:


   1413 static int hub_port_status(struct usb_hub *hub, int port1,


   1414                                u16 *status, u16 *change)


   1415 {


   1416         int ret;


   1417


   1418         mutex_lock(&hub->status_mutex);


   1419         ret = get_port_status(hub->hdev, port1, &hub->status->port);


   1420         if (ret < 4) {


   1421                 dev_err (hub->intfdev,


   1422                         "%s failed (err = %d)\n", __FUNCTION__, ret);


   1423                 if (ret >= 0)


   1424                         ret = -EIO;


   1425         } else {


   1426                 *status = le16_to_cpu(hub->status->port.wPortStatus);


   1427                 *change = le16_to_cpu(hub->status->port.wPortChange);


   1428                 ret = 0;


   1429         }


   1430         mutex_unlock(&hub->status_mutex);


   1431         return ret;


   1432 }


重要的是其中的那个get_port_status()函数.


    300 /*


    301  * USB 2.0 spec Section 11.24.2.7


    302  */


    303 static int get_port_status(struct usb_device *hdev, int port1,


    304                 struct usb_port_status *data)


    305 {


    306         int i, status = -ETIMEDOUT;


    307


    308         for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {


    309                 status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),


    310                         USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,


    311                         data, sizeof(*data), USB_STS_TIMEOUT);


    312         }


    313         return status;


    314 }


一路从泥泞走到美景,我们再也不会对usb_control_msg()函数陌生了,这个函数做什么勾当我们完全是一目了然.Get Port Status是Hub的一个标准请求,对我们来说就是一次控制传输就可以搞定.这个请求的格式如下图所示:



其中这个GET_STATUS的对应具体的数值可以在下面这张表中对比得到,



而关于各种请求,咱们在include/linux/usb/ch9.h中也定义了相应的宏,


     72 /*


     73  * Standard requests, for the bRequest field of a SETUP packet.


     74  *


     75  * These are qualified by the bRequestType field, so that for example


     76  * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved


     77  * by a GET_STATUS request.


     78  */


     79 #define USB_REQ_GET_STATUS              0x00


     80 #define USB_REQ_CLEAR_FEATURE           0x01


     81 #define USB_REQ_SET_FEATURE             0x03


     82 #define USB_REQ_SET_ADDRESS             0x05


     83 #define USB_REQ_GET_DESCRIPTOR          0x06


     84 #define USB_REQ_SET_DESCRIPTOR          0x07


     85 #define USB_REQ_GET_CONFIGURATION       0x08


     86 #define USB_REQ_SET_CONFIGURATION       0x09


     87 #define USB_REQ_GET_INTERFACE           0x0A


     88 #define USB_REQ_SET_INTERFACE           0x0B


     89 #define USB_REQ_SYNCH_FRAME             0x0C


     90


     91 #define USB_REQ_SET_ENCRYPTION          0x0D    /* Wireless USB */


     92 #define USB_REQ_GET_ENCRYPTION          0x0E


     93 #define USB_REQ_RPIPE_ABORT             0x0E


     94 #define USB_REQ_SET_HANDSHAKE           0x0F


     95 #define USB_REQ_RPIPE_RESET             0x0F


     96 #define USB_REQ_GET_HANDSHAKE           0x10


     97 #define USB_REQ_SET_CONNECTION          0x11


     98 #define USB_REQ_SET_SECURITY_DATA       0x12


     99 #define USB_REQ_GET_SECURITY_DATA       0x13


    100 #define USB_REQ_SET_WUSB_DATA           0x14


    101 #define USB_REQ_LOOPBACK_DATA_WRITE     0x15


    102 #define USB_REQ_LOOPBACK_DATA_READ      0x16


    103 #define USB_REQ_SET_INTERFACE_DS        0x17


比如这里咱们传递给usb_control_msg的request就是USB_REQ_GET_STATUS,它的值为0,和usb spec中定义的GET_STATUS的值是对应的.这个请求返回两个咚咚,一个称为Port Status,一个称为Port Change Status.usb_control_msg()的调用注定了返回值将保存在struct usb_port_status *data里面,这个结构体定义与drivers/usb/core/hub.h中:


     58 /*


     59  * Hub Status and Hub Change results


     60  * See USB 2.0 spec Table 11-19 and Table 11-20


     61  */


     62 struct usb_port_status {


     63         __le16 wPortStatus;


     64         __le16 wPortChange;


     65 } __attribute__ ((packed));


很显然这个格式是和实际的spec规范对应的,我们给get_port_status()传递的实参是&hub->status->port,port也是一个struct usb_port_status结构体变量,所以在hub_port_status()里面,1426和1427两行我们就得到了Status Bits和Status Change Bits.get_port_status()返回值就是GET PORT STATUS请求的返回数据的长度,它至少应该能够保存wPortStatus和wPortChange,所以至少不能小于4,所以1420行有这么一个错误判断.这样,hub_port_status()就返回了,而status和change这两个指针也算是满载而归了,正常的话返回值就是0.


继续往下走,2699行,children[i-1],这么一个冬冬我们从没有见过,但是我想白痴都知道,正是像parent和children这样的指针才能把USB树给建立起来,而我们才刚上路,肯定还没有设置children,所以对我们来说,至少目前children数组肯定为空,而我们又知道hub->activating这时候肯定为1,所以就看第三个条件了,portstatus&USB_PORT_STAT_CONNECTION,这是啥意思?稍有悟性的人就能看出来,这表明这个端口连了设备,没错,USB_PORT_STAT_CONNECTION这个宏定义于drivers/usb/core/hub.h中:


     67 /*


     68  * wPortStatus bit field


     69  * See USB 2.0 spec Table 11-21


     70  */


     71 #define USB_PORT_STAT_CONNECTION        0x0001


     72 #define USB_PORT_STAT_ENABLE            0x0002


     73 #define USB_PORT_STAT_SUSPEND           0x0004


     74 #define USB_PORT_STAT_OVERCURRENT       0x0008


     75 #define USB_PORT_STAT_RESET             0x0010


     76 /* bits 5 to 7 are reserved */


     77 #define USB_PORT_STAT_POWER             0x0100


     78 #define USB_PORT_STAT_LOW_SPEED         0x0200


     79 #define USB_PORT_STAT_HIGH_SPEED        0x0400


     80 #define USB_PORT_STAT_TEST              0x0800


     81 #define USB_PORT_STAT_INDICATOR         0x1000


     82 /* bits 13 to 15 are reserved */


     83


     84 /*


     85  * wPortChange bit field


     86  * See USB 2.0 spec Table 11-22


     87  * Bits 0 to 4 shown, bits 5 to 15 are reserved


     88  */


     89 #define USB_PORT_STAT_C_CONNECTION      0x0001


     90 #define USB_PORT_STAT_C_ENABLE          0x0002


     91 #define USB_PORT_STAT_C_SUSPEND         0x0004


     92 #define USB_PORT_STAT_C_OVERCURRENT     0x0008


     93 #define USB_PORT_STAT_C_RESET           0x0010


这都是这两个变量对应的宏,usb 2.0的spec里面对这些宏的意义说得很清楚,USB_PORT_STAT_CONNECTION的意思的确是表征是否有设备连接在这个端口上,我们不妨假设有,那么portstatus和它相与的结果就是1,在usb spec里面,这一位叫做Current Connect Status位,于是这里我们会看到connect_change被设置成了1.而接下来,USB_PORT_STAT_C_CONNECTION则是表征这个端口的Current Connect Status位是否有变化,如果有变化,那么portchange和USB_PORT_STAT_C_CONNECTION相与的结果就是1,对于这种情况,我们需要发送另一个请求以清除这个flag,并且将connect_change也设置为1.这个请求叫做Clear Port Feature.这个请求也是Hub的标准请求,



它的作用就是reset hub端口的某种feature.clear_port_feature()定义于drivers/usb/core/hub.c:


    162 /*


    163  * USB 2.0 spec Section 11.24.2.2


    164  */


    165 static int clear_port_feature(struct usb_device *hdev, int port1, int feature)


    166 {


    167         return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),


    168                 USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,


    169                 NULL, 0, 1000);


    170 }


对比上面贴出来的定义可知,USB_REQ_CLEAR_FEATURE和usb spec中的CLEAR_FEATURE这个请求是对应的,那么一共有些什么Feature呢?在drivers/usb/core/hub.h中是这样定义的,


     38 /*


     39  * Port feature numbers


     40  * See USB 2.0 spec Table 11-17


     41  */


     42 #define USB_PORT_FEAT_CONNECTION        0


     43 #define USB_PORT_FEAT_ENABLE            1


     44 #define USB_PORT_FEAT_SUSPEND           2


     45 #define USB_PORT_FEAT_OVER_CURRENT      3


     46 #define USB_PORT_FEAT_RESET             4


     47 #define USB_PORT_FEAT_POWER             8


     48 #define USB_PORT_FEAT_LOWSPEED          9


     49 #define USB_PORT_FEAT_HIGHSPEED         10


     50 #define USB_PORT_FEAT_C_CONNECTION      16


     51 #define USB_PORT_FEAT_C_ENABLE          17


     52 #define USB_PORT_FEAT_C_SUSPEND         18


     53 #define USB_PORT_FEAT_C_OVER_CURRENT    19


     54 #define USB_PORT_FEAT_C_RESET           20


     55 #define USB_PORT_FEAT_TEST              21


     56 #define USB_PORT_FEAT_INDICATOR         22


而在usb spec中,有一张与之相对应的表格,定义了许多的feature,如图所示:


 


所以,我们清除的是C_PORT_CONNECTION这一个feature.spec里面说了,清除一个状态改变的feature就等于承认这么一个feature.(clearing that status change acknowledges the change)理由很简单,每次你检测到一个flag被设置之后,你都应该清除掉它,以便下次人家一设你就知道是人家设了,否则你不清你下次判断你就不知道是不是又有人设了.同理,接下来的每个与portchange相关的判断语句都要这么做.所以如果portchange与上USB_PORT_STAT_C_CONNECTION确实为1,那么我们就要清除这个feature.同时我们当然也要记录connect_change为1.


继续,每个端口都有一个开关,这叫做enable或者disable一个端口.portchange和USB_PORT_STAT_C_ENABLE相与如果为1的话,说明端口开关有变化.和刚才一样,首先我们要做的是,清除掉这个变化的feature.但是这里需要注意,spec里对这个feature是这样规定的,如果portchange和USB_PORT_STAT_C_ENABLE为1,说明这个port是从enable状态进入了disable状态.为什么呢?因为在spec规定了,Hub的端口是不可以直接设置成enable的.通常让Hub端口enable的方法是reset hub port.用spec的话说,这叫做发送另一个request,名为SET_FEATURE.SET_FEATURE和CLEAR_FEATURE是对应的,一个设置一个清除. 对于PORT_ENABLE这一位,用spec里的话说,This bit may be set only as a result of a SetPortFeature(PORT_RESET) request,PORT_RESET是为hub定义的众多feature中的一种.最后提醒一点,2711至2715这段if语句仅仅是为了打印调试信息的,就是说如果port enable改变了,但是端口连接没有改变,那么打印出信息来通知调试者,不要把clear_port_feature这一行也纳入到if语句里去了.因为port enable的改变有多种可能,其中一种可能就是由于检测到了disconnection,但是对于这种情况,我们下面要处理的,所以甭急.


下面这段代码就比较帅了,电磁干扰都给扯进来了.EMI,就是电磁干扰.就是说有的时候hub port的enable变成disable有可能是由于电磁干扰造成的,这个if条件判断的是,端口被disable了,但是连接没有变化,并且hdev->children还有值,这就说明明明有子设备连在端口上,可是端口却被disable了,基本上这种情况就是电磁干扰造成的,否则hub端口不会有这种抽风的举动.那么这种情况就设置connect_change为1.因为接下来我们会看到对于connect_change为1的情况,我们会专门进行处理,而更犀利更一针见血的说法就是,hub_events()其实最重要的任务就是对于端口连接有变化的情况进行处理,或者说进行响应.


再往下,portchange和USB_PORT_STAT_C_SUSPEND相与如果为1,表明连在该端口的设备的suspend状态有变化,并且是从suspended状态出来,也就是说resume完成.(别问我为什么,spec就这么规定的,没什么理由,一定要问理由那你问郑源去,他不是唱那什么如果你真的需要什么理由,一万个够不够吗.)那么首先我们就调用clear_port_feature清掉这个feature.接下来这个if牵扯到的东西比较高深,涉及到电源管理中很华丽的部分,我们只能先跳过.否则深陷其中难免会走火入魔欲罢不能.总之这里做的就是对于该端口连了子设备的情况就把子设备唤醒,否则如果端口没有连子设备,那么就把端口disable掉.


2754行,portchange如果和USB_PORT_STAT_C_OVERCURRENT相与结果为1的话,说明这个端口可能曾经存在电流过大的情况,而现在这种情况不存在了,或者本来不存在而现在存在了.对此我们能做的就是首先清除这个feature.有一种比较特别的情况是,如果其它的端口电流过大,那么将会导致本端口断电,即hub上一个端口出现over-current条件将有可能引起hub上其它端口陷入powered off的状态.不管怎么说,对于over-current的情况我们都把hub重新上电,执行hub_power_on().


2763行,portchange如果和USB_PORT_STAT_C_RESET相与为1的话,这叫做一个端口从Resetting状态进入到Enabled状态.


2771行,connect_change如果为1,就执行hub_port_connect_change(),啥也不说了,这是每一个看hub驱动的人最期待的函数,因为这正是我们的原始动机,即当一个usb设备插入usb接口之后究竟会发生什么,usb设备驱动程序提供那个probe函数究竟是如何被调用的.这些疑问统统会在这个函数里得到答案.来自drivers/usb/core/hub.c:


   2404 /* Handle physical or logical connection change events.


   2405  * This routine is called when:


   2406  *      a port connection-change occurs;


   2407  *      a port enable-change occurs (often caused by EMI);


   2408  *      usb_reset_device() encounters changed descriptors (as from


   2409  *              a firmware download)


   2410  * caller already locked the hub


   2411  */


   2412 static void hub_port_connect_change(struct usb_hub *hub, int port1,


   2413                                         u16 portstatus, u16 portchange)


   2414 {


   2415         struct usb_device *hdev = hub->hdev;


   2416         struct device *hub_dev = hub->intfdev;


   2417         u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);


   2418         int status, i;


   2419


   2420         dev_dbg (hub_dev,


   2421                 "port %d, status %04x, change %04x, %s\n",


   2422                 port1, portstatus, portchange, portspeed (portstatus));


   2423


   2424         if (hub->has_indicators) {


   2425                 set_port_led(hub, port1, HUB_LED_AUTO);


   2426                 hub->indicator[port1-1] = INDICATOR_AUTO;


   2427         }


   2428


   2429         /* Disconnect any existing devices under this port */


   2430         if (hdev->children[port1-1])


   2431                 usb_disconnect(&hdev->children[port1-1]);


   2432         clear_bit(port1, hub->change_bits);


   2433


   2434 #ifdef  CONFIG_USB_OTG


   2435         /* during HNP, don't repeat the debounce */


   2436         if (hdev->bus->is_b_host)


   2437                 portchange &= ~USB_PORT_STAT_C_CONNECTION;


   2438 #endif


   2439


   2440         if (portchange & USB_PORT_STAT_C_CONNECTION) {


   2441                 status = hub_port_debounce(hub, port1);


   2442                 if (status < 0) {


   2443                         if (printk_ratelimit())


   2444                                 dev_err (hub_dev, "connect-debounce failed, "


   2445                                                 "port %d disabled\n", port1);


   2446                         goto done;


   2447                 }


   2448                 portstatus = status;


   2449         }


   2450


   2451         /* Return now if nothing is connected */


   2452         if (!(portstatus & USB_PORT_STAT_CONNECTION)) {


   2453


   2454                 /* maybe switch power back on (e.g. root hub was reset) */


   2455                 if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2


   2456                                 && !(portstatus & (1 << USB_PORT_FEAT_POWER)))


   2457                         set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);


   2458


   2459                 if (portstatus & USB_PORT_STAT_ENABLE)


   2460                         goto done;


   2461                 return;


   2462         }


   2463


   2464 #ifdef  CONFIG_USB_SUSPEND


   2465         /* If something is connected, but the port is suspended, wake it up. */


   2466         if (portstatus & USB_PORT_STAT_SUSPEND) {


   2467                 status = hub_port_resume(hub, port1, NULL);


   2468                 if (status < 0) {


   2469                         dev_dbg(hub_dev,


   2470                                 "can't clear suspend on port %d; %d\n",


   2471                                 port1, status);


   2472                         goto done;


   2473                 }


   2474         }


   2475 #endif


   2476


   2477         for (i = 0; i < SET_CONFIG_TRIES; i++) {


   2478                 struct usb_device *udev;


   2479


   2480                 /* reallocate for each attempt, since references


   2481                  * to the previous one can escape in various ways


   2482                  */


   2483                 udev = usb_alloc_dev(hdev, hdev->bus, port1);


   2484                 if (!udev) {


   2485                         dev_err (hub_dev,


   2486                                 "couldn't allocate port %d usb_device\n",


   2487                                 port1);


   2488                         goto done;


   2489                 }


   2490


   2491                 usb_set_device_state(udev, USB_STATE_POWERED);


   2492                 udev->speed = USB_SPEED_UNKNOWN;


   2493                 udev->bus_mA = hub->mA_per_port;


   2494                 udev->level = hdev->level + 1;


   2495


   2496                 /* set the address */


   2497                 choose_address(udev);


   2498                 if (udev->devnum <= 0) {


   2499                         status = -ENOTCONN;     /* Don't retry */


   2500                         goto loop;


   2501                 }


   2502


   2503                 /* reset and get descriptor */


   2504                 status = hub_port_init(hub, udev, port1, i);


   2505                 if (status < 0)


   2506                         goto loop;


   2507


   2508                 /* consecutive bus-powered hubs aren't reliable; they can


   2509                  * violate the voltage drop budget.  if the new child has


   2510                  * a "powered" LED, users should notice we didn't enable it


   2511                  * (without reading syslog), even without per-port LEDs


   2512                  * on the parent.


   2513                  */


   2514                 if (udev->descriptor.bDeviceClass == USB_CLASS_HUB


   2515                                 && udev->bus_mA <= 100) {


   2516                         u16     devstat;


   2517


   2518                         status = usb_get_status(udev, USB_RECIP_DEVICE, 0,


   2519                                         &devstat);


   2520                         if (status < 2) {


   2521                                 dev_dbg(&udev->dev, "get status %d ?\n", status);


   2522                                 goto loop_disable;


   2523                         }


   2524                         le16_to_cpus(&devstat);


   2525                         if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {


   2526                                 dev_err(&udev->dev,


   2527                                         "can't connect bus-powered hub "


   2528                                         "to this port\n");


   2529                                 if (hub->has_indicators) {


   2530                                         hub->indicator[port1-1] =


   2531                                                 INDICATOR_AMBER_BLINK;


   2532                                         schedule_delayed_work (&hub->leds, 0);


   2533                                 }


   2534                                 status = -ENOTCONN;     /* Don't retry */


   2535                                 goto loop_disable;


   2536                         }


   2537                 }


   2538


   2539                 /* check for devices running slower than they could */


   2540                 if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200


   2541                                 && udev->speed == USB_SPEED_FULL


   2542                                 && highspeed_hubs != 0)


   2543                         check_highspeed (hub, udev, port1);


   2544


   2545                 /* Store the parent's children[] pointer.  At this point


   2546                  * udev becomes globally accessible, although presumably


   2547                  * no one will look at it until hdev is unlocked.


   2548                  */


   2549                 status = 0;


   2550


   2551                 /* We mustn't add new devices if the parent hub has


   2552                  * been disconnected; we would race with the


   2553                  * recursively_mark_NOTATTACHED() routine.


   2554                  */


   2555                 spin_lock_irq(&device_state_lock);


   2556                 if (hdev->state == USB_STATE_NOTATTACHED)


   2557                         status = -ENOTCONN;


   2558                 else


   2559                         hdev->children[port1-1] = udev;


   2560                 spin_unlock_irq(&device_state_lock);


   2561


   2562                 /* Run it through the hoops (find a driver, etc) */


   2563                 if (!status) {


   2564                         status = usb_new_device(udev);


   2565                         if (status) {


   2566                                 spin_lock_irq(&device_state_lock);


   2567                                 hdev->children[port1-1] = NULL;


   2568                                 spin_unlock_irq(&device_state_lock);


   2569                         }


   2570                 }


   2571


   2572                 if (status)


   2573                         goto loop_disable;


   2574


   2575                 status = hub_power_remaining(hub);


   2576                 if (status)


   2577                         dev_dbg(hub_dev, "%dmA power budget left\n", status);


   2578


   2579                 return;


   2580


   2581 loop_disable:


   2582                 hub_port_disable(hub, port1, 1);


   2583 loop:


   2584                 ep0_reinit(udev);


   2585                 release_address(udev);


   2586                 usb_put_dev(udev);


   2587                 if (status == -ENOTCONN)


   2588                         break;


   2589         }


   2590


   2591 done:


   2592         hub_port_disable(hub, port1, 1);


   2593 }


到今天我算是看明白了,内核里面这些函数,没有最变态只有更变态,变态哪都有,可是开源社区尤其多!你们他妈的不是我的冤家派来故意玩我的吧?面对这个函数,我真的想吐血!我打算不像过去那样一行一行讲了,我必须先来个提纲挈领,必须先开门见山把这个函数的哲学思想讲清楚,否则一行一行往下讲肯定晕菜. 



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fudan_abc/archive/2007/08/30/1766178.aspx

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
5
关闭 站长推荐上一条 /3 下一条