PMBus协议规范介绍

PMBus是一套对电源进行配置、控制和监控的通讯协议标准。其最新版本为1.3,该规范还在不断演进中,比如新标准中新增的zone PMBus、AVSBus等特性。在其官网上有详细的规范文档,本节不尝试翻译规范文档,重点记录作者在了解PMBus过程中的疑问和解答。

PMBus与I2C、SMBus的区别?

PMBus在SMBus(System Management Bus)基础上增加了一套电源配置、控制和监控规范。SMBus最初是为电池智能管理而开发的一套标准,其基于I2C协议,并针对I2C协议的弱健壮性做了如下改进:

  • 支持SMBALERT#中断;
  • 支持错包检测(PEC);
  • 支持包超时;
  • 支持START/STOP保护;
  • 支持Host Notify Protocol协议;

PMBus监控哪些参数?告警分为几级?不同告警级别有什么样的应对措施?

PMBus支持电压、电流、功率、温度和风扇等参数的上下限监控,支持warning和fault 2级告警级别(如上图所示)。

  • warning告警:表示监控参数异常,系统需引起关注,但可以继续运行,系统无需任何响应措施;
  • fault告警:比warning告警级别高,系统会根据异常对设备的危害情况,进行设备控制电路重启(restart)或输出切断(shutdown)等处理;

告警产生时如何上报给主机?

告警上报一般有如下几种方式:

  • 主机轮询PMBus设备;
  • PMBus设备通过SMBALERT#中断通知主机;
  • Host Notify Protocol(PMBus设备临时切换成总线主机(bus master),并发送一组特定协议通知系统主机)。

什么情况下告警会取消或清除?重启是否会清除告警?

任何warning或fault告警一旦上报,只有通过如下几种方式可以取消清除:

  • PMBus设备接收到CLEAR_FAULTS命令;
  • PMBus设备RESET引脚生效;
  • PMBus设备通过CONTROL引脚或OPERATION命令关闭并重新打开;
  • 断电;
  • 如果异常一直存在,那么即使进行告警清除操作,告警会马上重新上报。

linux PMBus驱动设计分析

PMBus设备驱动位于linux/drivers/hwmon/pmbus,文件组织划分为3个部分:

比较有意思的是PMBus的通用设备驱动框架设计部分,其设计方案主要要解决如下2个问题:

  1. 支持PMBus设备厂商的自定义功能集。PMBus规范定义一套功能集,其中有些是基本功能,有些是可选功能;
  2. 支持PMBus设备厂商的自定义寄存器。

pmbus驱动框架的数据模型如下,其核心对象为i2c_client,即i2c设备对象,i2c_client继承于linux设备驱动模型device对象。pmbus设备信息通过设备驱动模型抽象接口driver_data访问,由pmbus_data对象实现。pmbus_data对象又关联如下2个主要对象:

  • pmbus_driver_info:PMBus设备支持的功能集描述及相关接口,由pmbus设备实现。
  • pmbus_sensor:PMBus设备支持的监控传感器对象链表,由voltage/current/power/temp/fan实现。

pmbus设备功能集识别有2种实现方式:

  • 由pmbus_driver_info对象的identify接口完成,其工作原理是通过读取功能寄存器,如果读取成功,则说明设备支持此功能,否则不支持;
  • 直接静态初始化pmbus_driver_info。

设备自定义寄存器通过虚拟寄存器(Virtual registers)统一到pmbus驱动框架中。pmbus通用设备驱动只看到标准寄存器和虚拟寄存器。虚拟寄存器到设备自定义寄存器的映射过程通过设备注册的4个接口:read_byte_data/read_word_data/write_word_data/write_byte来完成。 

应用示例

1. 编写pmbus设备的smbus总线设备驱动并注册。如下i2c-10[1-3]为epld实现的4个i2c总线设备

  1. / # ls /sys/bus/i2c/devices/ -l
  2. total 0
  3. lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-100 -> ../../../devices/i2c-100
  4. lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-101 -> ../../../devices/i2c-101
  5. lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-102 -> ../../../devices/i2c-102
  6. lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-103 -> ../../../devices/i2c-103
  7.  
  8. / # cats '/sys/bus/i2c/devices/i2c-10*/name'
  9. /sys/bus/i2c/devices/i2c-100/name: WORK_EPLD1
  10. /sys/bus/i2c/devices/i2c-101/name: WORK_EPLD2.0
  11. /sys/bus/i2c/devices/i2c-102/name: WORK_EPLD2.1
  12. /sys/bus/i2c/devices/i2c-103/name: WORK_NSE
  13. / #

  

2. 编写pmbus设备驱动并注册。如下为注册方法,hwmon[0-9]为注册的pmbus设备

  1. echo tps53667 0x60 > /sys/bus/i2c/devices/i2c-100/new_device
  2. echo tps53667 0x62 > /sys/bus/i2c/devices/i2c-100/new_device
  3. echo tps53667 0x1060 > /sys/bus/i2c/devices/i2c-100/new_device
  4. echo tps53667 0x1062 > /sys/bus/i2c/devices/i2c-100/new_device
  5.  
  6. echo tps53667 0x60 > /sys/bus/i2c/devices/i2c-101/new_device
  7. echo tps53667 0x60 > /sys/bus/i2c/devices/i2c-102/new_device
  8.  
  9. echo tps53667 0x70 > /sys/bus/i2c/devices/i2c-103/new_device
  10. echo tps53667 0x1071 > /sys/bus/i2c/devices/i2c-103/new_device
  11. echo tps53667 0x2072 > /sys/bus/i2c/devices/i2c-103/new_device
  12. echo tps53667 0x3073 > /sys/bus/i2c/devices/i2c-103/new_device
  13.  
  14. / # ls /sys/class/hwmon/ -l
  15. total 0
  16. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon0 -> ../../devices/i2c-100/100-0060/hwmon/hwmon0
  17. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon1 -> ../../devices/i2c-100/100-0062/hwmon/hwmon1
  18. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon2 -> ../../devices/i2c-100/100-1060/hwmon/hwmon2
  19. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon3 -> ../../devices/i2c-100/100-1062/hwmon/hwmon3
  20. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon4 -> ../../devices/i2c-101/101-0060/hwmon/hwmon4
  21. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon5 -> ../../devices/i2c-102/102-0060/hwmon/hwmon5
  22. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon6 -> ../../devices/i2c-103/103-0070/hwmon/hwmon6
  23. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon7 -> ../../devices/i2c-103/103-1071/hwmon/hwmon7
  24. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon8 -> ../../devices/i2c-103/103-2072/hwmon/hwmon8
  25. lrwxrwxrwx 1 root root 0 Jan 1 00:00 hwmon9 -> ../../devices/i2c-103/103-3073/hwmon/hwmon9

  

3. 查看pmbus设备监控数据,所有字段解释详见kernel文档

  1. /sys/class/hwmon # cats 'hwmon2/device/*'
  2. # 电流监控数据 单位:mA 毫安 /1000
  3. hwmon2/device/curr1_crit: 255000
  4. hwmon2/device/curr1_crit_alarm: 0
  5. hwmon2/device/curr1_input: 2679
  6. hwmon2/device/curr1_label: iin
  7. hwmon2/device/curr1_max: 25000
  8. hwmon2/device/curr1_max_alarm: 0
  9. hwmon2/device/curr2_crit: 122000
  10. hwmon2/device/curr2_crit_alarm: 0
  11. hwmon2/device/curr2_input: 22968
  12. hwmon2/device/curr2_label: iout1
  13. hwmon2/device/curr2_max: 98000
  14. hwmon2/device/curr2_max_alarm: 0
  15. hwmon2/device/driver: cat: read error: Is a directory
  16. hwmon2/device/hwmon: cat: read error: Is a directory
  17. # 电压监控数据 单位:mV 毫伏 1/1000
  18. hwmon2/device/in1_crit: 17000
  19. hwmon2/device/in1_crit_alarm: 0
  20. hwmon2/device/in1_input: 11906
  21. hwmon2/device/in1_label: vin
  22. hwmon2/device/in2_alarm: 0
  23. hwmon2/device/in2_input: 631
  24. hwmon2/device/in2_label: vout1
  25. hwmon2/device/modalias: i2c:tps53667
  26. hwmon2/device/name: tps53667
  27. # 功率监控数据 单位:uW 微伏 1/1000000
  28. hwmon2/device/power1_input: 31625000
  29. hwmon2/device/power1_label: pin
  30. hwmon2/device/power2_input: 23343750
  31. hwmon2/device/power2_label: pout1
  32. hwmon2/device/subsystem: cat: read error: Is a directory
  33. # 温度监控数据 单位:m℃ 毫摄氏度 1/1000
  34. hwmon2/device/temp1_crit: 125000
  35. hwmon2/device/temp1_crit_alarm: 0
  36. hwmon2/device/temp1_input: 35500
  37. hwmon2/device/temp1_max: 95000
  38. hwmon2/device/temp1_max_alarm: 0
  39. hwmon2/device/uevent: DRIVER=tps53667
  40. MODALIAS=i2c:tps53667

  

4. 构造一个UV fault alarm,如下。可见异常恢复后,告警依然保持,不会清除;重启也不是清除告警;手动清除后,告警清除。

  1. /sys/devices/i2c-103/103-3073 # cats 'in*'
  2. in1_crit: 17000
  3. in1_crit_alarm: 0
  4. in1_input: 11968
  5. in1_label: vin
  6. in2_alarm: 0
  7. in2_input: 0
  8. in2_label: vout1
  9. /sys/devices/i2c-103/103-3073 # echo 10000 > in1_crit  # 将in voltage的UV fault阈值设成10V
  10. /sys/devices/i2c-103/103-3073 # cats 'in*'
  11. in1_crit: 10000
  12. in1_crit_alarm: 1  # 告警触发
  13. in1_input: 11953
  14. in1_label: vin
  15. in2_alarm: 0
  16. in2_input: 0
  17. in2_label: vout1
  18. /sys/devices/i2c-103/103-3073 # echo 17000 > in1_crit  # 将in voltage的UV fault阈值恢复成17V
  19. /sys/devices/i2c-103/103-3073 # cats 'in*'
  20. in1_crit: 17000
  21. in1_crit_alarm: 1  # 异常后再恢复正常,告警依然保持
  22. in1_input: 11968
  23. in1_label: vin
  24. in2_alarm: 0
  25. in2_input: 0
  26. in2_label: vout1
  27. /sys/devices/i2c-103/103-3073 # reboot
  28. 。。。(启动过程省略)
  29. /sys/devices/i2c-103/103-3073 # cats 'in*'
  30. in1_crit: 17000
  31. in1_crit_alarm: 1  # 重启不会清除告警
  32. in1_input: 11968
  33. in1_label: vin
  34. in2_alarm: 0
  35. in2_input: 0
  36. in2_label: vout1
  37. /sys/devices/i2c-103/103-3073 # echo 0 > clear_fault   # 手动清除告警
  38. /sys/devices/i2c-103/103-3073 # cats 'in*'
  39. in1_crit: 17000
  40. in1_crit_alarm: 0  # 告警清除
  41. in1_input: 11968
  42. in1_label: vin
  43. in2_alarm: 0
  44. in2_input: 631
  45. in2_label: vout1

  

附主要数据结构:

  1. struct pmbus_data {
  2. struct device *dev;
  3. struct device *hwmon_dev;
  4.  
  5. u32 flags; /* from platform data */
  6.  
  7. int exponent; /* linear mode: exponent for output voltages */
  8.  
  9. const struct pmbus_driver_info *info;
  10.  
  11. int max_attributes;
  12. int num_attributes;
  13. struct attribute_group group;
  14.  
  15. struct pmbus_sensor *sensors;
  16.  
  17. struct mutex update_lock;
  18. bool valid;
  19. unsigned long last_updated; /* in jiffies */
  20.  
  21. /*
  22. * A single status register covers multiple attributes,
  23. * so we keep them all together.
  24. */
  25. u8 status[PB_NUM_STATUS_REG];
  26. u8 status_register;
  27.  
  28. u8 currpage;
  29. };
  30.  
  31. struct pmbus_driver_info {
  32. int pages; /* Total number of pages */
  33. enum pmbus_data_format format[PSC_NUM_CLASSES];
  34. /*
  35. * Support one set of coefficients for each sensor type
  36. * Used for chips providing data in direct mode.
  37. */
  38. int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */
  39. int b[PSC_NUM_CLASSES]; /* offset */
  40. int R[PSC_NUM_CLASSES]; /* exponent */
  41.  
  42. u32 func[PMBUS_PAGES]; /* Functionality, per page */
  43. /*
  44. * The following functions map manufacturing specific register values
  45. * to PMBus standard register values. Specify only if mapping is
  46. * necessary.
  47. * Functions return the register value (read) or zero (write) if
  48. * successful. A return value of -ENODATA indicates that there is no
  49. * manufacturer specific register, but that a standard PMBus register
  50. * may exist. Any other negative return value indicates that the
  51. * register does not exist, and that no attempt should be made to read
  52. * the standard register.
  53. */
  54. int (*read_byte_data)(struct i2c_client *client, int page, int reg);
  55. int (*read_word_data)(struct i2c_client *client, int page, int reg);
  56. int (*write_word_data)(struct i2c_client *client, int page, int reg,
  57. u16 word);
  58. int (*write_byte)(struct i2c_client *client, int page, u8 value);
  59. /*
  60. * The identify function determines supported PMBus functionality.
  61. * This function is only necessary if a chip driver supports multiple
  62. * chips, and the chip functionality is not pre-determined.
  63. */
  64. int (*identify)(struct i2c_client *client,
  65. struct pmbus_driver_info *info);
  66. };
  67.  
  68. struct pmbus_sensor {
  69. struct pmbus_sensor *next;
  70. char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
  71. struct device_attribute attribute;
  72. u8 page; /* page number */
  73. u16 reg; /* register */
  74. enum pmbus_sensor_classes class; /* sensor class */
  75. bool update; /* runtime sensor update needed */
  76. int data; /* Sensor data.
  77. Negative if there was a read error */
  78. };
  79.  
  80. /*
  81. * Virtual registers.
  82. * Useful to support attributes which are not supported by standard PMBus
  83. * registers but exist as manufacturer specific registers on individual chips.
  84. * Must be mapped to real registers in device specific code.
  85. *
  86. * Semantics:
  87. * Virtual registers are all word size.
  88. * READ registers are read-only; writes are either ignored or return an error.
  89. * RESET registers are read/write. Reading reset registers returns zero
  90. * (used for detection), writing any value causes the associated history to be
  91. * reset.
  92. * Virtual registers have to be handled in device specific driver code. Chip
  93. * driver code returns non-negative register values if a virtual register is
  94. * supported, or a negative error code if not. The chip driver may return
  95. * -ENODATA or any other error code in this case, though an error code other
  96. * than -ENODATA is handled more efficiently and thus preferred. Either case,
  97. * the calling PMBus core code will abort if the chip driver returns an error
  98. * code when reading or writing virtual registers.
  99. */
  100. #define PMBUS_VIRT_BASE 0x100
  101. #define PMBUS_VIRT_READ_TEMP_AVG (PMBUS_VIRT_BASE + 0)
  102. #define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 1)
  103. #define PMBUS_VIRT_READ_TEMP_MAX (PMBUS_VIRT_BASE + 2)
  104. #define PMBUS_VIRT_RESET_TEMP_HISTORY (PMBUS_VIRT_BASE + 3)
  105. #define PMBUS_VIRT_READ_VIN_AVG (PMBUS_VIRT_BASE + 4)
  106. #define PMBUS_VIRT_READ_VIN_MIN (PMBUS_VIRT_BASE + 5)
  107. #define PMBUS_VIRT_READ_VIN_MAX (PMBUS_VIRT_BASE + 6)
  108. #define PMBUS_VIRT_RESET_VIN_HISTORY (PMBUS_VIRT_BASE + 7)
  109. #define PMBUS_VIRT_READ_IIN_AVG (PMBUS_VIRT_BASE + 8)
  110. #define PMBUS_VIRT_READ_IIN_MIN (PMBUS_VIRT_BASE + 9)
  111. #define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 10)
  112. #define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 11)
  113. #define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 12)
  114. #define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 13)
  115. #define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 14)
  116. #define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 15)
  117. #define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 16)
  118. #define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 17)
  119. #define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 18)
  120. #define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 19)
  121. #define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 20)
  122. #define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 21)
  123. #define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 22)
  124. #define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 23)
  125. #define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 24)
  126. #define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 25)
  127. #define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 26)
  128. #define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 27)
  129. #define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28)
  130. #define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29)
  131.  
  132. #define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 30)
  133. #define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 31)
  134. #define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 32)
  135. #define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 33)
  136. #define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34)
  137. #define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35)

  

linux PMBus总线及设备驱动分析的更多相关文章

  1. Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化

    我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...

  2. Linux SPI总线和设备驱动架构之三:SPI控制器驱动

    通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...

  3. Linux SPI总线和设备驱动架构之二:SPI通用接口层

    通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了 ...

  4. Linux SPI总线和设备驱动架构之一:系统概述

    SPI是"Serial Peripheral Interface" 的缩写,是一种四线制的同步串行通信接口,用来连接微控制器.传感器.存储设备,SPI设备分为主设备和从设备两种,用 ...

  5. Linux SPI总线和设备驱动架构之一:系统概述【转】

    转自:http://blog.csdn.net/droidphone/article/details/23367051/ 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 硬 ...

  6. Linux I2C核心、总线和设备驱动

    目录 更新记录 一.Linux I2C 体系结构 1.1 Linux I2C 体系结构的组成部分 1.2 内核源码文件 1.3 重要的数据结构 二.Linux I2C 核心 2.1 流程 2.2 主要 ...

  7. 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 公元1951年5月15日的国会听证上, ...

  8. Linux 串口、usb转串口驱动分析(2-2) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...

  9. Linux 串口、usb转串口驱动分析(2-1) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186851 Linux 串口.usb转 ...

随机推荐

  1. hihoCoder 1493 : 歌德巴赫猜想 素数筛法

    题意:哥德巴赫猜想认为"每一个大于2的偶数,都能表示成两个质数之和".给定一个大于2的偶数N,你能找到两个质数P和Q满足P<=Q并且P+Q=N吗?如果有多组解,输出P最小的一 ...

  2. React——共享state

    通常,一些组件需要反映相同的数据更改,这种情况推荐将共享state移动到它们最近的公共祖先上. 在这里有一个例子:有一个温度计算器计算在给定温度是否能让水沸腾,用户可以输入华氏温度也能输入摄氏温度,当 ...

  3. Nginx 调优经验记录

    1.2017年连续爆出5.x版本xshell安全问题和intel的cpu设计漏洞 ,此时我就注意到尽量少暴露自己线上使用的工具以及版本.例如:mysql版本,以及缓存层策略,服务器版本等,以下为 隐藏 ...

  4. AppCompatActivity 去掉标题栏和EditText弹出软键盘遮住输入框问题

    1. AppCompatActivity去掉标题栏 此处除掉标题栏,需要注意一点,AppCompactActivity是继承自Activity.然而,AppCompactActivity据查看网上资料 ...

  5. sed 命令多行到多行的定位方式

    本文提要: sed 命令定位方式的分类 着重对 /pattern/,/pattern/ 的定位方式进行阐述 定位方式分类 总体上,只需要分为两类,即:x 和 x,y .如果在范围后加 ! 则表示取补集 ...

  6. asp.net动态网站repeater控件使用及分页操作介绍

    asp.net动态网站repeater控件使用及分页操作介绍 1.简单介绍 Repeater 控件是一个容器控件,可用于从网页的任何可用数据中创建自定义列表.Repeater 控件没有自己内置的呈现功 ...

  7. pyinstaller打包py文件成exe文件时,出现ImportError: No module named 'pefile'错误解决办法!

    首先pyinstaller的安装与使用详见如下链接: 安装完成之后,命令行中输入pyinstaller之后,结果如下: ImportError: No module named 'pefile' 缺少 ...

  8. Android视频播放的两种方式介绍

    1.在Android 中播放视频的方式有两种: 第一种方式是使用MediaPlayer 结合SurfaceView 来播放,通过MediaPlayer来控制视频的播放.暂停.进度等: 通过Surfac ...

  9. freemarker.template.TemplateException:Error executing macro:mainSelect

    1.错误描述 freemarker.template.TemplateException:Error executing macro:mainSelect require parameter:id i ...

  10. .net core 环境安装失败,错误:0x80072EE2

    安装[DotNetCore.1.0.1-VS2015Tools.Preview2.0.3.exe]失败,提示这个界面 查看log发现,发现猫腻,然后copy下链接,用迅雷手动下载[AspNetCore ...