免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 36214 | 回复: 27
打印 上一主题 下一主题

学习Linux内核和驱动开发有终南捷径吗?欢迎来辩! [复制链接]

论坛徽章:
19
处女座
日期:2014-07-18 14:50:5415-16赛季CBA联赛之北京
日期:2019-09-16 15:39:1415-16赛季CBA联赛之上海
日期:2019-09-15 15:29:0415-16赛季CBA联赛之山西
日期:2017-03-09 10:58:232017金鸡报晓
日期:2017-02-08 10:33:212017金鸡报晓
日期:2017-01-10 15:13:2915-16赛季CBA联赛之深圳
日期:2016-12-15 17:55:53C
日期:2016-10-25 16:00:1515-16赛季CBA联赛之新疆
日期:2016-07-21 14:02:0415-16赛季CBA联赛之江苏
日期:2016-06-30 12:15:04shanzhi
日期:2016-06-17 17:59:31平安夜徽章
日期:2015-12-26 00:06:30
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-08-15 11:09 |只看该作者 |倒序浏览
获奖名单已公布:http://bbs.chinaunix.net/thread-4188427-1-1.html

话题背景
      这是一个连阅读都被碎片化的时代,在这样一个时代,人们趋向于激进、浮躁。内心的不安宁使我们极难静下心来研究什么。许许多多的Linux工程师,他们的简历书写着“精通”Linux内核,有多年的工作经验,而他们的“精通”却只是把某个寄存器从0改成1,从1改成0的不断重复;许许多多的Linux工程师终日埋头苦干,敲打着自己的机器和电路板,却从未冷静下来思考,并不断重构和升华自己的知识体系。
      Linux内核的版本更新达上千个,代码规模不断增长,平均每个版本的新增代码有4万行左右。在源代码的10个主要子目录中,驱动程序的代码量呈线性增长趋势。Linux各个子系统之间的关系错综复杂,系统整体规模和复杂性分别呈超线性和接近线性增长趋势,drivers和arch等模块的快速变化是引起系统复杂性增加的主因。设备驱动程序是连接计算机软件和硬件的纽带和桥梁,开发者在嵌入式操作系统的开发移植过程中,有将近70%~80%的精力都用在了驱动程序的开发与调试方面。这就对设备驱动程序开发人员提出了极高的要求。开发者不仅要同时具备软件和硬件的知识和经验,而且还要不断地学习、更新自己,以便跟上嵌入式系统日新月异的发展。在代码量最多的驱动程序中,有什么规律可循?最根本的又是什么?学习Linux内核和驱动开发有捷径吗?欢迎大家参与讨论,分享Linux内核和驱动开发的经验。


讨论话题
从以下话题中任选一个或多个话题参与讨论,这次讨论的话题内容不限于下面罗列的话题。
1. 分享Linux内核学习和驱动开发的经验。
2. 您觉得Linux驱动开发的难点是什么,有什么好的方法来克服?
3. Linux内核有上百个驱动子系统,你研究过内核各种驱动子系统的共性,层次结构设计吗?分享学习一个Linux内核子系统的经验,例如USB、I2C、HID等driver。
4. 您深入研究过Linux设备驱动模型,关注过Linux内核驱动的设计思想吗?
5. Android系统是基于Linux内核的,传统的Linux驱动开发和Android驱动开发有什么区别?


讨论时间
2015-08-17至2015-09-15


活动奖励
活动结束后将选取4名讨论精彩的童鞋,每人赠送一本《Linux设备驱动开发详解:基于最新的Linux 4.0内核》图书作为奖励。


奖品简介
   
作者: 宋宝华   
丛书名: 电子与嵌入式系统设计丛书
出版社:机械工业出版社
出版日期:2015 年8月
开本:16开
版次:1-1


内容简介:
     历时8年,三次重构,内窖愈加炉火纯青。全部代码更新至全新的Linux4.0版本。全面讲解ARM Linux新版本内核架构,如设备树等。不仅仅注重知识和程序的讲解,更注重程序的思想、演变、架构和算法。
      本书首先介绍Linux设备驱动的基础。第1章简要地介绍了设备驱动,并从无操作系统的设备驱动引出了Linux操作系统下的设备驱动,介绍了本书所基于的开发环境。第2章系统地讲解了Linux驱动工程师应该掌握的硬件知识,为工程师打下Linux驱动编程的硬件基础,详细介绍了各种类型的CPU、存储器和常见的外设,并阐述了硬件时序分析方法和数据手册阅读方法。第3章将Linux设备驱动放在Linux 2.6内核背景中进行讲解,说明Linux内核的编程方法。由于驱动编程也在内核编程的范畴,因此,这一章实质是为编写Linux设备驱动打下软件基础。
      其次,讲解Linux设备驱动编程的基础理论、字符设备驱动及设备驱动设计中涉及的并发控制、同步等问题。第4、5章分别讲解Linux内核模块和Linux设备文件系统;第6~9章以虚拟设备globalmem和globalfifo为主线,逐步给其添加高级控制功能;第10、11章分别阐述Linux驱动编程中所涉及的中断和定时器、内核和I/O操作处理方法。
      接着,剖析复杂设备驱动的体系结构以及块设备、网络设备驱动。该篇讲解了设备与驱动的分离、主机控制器驱动与外设驱动的分离,并以大量实例(如input、tty、LCD、platform、I2C、SPI、USB等)来佐证。其中第12章和第17章遥相呼应,力图全面地展示驱动的架构。Linux有100多个驱动子系统,逐个讲解和学习都是不现实的,授人以鱼不如授人以渔,因此我们将更多的焦点放在了架构讲解方面,以便读者可以举一反三。


样章试读:
文前.pdf (1.46 MB, 下载次数: 208)
1-3z.txt (114.01 KB, 下载次数: 129)

shupi.jpg (33.22 KB, 下载次数: 363)

shupi.jpg

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
2 [报告]
发表于 2015-08-17 15:31 |只看该作者
支持

求职 : Linux运维
论坛徽章:
19
CU大牛徽章
日期:2013-03-13 15:15:0815-16赛季CBA联赛之山东
日期:2016-10-31 10:40:10综合交流区版块每日发帖之星
日期:2016-07-06 06:20:00IT运维版块每日发帖之星
日期:2016-02-08 06:20:00数据库技术版块每日发帖之星
日期:2016-01-15 06:20:00IT运维版块每日发帖之星
日期:2016-01-15 06:20:00IT运维版块每日发帖之星
日期:2016-01-10 06:20:00黄金圣斗士
日期:2015-11-24 10:45:10IT运维版块每日发帖之星
日期:2015-09-01 06:20:00IT运维版块每日发帖之星
日期:2015-08-13 06:20:00IT运维版块每日发帖之星
日期:2015-07-30 09:40:012015年亚洲杯之巴勒斯坦
日期:2015-05-05 10:19:03
3 [报告]
发表于 2015-08-17 16:37 |只看该作者
先支持意向,等想好了再写讨论内容,不过我个人理解LINUX内核很像进化中的生命体,同时它的模块化理念非常高级,每一个层次都在不断的进化和完善,同时不会影响全局的使用。

论坛徽章:
15
2015七夕节徽章
日期:2015-08-21 11:06:172017金鸡报晓
日期:2017-01-10 15:19:56极客徽章
日期:2016-12-07 14:07:30shanzhi
日期:2016-06-17 17:59:3115-16赛季CBA联赛之四川
日期:2016-04-13 14:36:562016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-01-28 06:20:0015-16赛季CBA联赛之新疆
日期:2016-01-25 14:01:34IT运维版块每周发帖之星
日期:2016-01-07 23:04:26数据库技术版块每日发帖之星
日期:2016-01-03 06:20:00数据库技术版块每日发帖之星
日期:2015-12-01 06:20:00IT运维版块每日发帖之星
日期:2015-11-10 06:20:00
4 [报告]
发表于 2015-08-18 09:05 |只看该作者
没深入搞过,乱谈一番:
1. 分享Linux内核学习和驱动开发的经验。
    驱动开发其实有一定的模式,主要是要了解硬件的特性以及如何对接到驱动的函数中,还有就是要适应内核编程的环境以及调试的方法

2. 您觉得Linux驱动开发的难点是什么,有什么好的方法来克服?
    难点就是后面的调试

3. Linux内核有上百个驱动子系统,你研究过内核各种驱动子系统的共性,层次结构设计吗?分享学习一个Linux内核子系统的经验,例如USB、I2C、HID等driver。
    每一个子系统都巨大无比,没那个能力去完全搞明白  

4. 您深入研究过Linux设备驱动模型,关注过Linux内核驱动的设计思想吗?
    个人理解设计思想就是回调函数,给一个API让你注册,后面通过注册ID找到对应的回调函数进行处理

5. Android系统是基于Linux内核的,传统的Linux驱动开发和Android驱动开发有什么区别?
    Android的驱动就是要对C语言再进行一层包装,采用类似JNI/JNA机制向Android上层提供Java的API,这样厂商可以决定驱动的主要部分在C还是Java实现

求职 : Linux运维
论坛徽章:
19
CU大牛徽章
日期:2013-03-13 15:15:0815-16赛季CBA联赛之山东
日期:2016-10-31 10:40:10综合交流区版块每日发帖之星
日期:2016-07-06 06:20:00IT运维版块每日发帖之星
日期:2016-02-08 06:20:00数据库技术版块每日发帖之星
日期:2016-01-15 06:20:00IT运维版块每日发帖之星
日期:2016-01-15 06:20:00IT运维版块每日发帖之星
日期:2016-01-10 06:20:00黄金圣斗士
日期:2015-11-24 10:45:10IT运维版块每日发帖之星
日期:2015-09-01 06:20:00IT运维版块每日发帖之星
日期:2015-08-13 06:20:00IT运维版块每日发帖之星
日期:2015-07-30 09:40:012015年亚洲杯之巴勒斯坦
日期:2015-05-05 10:19:03
5 [报告]
发表于 2015-08-18 20:45 |只看该作者
本帖最后由 niao5929 于 2015-08-18 20:45 编辑


1. 分享Linux内核学习和驱动开发的经验。
    读代码,编译内核的初级级别,自己没社么经验

2. 您觉得Linux驱动开发的难点是什么,有什么好的方法来克服?
    难点就是建模和对底层硬件的深入了解

3. Linux内核有上百个驱动子系统,你研究过内核各种驱动子系统的共性,层次结构设计吗?分享学习一个Linux内核子系统的经验,例如USB、I2C、HID等driver。
    linux 模块化的设计最让人感到方便,这样的设计可以非常方便的进行模块的替换和组装,这也是LINUX非常有应用广度的一个方面。

4. 您深入研究过Linux设备驱动模型,关注过Linux内核驱动的设计思想吗?
   感觉LINUX因为自由和开源的关系,她的进化非常类似与生命的特点。自由开源软件可以承载更多新思想和新技术。Linux内核自4.1开始支持不停机的热升级。这必然涉及到驱动的动态更新问题。这些新特性总是让好奇的我想看个究竟。

5. Android系统是基于Linux内核的,传统的Linux驱动开发和Android驱动开发有什么区别?
    Android总感觉似乎需要用到很多JAVA的技术,而目前JAVA确实已经被ORACLE搞得非常的让人担忧。我觉得程序员或者编程爱好者都应该学习更自由和开放的GO、PYTHON、D等等这些纯的自由开源软件,还是那句话:自由开源软件可以承载更多新思想和新技术。

论坛徽章:
0
6 [报告]
发表于 2015-08-19 07:35 |只看该作者
cool,mark,
不过还是不想做驱动,还是搞搞网络编程吧。

论坛徽章:
0
7 [报告]
发表于 2015-08-19 11:01 |只看该作者
本帖最后由 kartorz 于 2015-08-20 09:44 编辑

1. 分享Linux内核学习和驱动开发的经验。

捷径没有,但是有合理的方法。

1)  首先,需要熟悉操作系统的设计与实现,推荐大家看 MINIX作者的那部书,同时把MINIX的kernel代码研读一下。 不然,你不知道操作系统都有哪些模块, 不知道操作系统要做些什么事情,提供什么功能。
      简单地说,操作系统首先要驱动 CPU,然后提供那几大管理(中断,进程,内存),实现一,两百个系统呼叫,提供驱动接口。
      
2)  去intel的官网,找一下 Intel® 64 and IA-32 Architectures Software Developer’s Manual , 了解一下 CPU的架构,工作模式,底层的编码。否则, 你不知道 gdt, ldt,  page table, 实地址,保护模式,timer等中断都是什么东西,为什么操作系统要这样来设置寄存器。
      这块基本上全是汇编语言,对CPU的初始化,寄存器设置,手册上面都有严格的时序要求。 哪些操作需要屏蔽中断,哪些需要在一个指令周期完成等等。

有了上面的基础后,大概知道一个操作系统大概要做些什么事情, 如何驱动底层的 CPU,这个时候阅读 linux的kernel代码,事半功倍。

kernel 分为两个模块:一个是 core : 驱动cpu, 中断,进程,内存几大管理, 提供系统呼叫;   另一个是driver,  驱动设备工作。 linux的driver 都是有架构的,不需要从底层做起。 driver的架构大概就是 char, block, net, video, audio, usb, 等等。 别看操作系统的代码量大,其实,把driver 占了估计 90%的代码量, 这些都是不需要去看的。  driver 框架的设计,也就是 微内核 与 宏内核的区别。

阅读过程中,观其大略即可,主要了解整个结构,以及程序的流程。 如: 系统呼叫的调用, 追一个就可以了。—— 看看,操作系统如何捕捉软中断, 根据中断号,dispatch到相应的服务程序,如何 保存现场, 完成后,又回到用户态。 系统呼叫调用,核心 就是 dispatch的流程。 追完一支系统呼叫,其它的大概就知道怎么回事了。  driver 也就一样的, 找个简单的驱动看看, 从驱动层一直到驱动的架构,流程清楚就可以了。 如 char 设备驱动, 追一下 register 以后, 驱动框架如何 把该设备放入 list,当有用户请求的时候,它又如何 查找到 相应的设备,调用 相应的操作函数。 一路下来,流程大概知道就可以了。

不建议阅读, 毛德操的 linux内核源码分析 之类的书, 会让读者一头雾水。 正确的方法应该是, 先了解相应的背景知识后,再来阅读源码。 举个例子,你想了解 ext4的文件系统驱动代码,首先你得去查资料,搞清楚 ext4文件系统是怎么回事,再来阅读代码。 之前,推荐初学者 先 阅读 操作系统设计实现, intel的编程手册,就是这个道理。 只有了解了背景,再阅读源码时,一切都 迎刃而解了。 不推荐 毛德操的书也是个道理,书里面告诉你,代码一会跳到这里,一会又call back到注册的函数,一会又调用了什么,只见树木,而不见森林。

评分

参与人数 1信誉积分 +10 收起 理由
shenlanyouyu + 10 赞一个!

查看全部评分

论坛徽章:
19
处女座
日期:2014-07-18 14:50:5415-16赛季CBA联赛之北京
日期:2019-09-16 15:39:1415-16赛季CBA联赛之上海
日期:2019-09-15 15:29:0415-16赛季CBA联赛之山西
日期:2017-03-09 10:58:232017金鸡报晓
日期:2017-02-08 10:33:212017金鸡报晓
日期:2017-01-10 15:13:2915-16赛季CBA联赛之深圳
日期:2016-12-15 17:55:53C
日期:2016-10-25 16:00:1515-16赛季CBA联赛之新疆
日期:2016-07-21 14:02:0415-16赛季CBA联赛之江苏
日期:2016-06-30 12:15:04shanzhi
日期:2016-06-17 17:59:31平安夜徽章
日期:2015-12-26 00:06:30
8 [报告]
发表于 2015-08-19 13:26 |只看该作者
回复 7# kartorz


    分享有干货,感谢分享。

论坛徽章:
1
天蝎座
日期:2013-10-23 21:11:03
9 [报告]
发表于 2015-08-19 14:28 |只看该作者
回复 1# shenlanyouyu


临时想起一些说一下吧:


1. 分享Linux内核学习和驱动开发的经验。

内核学习

Linux 内核功能越来越完善,如果没有充裕的时间,深入内核并不是很现实。所以建议先读一本内核的书,
第一遍是读,会读的很迷糊;之后反省一下,然后再浏览一下;可以想象一个 OS 是如何运行的,这样可以不
陷入 Linux 内核的细节;最后可以深入自己感兴趣或者需要的那一子系统

        推荐 《Linux Kernel Development》

即便是子系统,也是很庞大的。一个省力的方式是网上搜一些相关的文章,便于快速了解这个子系统的运作;
然后结合代码,形成自己的认知,最后做一下总结。如果仅仅是快速了解某一子系统的运作,可以参考一些早期
代码的注解书籍,再深入的时候看看最新的代码实现

对内核的认知是一个反复的过程,一开始并不完善,可能需要反复纠正。不要陷入这种纠错中;而是以后继续
使用和学习过程中,发现了没有弄清楚的地方再深入,毕竟 Linux 内核是不断变化的

还有一个很好的方式是,从系统调用入手,现在这方面的数据不少,而且对系统调用的语义都有讲解,这样可以
间接了解 Linux 系统的一些概念。对系统调用熟悉了,可以根据系统调用的执行过程,来大体了解内核的一个
运作过程;但是跟踪系统调用的时候要注意抓主线,现在内核系统很复杂,一些 code path 上可能会涉及多个
子系统,可以从名字上猜测它们是干什么的,不需要深入,否则会发现精力完全被分散掉了

学习 Linux 内核,一个很重要的是抽象的能力,所谓的抽象这里仅仅是指分清接口和接口的实现。因为 Linux
内核子系统很多,有很多子系统相互渗透,这样 code path 看上去很复杂。阅读代码的时候,为了排除干扰,
需要分清哪些是自己需要看的,哪些是其它子系统的接口,对于其它子系统的接口,先当作它们功能完善不会
出问题好了,这样可以关注重点;打个比方,一个应用程序的代码可能量很大,比如一个 apache 项目,它
包含很多组件,有时候阅读代码的时候会看到不同组件的 API,深入看相关组件实现并不现实,这时候分清主次
对于代码的阅读就很有帮助了,总不能看到了 malloc 就要先把它的实现弄清楚吧,系统调用多者呢

推荐书籍
        OReilly.Linux.System.Programming.2nd.Edition
        The.Linux.Programming.Interface


驱动开发

一直围绕服务器做,接触的比较多的是网卡驱动。最开始想着从上到下,好好学习协议栈,后来发现内容太多,
进展太慢。后来参考一些驱动开发方面的书籍,把驱动独立开,使用内核提供的接口,就类似写应用的时候很多
情况下只需要了解系统接口和库函数的原型描述而不需要继续深入一样。这样把自己从内核复杂的实现细节中解
放出来,可以重点看网卡的特性部分;之后可以再深入了解设备的运作过程,比如网卡的收发包在协议栈中的
位置和运作

个人感觉如果工作中能接触驱动开发最好,否则很多情况下,有的设备并不常见,比如 Infiniband 卡

现在民用设备越来越广泛,可以选择自己感兴趣而手头又容易有的设备进行研究,比如无线网卡、wifi 等
驱动开发,一定要先专注一个设备,从头到尾熟悉一遍,然后总结驱动开发是怎样的、驱动是如何关联到系统中
的、Linux 采用什么样的分层模式来提供对多种多样设备的支持,如类似 VFS 一样的抽象分层

推荐
        linux device driver, 3rd edition
        Linux设备驱动开发详解



2. 您觉得Linux驱动开发的难点是什么,有什么好的方法来克服?

Linux 内核对各种设备的驱动开发提供了完善的框架支持,对应某个驱动,把对外的接口弄清楚就可以了。打个
比方,一个设备可能在不同的 OS 上需要支持,比如 FreeBSD/Windows 等,每个 OS 都有自己定义的接口,
设备的驱动定义好与这些 OS 接口的连接,剩下的就是设备本身的特性管理以及驱动接口中对设备管理函数的调
用了,比如寄存器访问、配置管理、缓冲区管理、数据收发等,比较重要的中断和同步的控制,要避免数据处理的
时候的死锁。

比如网卡驱动,基本的要求是提供内核需要的接口,这样网卡驱动才能挂接到系统中,剩下的就是接口需要调用
网卡驱动的内部函数,来对网卡进行控制、数据收发和管理等

Linux 支持的设备种类繁多,不可能所有都掌握,某一子系统也只能是熟悉,因为同类设备还有许多自由的特性。
写驱动的步骤可以概括为:
        1) 阅读设备规范,对设备的运行机理有所了解
           为了减少干扰,不考虑要支持的 OS,独立与 OS 考虑基本的功能如何实现
        2) 参考同类设备在 Linux 内核中的驱动架构
        3) 提供基本的 Linux 设备驱动接口和实现设备的基本功能,比如网卡收发小数据量
        4) 在性能上逐步提示,比如网卡传输的数据量加大、中断及时处理、避免死锁等
        5) 对边界条件进行完善,网卡上就是对一些特殊大小的数据包传输完善等
        6) 对设备进行更高级控制的支持,比如网卡支持 ethtool 等工具
        7) 反复调试、改进和优化



3. Linux内核有上百个驱动子系统,你研究过内核各种驱动子系统的共性,层次结构设计吗?分享学习一个Linux内核子系统的经验,例如USB、I2C、HID等driver。

        每一个子系统都巨大无比,而且涉及各种硬件规范,很难去搞明白所有。只能是遇到问题的时候,
        能对某一部分深入下去。之前了解过 SCSI 的架构,最上层的抽象,中间层的桥梁,最底层的设备
        驱动控制
        如果仅仅是做 driver 的工作,可以把精力放在设备特性上,Linux 内核部分只需要了解驱动
        接口和同步、内存管理等基本功能



4. 您深入研究过Linux设备驱动模型,关注过Linux内核驱动的设计思想吗?

        Linux 设备驱动模型是从分类的角度来看待设备,分类是多维的,所以 /sys 下也是多个目录
        另外,设备驱动模型给出了系统中设备布局信息,比如根据总线地址可以定位对应的设备目录等

        Linux 内核驱动可以都是遵循一个逐层抽象的架构:
                最上层的抽象层便于系统软件的访问,
                中间层的实现硬件协议细节,同时提供上下两层连接的接口,
                对于最下层的 driver 来说就是要定义底层驱动要实现的接口和实际的设备控制
        由于 Linux 内核各类驱动的框架支持,driver 可以更加关注设备本身的特性
       


5. Android系统是基于Linux内核的,传统的Linux驱动开发和Android驱动开发有什么区别?

        传统的 Linux 内核驱动开发,只需要定义好 Linux 需要的驱动接口就好了,之后
        专注与设备本身的特性
        而 Android 驱动开发,需要将设备操作接口继续封装,提供上层使用的 Java API;
        driver 部分可以使用 C 代码,一些更复杂的操作可以用 Java 实现,然后 driver
        提供对复杂操作的接口支持
        一个很重要的方面是功能的分离定义,比如哪些是 driver 实现的,哪些是上层实现的,
        它们之间的接口是怎样的,定义好这些,就可以按照传统 driver 的实现方式来做了;
        从某种程度上,可以看作是传统 driver 跟相关 tools 转换成了 Android driver
        和上层 Java 接口


评分

参与人数 1信誉积分 +10 收起 理由
shenlanyouyu + 10 很给力!

查看全部评分

论坛徽章:
0
10 [报告]
发表于 2015-08-19 18:43 |只看该作者
本帖最后由 lyl19 于 2015-08-19 18:44 编辑

回复 1# shenlanyouyu

我觉得设备驱动 开发对kernel的掌握还算是次要的,最重要的是对arch, 以及硬件的理解。
印象中发生了太多的case, 与arch相关的,比如说memory barrier,都要花比较大的气力解决。
而与硬件相关的,比如说DMA hung之类的,中断不触发之类的,这个时候,单纯从软件来很难解决,一般都是WAR,比如复位啥的。但如果有机会去读到硬件的RTL, 这个时候你对这类的问题将不再是恐惧,而是心里会有数。

所以个人认为,设备驱动的编写绝不是单纯软件的事情,必须要熟悉该设备的RTL,如果你能够得到的话。





   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP