Linux I2C(一)之常用的几种实例化(i2c_client ) 【转】

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

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

目录(?)[-]

  1. 前言
  2. 方式一
  3. 方式二
  4. 方式三
  5. 方式四
  6. 方式五
  7. 方式六

前言:

因为工作是音频驱动,所以经常涉及到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。

 

时间: 2024-10-25 03:09:58

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

Linux下挂载硬盘分区的几种方法_unix linux

Linux下挂载硬盘分区的几种方法 1.使用Autofs自动挂载分区 2.修改/etc/fstab 3.编写shell脚本,开机自动运行mount命令  方法一.使用Autofs  1.Autofs的特点:Autofs与Mount/Umount的不同之处在于,它是一种看守程序(deamon).如果它检测到用户正试图访问一个尚未挂接的文件系统,它就会自动检测该文件系 统,如果该文件系统存在,那么Autofs会自动将其挂接.另一方面,如果它检测到某个已挂接的文件系统在一段时间内没有被使用,那么Aut

Linux时间时区、常用时间函数、整形时间计算思路详解

Linux时间时区详解与常用时间函数 时间与时区 整个地球分为二十四时区,每个时区都有自己的本地时间. Ø  UTC时间 与 GMT时间 我们可以认为格林威治时间就是时间协调时间(GMT = UTC),格林威治时间和UTC时间都用秒数来计算的. Ø  UTC时间与本地时间 UTC + 时区差 = 本地时间 时区差东为正,西为负.在此,把东八区时区差记为 +0800 UTC + (+0800) = 本地(北京)时间 Ø  UTC与Unix时间戳 在计算机中看到的UTC时间都是从(1970年01月0

浅谈linux下的一些常用函数的总结(必看篇)_Linux

1.exit()函数 exit(int n)  其实就是直接退出程序, 因为默认的标准程序入口为int main(int argc, char** argv),返回值是int型的. 一般在shell下面,运行一个程序,然后使用命令echo $?就能得到该程序的返回值,也就是退出值,在main()里面,你可以用return n,也能够直接用exit(n)来做.unix默认的习惯正确退出是返回0,错误返回非0. 重点:单独的进程是返回给操作系统的.如果是多进程,是返回给父进程的. 在父进程里面调用w

网站运营:大型网站常用的五种推广方法

推广|网站运营 大型网站常用的五种推广方法   不同类型的网站,其推广方法的选择也是不同的,对于大型网站而言,那几种方法是最有效的呢?     1.搜索引擎优化:     由于大型网站的信息量非常的大,它的页面可能是上百万个页面,其每个页面都包含有相应得关键词,所以如果这些页面都能够从搜索引擎优化的角度来设计的话,将会帮助网站从搜索引擎中获得非常大的流量.比如IT.com.cn网站,目前每天能够从搜索引擎中获得几十万IP的流量.     平均而言,搜索引擎给网站带来的流量,占其新流量的75%左右

WebService最常用的两种方法

企业级应用,主要是讲PHP5对webservice的一些实现(以下的程序可以被JAVA,NET,C等正常调用) 国内用PHP写WebService的真的很少,网上资料也没多少,公司的项目开发过程中,经历了不少这方面的东西,写出来以供大家参考 客户端 代码: 01.<?php 02.header ( "Content-Type: text/html; charset=utf-8" ); 03./* 04.* 指定WebService路径并初始化一个WebService客户端 05.

PHP-WebService的最常用的两种方法

Ping Service,博客程序提供一种通知机制,以便在第一时间将博客的更新信息发布到提供Ping Service服务的网站,写聚合的时候研究了一下 Ping Service,博客程序提供一种通知机制,以便在第一时间将博客的更新信息发布到提供Ping Service服务的网站,写聚合的时候研究了一下 先看 标准 吧 这是一个标准的Ping Service,用XMLRPC来传数据的,注释写的这么详细,代码说明就不需要了吧,PHP5开启XMLRPC方法 client.php <?php $host

搜索引擎常用的三种网站排序算法

搜索引擎如何对互联网上那么多的网站进行合适的排名?想必做站长的都想知道这一点,这是通过一套非常繁琐复杂的算法计算出来的,具体的算法想必没有几个人知道,但是最常用的三种算法还是需要大家去了解一下的. 1.词频位置加权排序算法:顾名思义是说从整个网站上的文字的位置上与出现的次数进行排序,先来说一下位置,不同的网站关键词在内容里出现与在标题里面出现时差别非常大的,搜索引擎认为标题能表现出一个网站是干什么的,如果标题里面出现了关键词要远比文章里面出现关键词重要的多的多.这就是现在大家都知道一个网站的标题

常用的两种抠图技巧 如何轻松玩转PS抠图

  常用的两种抠图技巧            一.简易抠图法 简易抠图法主要是对前背景色色差较大,特别是要抠的图与周边的图色差较大,这样一般用简易法就可抠出来,简易抠图法可以通过很多种工具来实现. 工具一.魔术棒,注意魔术棒的容差,容差是魔术棒抠图的关键,在PS CS3以上的版本新增了一个魔术棒快速选择工具,对抠简易的图形非常方便. 工具二.套索工具,有时我们也会通过套索工具中的多条形套索及磁形套索工具来抠图. 工具三.色彩范围选择法,可以通过菜单栏中的[选择]→[色彩范围],根据相似颜色来进行

常用的10种CSS BUG解决方法与技巧

最常用的10种CSS BUG解决方法与技巧-浏览器兼容教程 CSS bug是布局中最头疼的问题.我们需要兼顾各种浏览器,以期待获得一致的效果. 非常遗憾的是各厂商之间的竞争导致很多问题的存在.而IE6与IE7在很多问题上也存在着很大的差别. 轻松的解决CSS bug是我们必须掌握的技能.现在整理出最常用的12种CSS BUG解决方法以及CSS BUG类的小技巧. 希望对您的学习.工作有所帮助,如果您依然有疑问, 一. 针对浏览器的选择器 这些选择器在你需要针对某款浏览器进行css设计时将非常有用