转自:http://blog.csdn.net/lugandong/article/details/48092397

版权声明:本文为博主原创文章,未经博主允许不得转载。

前言:

因为工作是音频驱动,所以经常涉及到I2C、I2S等常用的总线,想将I2C相关的东西总结一下,让自己更加了解I2C。

  • 基于:Linux3.10

方式一:

使用arch/arm/mach-s3c24xx/mach-mini2440.c举例:

static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
{
/* 遇到与”24c08一样的名称”的驱动就会与之绑定,0x50是I2C设备的地址 */
I2C_BOARD_INFO("24c08", 0x50),
.platform_data = &at24c08,
},
}; /* 这里的0代表:i2c-0总线 */
i2c_register_board_info(0, mini2440_i2c_devs,
ARRAY_SIZE(mini2440_i2c_devs));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 到这里我们可以说就完成了第一种方式的实例化。

  • 使用i2c_register_board_info去实例化必须知道我们使用的I2C设备是挂载到哪个总线上,并知道设备的地址。

  • Linux启动的时候会将信息进行收集,i2c适配器会扫描已经静态注册的i2c_board_info,通过调用i2c_register_board_info函数将包含所有I2C设备的i2c_board_info信息的i2c_devinfo变量加入到__i2c_board_list链表中,并调用i2c_new_device为其实例化一个i2c_client。在驱动加载的时候遇到同名的i2c_board_info就会将i2c_client和driver绑定,并且执行driver的probe函数。

  • 这种方式一般放在平台的代码中。

struct i2c_board_info :

/**
* struct i2c_board_info - template for device creation
* @type: chip type, to initialize i2c_client.name
* @flags: to initialize i2c_client.flags
* @addr: stored in i2c_client.addr
* @platform_data: stored in i2c_client.dev.platform_data
* @archdata: copied into i2c_client.dev.archdata
* @of_node: pointer to OpenFirmware device node
* @acpi_node: ACPI device node
* @irq: stored in i2c_client.irq
*
* I2C doesn't actually support hardware probing, although controllers and
* devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
* a device at a given address. Drivers commonly need more information than
* that, such as chip type, configuration, associated IRQ, and so on.
*
* i2c_board_info is used to build tables of information listing I2C devices
* that are present. This information is used to grow the driver model tree.
* For mainboards this is done statically using i2c_register_board_info();
* bus numbers identify adapters that aren't yet available. For add-on boards,
* i2c_new_device() does this dynamically with the adapter already known.
*/
struct i2c_board_info {
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
struct acpi_dev_node acpi_node;
int irq;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 3

i2c_register_board_info:

/**
* i2c_register_board_info - statically declare I2C devices
* @busnum: identifies the bus to which these devices belong
* @info: vector of i2c device descriptors
* @len: how many descriptors in the vector; may be zero to reserve
* the specified bus number.
*
* Systems using the Linux I2C driver stack can declare tables of board info
* while they initialize. This should be done in board-specific init code
* near arch_initcall() time, or equivalent, before any I2C adapter driver is
* registered. For example, mainboard init code could define several devices,
* as could the init code for each daughtercard in a board stack.
*
* The I2C devices will be created later, after the adapter for the relevant
* bus has been registered. After that moment, standard driver model tools
* are used to bind "new style" I2C drivers to the devices. The bus number
* for any device declared using this routine is not available for dynamic
* allocation.
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
*/
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
{
int status; down_write(&__i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */
if (busnum >= __i2c_first_dynamic_bus_num)
__i2c_first_dynamic_bus_num = busnum + 1; for (status = 0; len; len--, info++) {
struct i2c_devinfo *devinfo; devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
if (!devinfo) {
pr_debug("i2c-core: can't register boardinfo!\n");
status = -ENOMEM;
break;
} devinfo->busnum = busnum;
devinfo->board_info = *info;
list_add_tail(&devinfo->list, &__i2c_board_list);
} up_write(&__i2c_board_lock); return status;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

方式二:

使用arch/arm/mach-ux500/board-mop500-uib.c举例:

void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
unsigned n)
{
struct i2c_adapter *adap;
struct i2c_client *client;
int i;
/* 获得一个总线,当然必须知道我们设备要挂载在哪个总线上,busnum就是总线编号 */
adap = i2c_get_adapter(busnum);
if (!adap) {
pr_err("failed to get adapter i2c%d\n", busnum);
return;
} for (i = 0; i < n; i++) {
/* 将i2c_board_info所描述的器件与适配器进行关联,并实例化i2c_client */
client = i2c_new_device(adap, &info[i]);
if (!client)
pr_err("failed to register %s to i2c%d\n",
info[i].type, busnum);
}
/* 与 i2c_get_adapter对应,释放资源 */
i2c_put_adapter(adap);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 别忘了在注销驱动或者出错的情况下调用i2c_unregister_device(struct i2c_client *client)去释放资源。

  • 这种方式与方式一的差别是不需要在编译内核的时候就要知道设备挂载哪个总线上、设备的地址是什么。灵活性变强了。

方式三:

如果连i2c设备的地址不知道,我们可以提供一个地址列表供系统探测。

使用drivers/media/pci/bt8xx/bttv-input.c举例:

/* Instantiate the I2C IR receiver device, if present */
void init_bttv_i2c_ir(struct bttv *btv)
{
/* 这里就是地址列表 */
const unsigned short addr_list[] = {
0x1a, 0x18, 0x64, 0x30, 0x71,
I2C_CLIENT_END
};
struct i2c_board_info info;
struct i2c_client *i2c_dev; if (0 != btv->i2c_rc)
return;
/* 用于存放i2c_board_info信息 */
memset(&info, 0, sizeof(struct i2c_board_info));
memset(&btv->init_data, 0, sizeof(btv->init_data));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE); switch (btv->c.type) {
case BTTV_BOARD_PV951:
btv->init_data.name = "PV951";
btv->init_data.get_key = get_key_pv951;
btv->init_data.ir_codes = RC_MAP_PV951;
info.addr = 0x4b;
break;
} if (btv->init_data.name) {
info.platform_data = &btv->init_data;
i2c_dev = i2c_new_device(&btv->c.i2c_adap, &info);
} else {
/*
* The external IR receiver is at i2c address 0x34 (0x35 for
* reads). Future Hauppauge cards will have an internal
* receiver at 0x30 (0x31 for reads). In theory, both can be
* fitted, and Hauppauge suggest an external overrides an
* internal.
* That's why we probe 0x1a (~0x34) first. CB
*/
/* 这样就会在指定的总线上匹配addr_list中地址,将第一个匹配正确的地址保存到info->addr,然后使用i2c_device_new来实例化i2c_client */
i2c_dev = i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
}
if (NULL == i2c_dev)
return; #if defined(CONFIG_MODULES) && defined(MODULE)
request_module("ir-kbd-i2c");
#endif
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

i2c_new_probed_device:

struct i2c_client *i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list,
int (*probe)(struct i2c_adapter *, unsigned short addr))
{
int i; if (!probe)
probe = i2c_default_probe; for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
/* Check address validity */
if (i2c_check_addr_validity(addr_list[i]) < 0) {
dev_warn(&adap->dev, "Invalid 7-bit address "
"0x%02x\n", addr_list[i]);
continue;
} /* Check address availability */
if (i2c_check_addr_busy(adap, addr_list[i])) {
dev_dbg(&adap->dev, "Address 0x%02x already in "
"use, not probing\n", addr_list[i]);
continue;
} /* Test address responsiveness */
if (probe(adap, addr_list[i]))
break;
} if (addr_list[i] == I2C_CLIENT_END) {
dev_dbg(&adap->dev, "Probing failed, no device found\n");
return NULL;
} info->addr = addr_list[i];
return i2c_new_device(adap, info);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 3

方式四:

从用户空间着手,在/sys/bus/i2c/devices/i2c-0(i2c总线编号)下存在new_device(建立i2c_client)和delete_device(删除i2c_client)。

new_device方法:
echo [name] [addr:0x20] > /sys/bus/i2c/devices/i2c-0/new_device
delete_device方法:
echo [addr:0x20] > /sys/bus/i2c/devices/i2c-0/delete_device
  • 1
  • 2

方式五:

在dtsi中有:

/*@后面是设备的起始地址*/
&i2c-0@fe {
/* i2c_client的name = "hall-i2c" */
compatible = "qcom, hall-i2c";
reg = <fe>;
interrupts = <70>;
/* 如果设置成disabled,在初始化的时候就不会被实例化,可以在linux内置文档查看更多 */
status = "disabled";
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 其中:i2c-0中的0是总线编号,reg是设备地址,interrupts是中断号。

  • 在初始化的时候i2c总线会调用qup_i2c_probe(),接着调用of_i2c_register_devices对dtsi上所描述的设备进行实例化。并创建相应的sys文件:sys/bus/i2c/devices/0-00fe。

驱动部分代码:

/* 即使在dtsi中没有compatible 与驱动中的相对应,只要有i2c_client有与下面列表有对应的也会触发xxx_probe()函数。*/
static const struct i2c_device_id hall_id[] = {
{ "hall-i2c", 0 },
{ "lm82", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, hall_id);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 上面的lm83_id[] 列出的就是本驱动支持的i2c_client,哪一个i2c_client的名字与此处匹配就会调用xxx_probe()。具体的匹配函数是i2c_match_id。
static const struct of_device_id i2c_of_match[] = {
{
.compatible = "qcom,hall-i2c",
.data = &ppdata,
},
{ },
}; static struct platform_driver omap_i2c_driver = {
.probe = xxx_probe,
.remove = xxx_remove,
.id_table = hall_id,
.driver = {
.name = "qcom_test",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(i2c_of_match),
},
}; static int __init hall_i2c_init(void)
{
return i2c_add_driver(&omap_i2c_driver);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 在驱动加载的时候i2c_of_match与dtsi中的”qcom,hall-i2c”匹配成功就会调用xxx_probe函数。并发现/sys/bus/i2c/devices/0-00fe/subsystem/drivers/qcom_test,没错qcom_test就是我们驱动中的name。

of_i2c_register_devices:

void of_i2c_register_devices(struct i2c_adapter *adap)
{
void *result;
struct device_node *node; /* Only register child devices if the adapter has a node pointer set */
if (!adap->dev.of_node)
return; dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); for_each_available_child_of_node(adap->dev.of_node, node) {
struct i2c_board_info info = {};
struct dev_archdata dev_ad = {};
const __be32 *addr;
int len; dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
node->full_name);
continue;
} addr = of_get_property(node, "reg", &len);
if (!addr || (len < sizeof(int))) {
dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
node->full_name);
continue;
} info.addr = be32_to_cpup(addr);
if (info.addr > (1 << 10) - 1) {
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
info.addr, node->full_name);
continue;
} info.irq = irq_of_parse_and_map(node, 0);
info.of_node = of_node_get(node);
info.archdata = &dev_ad; if (of_get_property(node, "wakeup-source", NULL))
info.flags |= I2C_CLIENT_WAKE; request_module("%s%s", I2C_MODULE_PREFIX, info.type); result = i2c_new_device(adap, &info);
if (result == NULL) {
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
node->full_name);
of_node_put(node);
irq_dispose_mapping(info.irq);
continue;
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

方式六

方式三在探测到第一个可用的地址就停止探测了,且只能在一个总线上去探测。如果之前并不确定总线的编号,或者一次探测多个i2c设备,我们就可以用方式六了。

使用/drivers/hwmon/adm1026.c举例:

/* Addresses to scan ,地址列表,I2C_CLIENT_END结束标志*/
static const unsigned short normal_i2c[] = {
0x2c, 0x2d, 0x2e, I2C_CLIENT_END
}; /* 本驱动所支持的i2c_client */
static const struct i2c_device_id adm1026_id[] = {
{ "adm1026", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1026_id); static struct i2c_driver adm1026_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1026",
},
.probe = adm1026_probe,
.remove = adm1026_remove,
.id_table = adm1026_id,
/* 回调函数:用于自主检测,符合就返回0,不满足就返回-ENODEV */
.detect = adm1026_detect,
.address_list = normal_i2c,
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 2

回调函数adm1026_detect:

/* Return 0 if detection is successful, -ENODEV otherwise */
static int adm1026_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int address = client->addr;
int company, verstep; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
/* We need to be able to do byte I/O */
return -ENODEV;
}; /* Now, we do the remaining detection. */ company = adm1026_read_value(client, ADM1026_REG_COMPANY);
verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP); dev_dbg(&adapter->dev,
"Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
i2c_adapter_id(client->adapter), client->addr,
company, verstep); /* Determine the chip type. */
dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x...\n",
i2c_adapter_id(adapter), address);
if (company == ADM1026_COMPANY_ANALOG_DEV
&& verstep == ADM1026_VERSTEP_ADM1026) {
/* Analog Devices ADM1026 */
} else if (company == ADM1026_COMPANY_ANALOG_DEV
&& (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
dev_err(&adapter->dev,
"Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n",
verstep);
} else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
dev_err(&adapter->dev,
"Found version/stepping 0x%02x. Assuming generic ADM1026.\n",
verstep);
} else {
dev_dbg(&adapter->dev, "Autodetection failed\n");
/* Not an ADM1026... */
return -ENODEV;
} strlcpy(info->type, "adm1026", I2C_NAME_SIZE); return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • i2c_driver注册的时候,i2c_core会在所有已经注册的i2c_adapter上探测address_list中的所有地址,硬件探测成功之后后调用i2c_driver的detect(这里是adm1026_detect)回调函数,如果符合我们的要求那么久填充参数info(struct i2c_board_info *info),这里填充了info->type(也就是name),至于info->addr等i2c_core会自动赋值依据我们给出的address_list。接着会根据detect填充的info建立一个i2c_client。

  • 如果多个个总线上有相同的地址的设备,那么会分别建立多个个i2c_client。如果address_list中的多个地址都有设备占用,那么会建立多个i2c_client。

Linux I2C(一)之常用的几种实例化(i2c_client ) 【转】的更多相关文章

  1. Linux 操作系统常用的三种流012

    Linux 操作系统常用的三种流: 0 标准输入流 1 标准输出流 2 标准错误流 通常在写脚本启动程序,写log时候,会出现如下写法: nohup commod > log.txt 2> ...

  2. Linux I2C设备驱动编写(二)

    在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步 ...

  3. 【转】Linux I2C设备驱动编写(二)

    原文网址:http://www.cnblogs.com/biglucky/p/4059582.html 在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_drive ...

  4. linux驱动基础系列--Linux I2c驱动分析

    前言 主要是想对Linux I2c驱动框架有一个整体的把控,因此会忽略协议上的某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型.sysfs等也不进行详细说明原理,涉及到i2c协议部分也只 ...

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

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

  6. Linux+I2C总线分析(主要是probe的方式)

    Linux I2C 总线浅析 ㈠ Overview Linux的I2C体系结构分为3个组成部分: ·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法,I2C通信方法(即“algo ...

  7. Linux I2C总线设备驱动模型分析(ov7740)

    1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...

  8. linux i2c 设备节点读写

    最近需要操作24C02,封装了一下函数方便以后操作. 参考链接: https://my.oschina.net/handawei/blog/68526 http://blog.csdn.net/one ...

  9. linux i2c驱动架构-dm368 i2c驱动分析

      linux i2c驱动架构-dm368 i2c驱动分析   在阅读本文最好先熟悉一种i2c设备的驱动程序,并且浏览一下i2c-core.c以及芯片提供商的提供的i2c总线驱动(i2c-davinc ...

随机推荐

  1. delphi dbgrid 批量保存

    unit uzcdbadd; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Fo ...

  2. InnoDB,select为啥会阻塞insert?

    MySQL的InnoDB的细粒度行锁,是它最吸引人的特性之一. 但是,如<InnoDB,5项最佳实践>所述,如果查询没有命中索引,也将退化为表锁. InnoDB的细粒度锁,是实现在索引记录 ...

  3. deep learning3

    9.3.Restricted Boltzmann Machine (RBM)受限玻尔兹曼基 假设有一个二部图,每一层的节点之间没有链接,一层是可视层,即输入数据层(v),一层是隐藏层(h),如果假设所 ...

  4. nopi导出

    1.NPOI官方网站:http://npoi.codeplex.com/ 可以到此网站上去下载最新的NPOI组件版本 2.NPOI在线学习教程(中文版): http://www.cnblogs.com ...

  5. BZOJ 3040最短路

    题目描述 给定一个 NN 个点, MM 条有向边的带权图,请你计算从 SS 出发,到每个点的距离. 数据保证你能从 SS 出发到任意点. 输入输出格式 输入格式: 第一行两个整数 NN . MM ,表 ...

  6. Python高级数据类型模块collections

    collections模块提供更加高级的容器数据类型,替代Python的内置dict,list, set,和tuple  Counter对象 提供计数器,支持方便和快速的计数.返回的是一个以元素为键, ...

  7. CF25E:Test——题解

    https://vjudge.net/problem/CodeForces-25E 题目大意:给三个字符串,求最小串,使得前三个串都是它的子串. ———————————————— 这题虽然是看哈希的时 ...

  8. [Leetcode] maximun subarray 最大子数组

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  9. bzoj2330: [SCOI2011]糖果(差分约束)

    差分约束裸题,a==b的话分别建a>=b a<=b的边就行.倒序加边不然会TLE是什么鬼 #include<iostream> #include<cstring> ...

  10. [LOJ 6000]搭配飞行员

    link 其实就是一道二分图匹配板子,我们建立$S$,$T$为源点与汇点,然后分别将$S$连向所有正驾驶员,边权为$1$,然后将副驾驶员与$T$相连,边权为$1$,将数据中给出的$(a,b)$,将$a ...