#include <linux/init.h>            // __init   __exit
#include <linux/module.h> // module_init module_exit
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h> #include <asm/io.h> //writel #include <mach/gpio.h>
#include <linux/leds.h>
#include <asm/string.h> #define X210_LED_OFF 1U
#define X210_LED_ON 0U struct led_classdev cdev1;
struct led_classdev cdev2;
struct led_classdev cdev3; void s5pv210_led1_set(struct led_classdev *led_cdev,enum led_brightness brightness);
void s5pv210_led2_set(struct led_classdev *led_cdev,enum led_brightness brightness);
void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness brightness); static struct gpio x210_led_gpio[] =
{
{ S5PV210_GPJ0(), GPIOF_OUT_INIT_HIGH, "LED1" }, /* default to OFF */
{ S5PV210_GPJ0(), GPIOF_OUT_INIT_HIGH, "LED2" }, /* default to OFF */
{ S5PV210_GPJ0(), GPIOF_OUT_INIT_HIGH, "LED3" } /* default to OFF */
};
void s5pv210_led1_set(struct led_classdev *led_cdev,enum led_brightness brightness)
{
printk(KERN_INFO "s5pv210_led1_set successful %d\n",brightness);
if(brightness == LED_OFF)
{
gpio_set_value(x210_led_gpio[].gpio,X210_LED_OFF);
}
else
{
gpio_set_value(x210_led_gpio[].gpio,X210_LED_ON); }
}
void s5pv210_led2_set(struct led_classdev *led_cdev,enum led_brightness brightness)
{
printk(KERN_INFO "s5pv210_led2_set successful %d\n",brightness);
if(brightness == LED_OFF)
{
gpio_set_value(x210_led_gpio[].gpio,X210_LED_OFF);
}
else
{
gpio_set_value(x210_led_gpio[].gpio,X210_LED_ON); }
}
void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness brightness)
{
printk(KERN_INFO "s5pv210_led3_set successful %d\n",brightness);
if(brightness == LED_OFF)
{
gpio_set_value(x210_led_gpio[].gpio,X210_LED_OFF);
}
else
{
gpio_set_value(x210_led_gpio[].gpio,X210_LED_ON); } }
static int __init s5pv210_led_init(void)
{
int ret = -;
printk(KERN_INFO "s5pv210_led_init successful \n");
cdev1.brightness_set = s5pv210_led1_set;
cdev1.name = "led1";
ret = led_classdev_register(NULL, &cdev1);
if (ret < )
{
printk(KERN_WARNING "led_classdev_register fail \n");
goto reg_err1;
} cdev2.brightness_set = s5pv210_led2_set;
cdev2.name = "led2";
ret = led_classdev_register(NULL, &cdev2);
if (ret < )
{
printk(KERN_WARNING "led_classdev_register fail \n");
goto reg_err2;
} cdev3.brightness_set = s5pv210_led3_set;
cdev3.name = "led3";
ret = led_classdev_register(NULL, &cdev3);
if (ret < )
{
printk(KERN_WARNING "led_classdev_register fail \n");
goto reg_err3;
}
ret = gpio_request_array(x210_led_gpio, ARRAY_SIZE(x210_led_gpio));
if (ret)
{
goto gpio_err;
} return ; gpio_err:
led_classdev_unregister(&cdev3); reg_err3:
led_classdev_unregister(&cdev2); reg_err2:
led_classdev_unregister(&cdev1); reg_err1:
return ret;
} static void __exit s5pv210_led_exit(void)
{
printk(KERN_INFO "s5pv210_led_exit successful \n");
gpio_free_array(x210_led_gpio, ARRAY_SIZE(x210_led_gpio)); led_classdev_unregister(&cdev1);
led_classdev_unregister(&cdev2);
led_classdev_unregister(&cdev3); } module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit); // MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("musk"); // 描述模块的作者
MODULE_DESCRIPTION("x210 LED driver"); // 描述模块的介绍信息
MODULE_ALIAS("led_driver"); // 描述模块的别名信息

一. 什么是gpiolib

1.1. linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;这会造成混乱。所以内核提供了一些方法来管理gpio资源;

二. gpiolib在内核中实现流程

2.1. gpiolib初始化哪里

2.1.1. smdkc110_map_io函数是gpiolib初始化的入口

a. 前面介绍虚拟地址映射时,介绍过下面的结构体在linux初始化会被调用。其中smdkc110_map_io我们值得关注。

#ifdef CONFIG_MACH_SMDKC110
MACHINE_START(SMDKC110, "SMDKC110")
#elif CONFIG_MACH_SMDKV210
MACHINE_START(SMDKV210, "SMDKV210")
#endif
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
.phys_io = S3C_PA_UART & 0xfff00000,
.io_pg_offst = (((u32)S3C_VA_UART) >> ) & 0xfffc,
.boot_params = S5P_PA_SDRAM + 0x100,
//.fixup = smdkv210_fixup,
.init_irq = s5pv210_init_irq,
.map_io = smdkc110_map_io,
.init_machine = smdkc110_machine_init,
.timer = &s5p_systimer,

b. s5pv210_gpiolib_init的调用就会初始化gpiolib

static void __init smdkc110_map_io(void)
{
s5p_init_io(NULL, , S5P_VA_CHIPID); // 静态物理地址到虚拟地址的映射初始化
s3c24xx_init_clocks(); // 系统时钟初始化
s5pv210_gpiolib_init(); // gpiolib管理器初始化
s3c24xx_init_uarts(smdkc110_uartcfgs, ARRAY_SIZE(smdkc110_uartcfgs));
s5p_reserve_bootmem(smdkc110_media_devs, ARRAY_SIZE(smdkc110_media_devs));
#ifdef CONFIG_MTD_ONENAND
s5pc110_device_onenand.name = "s5pc110-onenand";
#endif
#ifdef CONFIG_MTD_NAND
s3c_device_nand.name = "s5pv210-nand";
#endif
s5p_device_rtc.name = "smdkc110-rtc";
}

2.1.2. s5pv210_gpiolib_init函数

a. 函数中有个重要结构体函数s5pv210_gpio_4bit。这个我们后面讲

b. samsung_gpiolib_add_4bit_chips这个函数用于挂载硬件数据到内核中

__init int s5pv210_gpiolib_init(void)
{
struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; // 4bit表示的是一个gpio使用4位来配置描述 s5pv210_gpio_4bit是一个struct s3c_gpio_chip数组,是三星移植时写好的
int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); // 获取端口数量(注意一组端口和一个具体的gpio)
int i = ; for (i = ; i < nr_chips; i++, chip++) {
if (chip->config == NULL) // 如果我们的gpio端口没有 配置方法 则使用 gpio_cfg 进行默认配置
chip->config = &gpio_cfg;
if (chip->base == NULL) // 如果我们的gpio端口结构体中没有填充 基准编号 则使用下面进行填充
chip->base = S5PV210_BANK_BASE(i);
} samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); // 添加gpiolib return ;
}

2.2. 与硬件相关函数

2.2.1.  samsung_gpiolib_4bit_input&samsung_gpiolib_4bit_output函数

a. 这个函数是真正进行寄存器操作的函数,最终驱动工程师进行io设置时会间接指向该函数指针

/* The samsung_gpiolib_4bit routines are to control the gpio banks where
* the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
* following example:
*
* base + 0x00: Control register, 4 bits per gpio
* gpio n: 4 bits starting at (4*n)
* 0000 = input, 0001 = output, others mean special-function
* base + 0x04: Data register, 1 bit per gpio
* bit n: data bit n
*
* Note, since the data register is one bit per gpio and is at base + 0x4
* we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
* the output.
*/ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
unsigned int offset)
{
struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
void __iomem *base = ourchip->base;
unsigned long con; con = __raw_readl(base + GPIOCON_OFF);
con &= ~(0xf << con_4bit_shift(offset));
__raw_writel(con, base + GPIOCON_OFF); gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); return ;
}
static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
void __iomem *base = ourchip->base;
unsigned long con;
unsigned long dat; con = __raw_readl(base + GPIOCON_OFF);
con &= ~(0xf << con_4bit_shift(offset));
con |= 0x1 << con_4bit_shift(offset); dat = __raw_readl(base + GPIODAT_OFF); if (value)
dat |= << offset;
else
dat &= ~( << offset); __raw_writel(dat, base + GPIODAT_OFF);
__raw_writel(con, base + GPIOCON_OFF);
__raw_writel(dat, base + GPIODAT_OFF); gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); return ;
}

 2.2.2. gpio_get_value & gpio_set_value

a. 这两个红替代gpio的读取和设置函数。一般函数前加"_"或"__"是给内核调用的,这里使用宏定义就很好的避免了驱动开发调用内核调用的函数

b. 这个函数也是真正进行寄存器操作的函数,最终驱动工程师进行io读写时也会间接指向该函数指针

#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value /**
* __gpio_get_value() - return a gpio's value
* @gpio: gpio whose value will be returned
* Context: any
*
* This is used directly or indirectly to implement gpio_get_value().
* It returns the zero or nonzero value provided by the associated
* gpio_chip.get() method; or zero if no such method is provided.
*/
int __gpio_get_value(unsigned gpio)
{
struct gpio_chip *chip; chip = gpio_to_chip(gpio);
WARN_ON(extra_checks && chip->can_sleep);
return chip->get ? chip->get(chip, gpio - chip->base) : ;
} /**
* __gpio_set_value() - assign a gpio's value
* @gpio: gpio whose value will be assigned
* @value: value to assign
* Context: any
*
* This is used directly or indirectly to implement gpio_set_value().
* It invokes the associated gpio_chip.set() method.
*/
void __gpio_set_value(unsigned gpio, int value)
{
struct gpio_chip *chip; chip = gpio_to_chip(gpio);
WARN_ON(extra_checks && chip->can_sleep);
chip->set(chip, gpio - chip->base, value);
}

    2.3. gpiolib的attribute部分

2.3.1. attribute用于定义文件的属性,当我们echo 和cat时都由其决定

2.3.2. 源码中export_store&unexport_store函数与查看gpio的其他属性有关,比如查看IO电平值等。。。

2.3.3. CONFIG_GPIO_SYSFS该宏决定是否开启gpiolib的attribute部分。可以在menuconfig进行配置

[root@musk210 led3]# cd /sys/class/gpio/                                                         //shell测试结果
[root@musk210 gpio]# ls
export gpiochip164 gpiochip235 gpiochip316 gpiochip396 gpiochip56
gpiochip0 gpiochip172 gpiochip244 gpiochip325 gpiochip40 gpiochip62
gpiochip104 gpiochip181 gpiochip253 gpiochip334 gpiochip405 gpiochip71
gpiochip112 gpiochip188 gpiochip262 gpiochip343 gpiochip414 gpiochip80
gpiochip120 gpiochip197 gpiochip271 gpiochip35 gpiochip423 gpiochip89
gpiochip128 gpiochip206 gpiochip280 gpiochip351 gpiochip431 gpiochip9
gpiochip137 gpiochip212 gpiochip289 gpiochip360 gpiochip438 gpiochip96
gpiochip14 gpiochip221 gpiochip29 gpiochip369 gpiochip447 unexport
gpiochip146 gpiochip226 gpiochip298 gpiochip378 gpiochip456
gpiochip155 gpiochip23 gpiochip307 gpiochip387 gpiochip47
[root@musk210 gpio]# cd gpiochip0
[root@musk210 gpiochip0]# ls
base label ngpio power subsystem uevent
[root@musk210 gpiochip0]# cat base [root@musk210 gpiochip0]# echo > base
-sh: can't create base: Permission denied
[root@musk210 gpiochip0]# // shell测试 end /*
* /sys/class/gpio/gpiochipN/
* /base ... matching gpio_chip.base (N)
* /label ... matching gpio_chip.label
* /ngpio ... matching gpio_chip.ngpio
*/ static ssize_t chip_base_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev); return sprintf(buf, "%d\n", chip->base);
}
static DEVICE_ATTR(base, , chip_base_show, NULL); static ssize_t chip_label_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev); return sprintf(buf, "%s\n", chip->label ? : "");
}
static DEVICE_ATTR(label, , chip_label_show, NULL); static ssize_t chip_ngpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev); return sprintf(buf, "%u\n", chip->ngpio);
}
static DEVICE_ATTR(ngpio, , chip_ngpio_show, NULL); static const struct attribute *gpiochip_attrs[] = {
&dev_attr_base.attr,
&dev_attr_label.attr,
&dev_attr_ngpio.attr,
NULL,
}; static const struct attribute_group gpiochip_attr_group = {
.attrs = (struct attribute **) gpiochip_attrs,
};

2.4. linux中查看gpio使用情况

2.4.1. 使用方法:mount -t debugfs debugfs /tmp,然后cat /tmp/gpio即可得到gpio的所有信息

2.4.2. 使用完后umount /tmp卸载掉debugfs

三. struct s3c_gpio_chip s5pv210_gpio_4bit[]

3.1. 这个结构体数据就是三星SOC厂商编写的code,把SOC是所有的port,虚拟地址,操作function和内核挂接起来

3.1.1. 这里讲解下*base与base

a. struct s3c_gpio_chip结构体下的*base是每个port起始虚拟地址

b. struct gpio_chip结构体下的base可以理解为每个port下具体IO的编号。这个编号从小到大排列,可以是不连续单必须唯一,这样可以定位到每个IO口上

/**
* struct s3c_gpio_chip - wrapper for specific implementation of gpio
* @chip: The chip structure to be exported via gpiolib.
* @base: The base pointer to the gpio configuration registers.
* @config: special function and pull-resistor control information.
* @lock: Lock for exclusive access to this gpio bank.
* @pm_save: Save information for suspend/resume support.
*
* This wrapper provides the necessary information for the Samsung
* specific gpios being registered with gpiolib.
*
* The lock protects each gpio bank from multiple access of the shared
* configuration registers, or from reading of data whilst another thread
* is writing to the register set.
*
* Each chip has its own lock to avoid any contention between different
* CPU cores trying to get one lock for different GPIO banks, where each
* bank of GPIO has its own register space and configuration registers.
*/
struct s3c_gpio_chip {
struct gpio_chip chip;
struct s3c_gpio_cfg *config;
struct s3c_gpio_pm *pm;
void __iomem *base;
int eint_offset;
spinlock_t lock;
#ifdef CONFIG_PM
u32 pm_save[];
#endif
}; /**
* struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics
* @dev: optional device providing the GPIOs
* @owner: helps prevent removal of modules exporting active GPIOs
* @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep
* @direction_input: configures signal "offset" as input, or returns error
* @get: returns value for signal "offset"; for output signals this
* returns either the value actually sensed, or zero
* @direction_output: configures signal "offset" as output, or returns error
* @set: assigns output value for signal "offset"
* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
* implementation may not sleep
* @dbg_show: optional routine to show contents in debugfs; default code
* will be used when this is omitted, but custom code can show extra
* state (such as pullup/pulldown configuration).
* @base: identifies the first GPIO number handled by this chip; or, if
* negative during registration, requests dynamic ID allocation.
* @ngpio: the number of GPIOs handled by this controller; the last GPIO
* handled is (base + ngpio - 1).
* @can_sleep: flag must be set iff get()/set() methods sleep, as they
* must while accessing GPIO expander chips over I2C or SPI
* @names: if set, must be an array of strings to use as alternative
* names for the GPIOs in this chip. Any entry in the array
* may be NULL if there is no alias for the GPIO, however the
* array must be @ngpio entries long. A name can include a single printk
* format specifier for an unsigned int. It is substituted by the actual
* number of the gpio.
*
* A gpio_chip can help platforms abstract various sources of GPIOs so
* they can all be accessed through a common programing interface.
* Example sources would be SOC controllers, FPGAs, multifunction
* chips, dedicated GPIO expanders, and so on.
*
* Each chip controls a number of signals, identified in method calls
* by "offset" values in the range 0..(@ngpio - 1). When those signals
* are referenced through calls like gpio_get_value(gpio), the offset
* is calculated by subtracting @base from the gpio number.
*/
struct gpio_chip {
const char *label;
struct device *dev;
struct module *owner; int (*request)(struct gpio_chip *chip,
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset); int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,
unsigned offset);
int (*direction_output)(struct gpio_chip *chip,
unsigned offset, int value);
int (*set_debounce)(struct gpio_chip *chip,
unsigned offset, unsigned debounce); void (*set)(struct gpio_chip *chip,
unsigned offset, int value); int (*to_irq)(struct gpio_chip *chip,
unsigned offset); void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip);
int base;
u16 ngpio;
const char *const *names;
unsigned can_sleep:;
unsigned exported:;
};
/*
* Following are the gpio banks in v210.
*
* The 'config' member when left to NULL, is initialized to the default
* structure gpio_cfg in the init function below.
*
* The 'base' member is also initialized in the init function below.
* Note: The initialization of 'base' member of s3c_gpio_chip structure
* uses the above macro and depends on the banks being listed in order here.
*/
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
{
.chip = {
.base = S5PV210_GPA0(),
.ngpio = S5PV210_GPIO_A0_NR,
.label = "GPA0",
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
}, {
.chip = {
.base = S5PV210_GPA1(),
.ngpio = S5PV210_GPIO_A1_NR,
.label = "GPA1",
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
}, {
.chip = {
.base = S5PV210_GPB(),
.ngpio = S5PV210_GPIO_B_NR,
.label = "GPB",
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
}, {
.chip = {
.base = S5PV210_GPC0(),
.ngpio = S5PV210_GPIO_C0_NR,
.label = "GPC0",
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
}, {......

四. gpiolib使用方法

4.1. 相关函数gpio_request/gpio_request_one&gpio_free

4.1.1. gpio_request:驱动中要想使用某一个gpio,就必须先调用gpio_request接口来向内核的gpiolib部分申请,得到允许后才可以去使用这个gpio

4.1.2. gpio_request_one:与gpio_request相似,只是在调用该函数同时多了一个设置参数,不同点具体查看内核源码。

4.1.3. gpio_free:对应gpio_request,用来释放申请后用完了的gpio

4.3. 相关函数gpio_request_array&gpio_free_array

4.3.1. gpio_request_array:申请一组gpio。

4.3.2. gpio_free_array:释放一组gpio

4.3. 相关函数gpiochip_is_requested

4.3.1. gpiochip_is_requested:接口用来判断某一个gpio是否已经被申请了

4.4.相关文件目录

目录和文件结构:

mach-s5pv210/gpiolib.c s5pv210_gpiolib_init

mach-s5pv210/include/mach/gpio.h#define S5PV210_GPA0(_nr)(S5PV210_GPIO_A0_START + (_nr))

arch/arm/plat-samsung/gpiolib.c里面是210/6410这种4bit CON寄存器类型的操作方法

arch/arm/plat-samsung/gpio.c里面是24XX这种2bit CON寄存器类型的操作方法

drivers/gpio/gpiolib.c里面是内核开发者提供的gpiolib的驱动框架部分

五. 最终调试效果

[root@musk210 gpio]# cd /sys/class/leds/
[root@musk210 leds]# ls
led1 led2 led3 mmc0:: mmc1:: mmc2:: mmc3::
[root@musk210 leds]# cd led1
[root@musk210 led1]# echo > brightness
[ 8056.785758] s5pv210_led1_set successful
[root@musk210 led1]# echo > brightness
[ 8064.545061] s5pv210_led1_set successful
[root@musk210 led1]#

参考《朱老师.课件_5.4.驱动框架入门之LED》

索引文献:https://blog.csdn.net/ultraman_hs/article/details/54952253

索引文献:http://www.cnblogs.com/deng-tao/p/6366905.html

linux内核的gpiolib详解的更多相关文章

  1. Linux内核异常处理体系结构详解(一)【转】

    转自:http://www.techbulo.com/1841.html 2015年11月30日 ⁄ 基础知识 ⁄ 共 6653字 ⁄ 字号 小 中 大 ⁄ Linux内核异常处理体系结构详解(一)已 ...

  2. [转]Linux内核源码详解--iostat

    Linux内核源码详解——命令篇之iostat 转自:http://www.cnblogs.com/york-hust/p/4846497.html 本文主要分析了Linux的iostat命令的源码, ...

  3. Linux内核ROP姿势详解(二)

    /* 很棒的文章,在freebuf上发现了这篇文章上部分的翻译,但作者貌似弃坑了,顺手把下半部分也翻译了,原文见文尾链接 --by JDchen */ 介绍 在文章第一部分,我们演示了如何找到有用的R ...

  4. linux 内核 RCU机制详解

    RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制读取数 ...

  5. linux内核IDR机制详解【转】

    这几天在看Linux内核的IPC命名空间时候看到关于IDR的一些管理性质的东西,刚开始看有些迷茫,深入看下去豁然开朗的感觉,把一些心得输出共勉. 我们来看一下什么是IDR?IDR的作用是什么呢? 先来 ...

  6. linux内核 RCU机制详解【转】

    本文转载自:https://blog.csdn.net/xabc3000/article/details/15335131 简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前 ...

  7. linux内核调优详解

    cat > /etc/sysctl.conf << EOF net.ipv4.ip_forward = net.ipv4.conf.all.rp_filter = net.ipv4. ...

  8. Linux内核源码详解——命令篇之iostat[zz]

    本文主要分析了Linux的iostat命令的源码,iostat的主要功能见博客:性能测试进阶指南——基础篇之磁盘IO iostat源码共563行,应该算是Linux系统命令代码比较少的了.源代码中主要 ...

  9. 嵌入式Linux内核I2C子系统详解

    1.1 I2C总线知识 1.1.1  I2C总线物理拓扑结构     I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成.通信原理是通过对SCL和SDA线高 ...

随机推荐

  1. Facebook再现丑闻,约100位应用程序开发人员偷看用户数据

    Facebook今天披露了另一起安全事件,承认大约100名应用程序开发人员可能不正确地访问了某些Facebook组中的用户数据,包括他们的姓名和个人资料图片. 在周二发布的博客文章中,Facebook ...

  2. 【bzoj4551】【NOIP2016模拟7.11】树

    题目 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标 ...

  3. NOIP模拟赛(by hzwer) T3 小奇回地球

    [题目背景] 开学了,小奇在回地球的路上,遇到了一个棘手的问题. [问题描述] 简单来说,它要从标号为 1 的星球到标号为 n 的星球,某一些星球之间有航线. 由于超时空隧道的存在,从一个星球到另一个 ...

  4. React Native 之FlatList 下拉刷新和上拉加载更多

    接上一篇代码: 只修改了FlatListDemo.js里面的代码 import React, {Fragment,Component} from 'react'; import { SafeAreaV ...

  5. 【JavaMail】JavaMail整合RabbitMq发送邮件案例

    前言 Linux安装RabbitMQ:https://www.cnblogs.com/jxd283465/p/11975094.html SpringBoot整合RabbitMQ:https://ww ...

  6. 有关于TreeSet的自我理解

    TreeSet是依靠TreeMap来实现的. TreeSet是一个有序集合,TreeSet中的元素将按照升序排列,缺省是按照自然排序进行排列,意味着TreeSet中的元素要实现Comparable接口 ...

  7. 使用chooseImage上传图片,不压缩,使用原图

    参考文章: https://help.aliyun.com/document_detail/92883.html

  8. postman之请求&断言

    http://www.jianshu.com/p/dd0db1b13cfc    ---参考网址 文档:https://www.v2ex.com/p/7v9TEc53 api地址:https://ww ...

  9. 在命令行运行java代码

    因为尝试将运行结果通过管道命令保存,所以尝试在命令行(不借助lde来运行java代码,结果折腾了半天) 仿照的是eclipse创建文件目录的方式 最终解决方法是: #/bin/bash root_di ...

  10. EasyUI combotree 设置节点折叠和叶子节点循环展开的BUG

    树实体 public class Combotree { public string id { get; set; } public string text { get; set; } public ...