ChangeSet 1.1807.56.24, 2004/08/06 15:25:13-07:00, johnpol@2ka.mipt.ru [PATCH] w1: Added w1_read_block() and w1_write_block() callbacks. Added w1_read_block() and w1_write_block(). w1_therm.c now uses them. w1_therm: Chnaged snprintf to sprintf in w1_therm_read_bin() and added max_trying - number of tryings to read temperature before failng. By default it is 10. Added w1_therm_check_rom() - checks if read rom is in black list. If rom is in black list it is probably due to unsufficient of "power" in the sensor - either add strong pullup or connect it to Vcc. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman drivers/w1/w1.h | 10 ++++ drivers/w1/w1_io.c | 71 +++++++++++++++++++++++++++++------ drivers/w1/w1_io.h | 3 + drivers/w1/w1_therm.c | 101 ++++++++++++++++++++++++++++---------------------- 4 files changed, 131 insertions(+), 54 deletions(-) diff -Nru a/drivers/w1/w1.h b/drivers/w1/w1.h --- a/drivers/w1/w1.h 2004-08-23 11:04:19 -07:00 +++ b/drivers/w1/w1.h 2004-08-23 11:04:19 -07:00 @@ -73,6 +73,16 @@ u8 (*read_bit)(unsigned long); void (*write_bit)(unsigned long, u8); + + u8 (*read_byte)(unsigned long); + void (*write_byte)(unsigned long, u8); + + u8 (*read_block)(unsigned long, u8 *, int); + void (*write_block)(unsigned long, u8 *, int); + + u8 (*touch_bit)(unsigned long, u8); + + u8 (*reset_bus)(unsigned long); }; struct w1_master diff -Nru a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c --- a/drivers/w1/w1_io.c 2004-08-23 11:04:19 -07:00 +++ b/drivers/w1/w1_io.c 2004-08-23 11:04:19 -07:00 @@ -55,6 +55,14 @@ udelay(tm * w1_delay_parm); } +u8 w1_touch_bit(struct w1_master *dev, int bit) +{ + if (dev->bus_master->touch_bit) + return dev->bus_master->touch_bit(dev->bus_master->data, bit); + else + return w1_read_bit(dev); +} + void w1_write_bit(struct w1_master *dev, int bit) { if (bit) { @@ -74,8 +82,11 @@ { int i; - for (i = 0; i < 8; ++i) - w1_write_bit(dev, (byte >> i) & 0x1); + if (dev->bus_master->write_byte) + dev->bus_master->write_byte(dev->bus_master->data, byte); + else + for (i = 0; i < 8; ++i) + w1_write_bit(dev, (byte >> i) & 0x1); } u8 w1_read_bit(struct w1_master *dev) @@ -98,23 +109,59 @@ int i; u8 res = 0; - for (i = 0; i < 8; ++i) - res |= (w1_read_bit(dev) << i); + if (dev->bus_master->read_byte) + res = dev->bus_master->read_byte(dev->bus_master->data); + else + for (i = 0; i < 8; ++i) + res |= (w1_read_bit(dev) << i); return res; } +void w1_write_block(struct w1_master *dev, u8 *buf, int len) +{ + int i; + + if (dev->bus_master->write_block) + dev->bus_master->write_block(dev->bus_master->data, buf, len); + else + for (i = 0; i < len; ++i) + w1_write_8(dev, buf[i]); +} + +u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) +{ + int i; + u8 ret; + + if (dev->bus_master->read_block) + ret = dev->bus_master->read_block(dev->bus_master->data, buf, len); + else + { + for (i = 0; i < len; ++i) + buf[i] = w1_read_8(dev); + ret = len; + } + + return ret; +} + int w1_reset_bus(struct w1_master *dev) { - int result; + int result = 0; - dev->bus_master->write_bit(dev->bus_master->data, 0); - w1_delay(480); - dev->bus_master->write_bit(dev->bus_master->data, 1); - w1_delay(70); + if (dev->bus_master->reset_bus) + result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; + else + { + dev->bus_master->write_bit(dev->bus_master->data, 0); + w1_delay(480); + dev->bus_master->write_bit(dev->bus_master->data, 1); + w1_delay(70); - result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1; - w1_delay(410); + result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1; + w1_delay(410); + } return result; } @@ -136,3 +183,5 @@ EXPORT_SYMBOL(w1_reset_bus); EXPORT_SYMBOL(w1_calc_crc8); EXPORT_SYMBOL(w1_delay); +EXPORT_SYMBOL(w1_read_block); +EXPORT_SYMBOL(w1_write_block); diff -Nru a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h --- a/drivers/w1/w1_io.h 2004-08-23 11:04:19 -07:00 +++ b/drivers/w1/w1_io.h 2004-08-23 11:04:19 -07:00 @@ -25,11 +25,14 @@ #include "w1.h" void w1_delay(unsigned long); +u8 w1_touch_bit(struct w1_master *, int); void w1_write_bit(struct w1_master *, int); void w1_write_8(struct w1_master *, u8); u8 w1_read_bit(struct w1_master *); u8 w1_read_8(struct w1_master *); int w1_reset_bus(struct w1_master *); u8 w1_calc_crc8(u8 *, int); +void w1_write_block(struct w1_master *, u8 *, int); +u8 w1_read_block(struct w1_master *, u8 *, int); #endif /* __W1_IO_H */ diff -Nru a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c --- a/drivers/w1/w1_therm.c 2004-08-23 11:04:19 -07:00 +++ b/drivers/w1/w1_therm.c 2004-08-23 11:04:19 -07:00 @@ -36,6 +36,11 @@ MODULE_AUTHOR("Evgeniy Polyakov "); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); +static u8 bad_roms[][9] = { + {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, + {} + }; + static ssize_t w1_therm_read_name(struct device *, char *); static ssize_t w1_therm_read_temp(struct device *, char *); static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); @@ -69,14 +74,24 @@ return sprintf(buf, "%d\n", temp * 1000); } +static int w1_therm_check_rom(u8 rom[9]) +{ + int i; + + for (i=0; imaster; u8 rom[9], crc, verdict; - size_t icount; - int i; + int i, max_trying = 10; u16 temp; atomic_inc(&sl->refcnt); @@ -89,10 +104,10 @@ count = 0; goto out; } - if (off + count > W1_SLAVE_DATA_SIZE) - count = W1_SLAVE_DATA_SIZE - off; - - icount = count; + if (off + count > W1_SLAVE_DATA_SIZE) { + count = 0; + goto out; + } memset(buf, 0, count); memset(rom, 0, sizeof(rom)); @@ -100,56 +115,56 @@ count = 0; verdict = 0; crc = 0; - if (!w1_reset_bus(dev)) { - u64 id = *(u64 *) & sl->reg_num; - int count = 0; - - w1_write_8(dev, W1_MATCH_ROM); - for (i = 0; i < 8; ++i) - w1_write_8(dev, (id >> i * 8) & 0xff); - - w1_write_8(dev, W1_CONVERT_TEMP); - - while (dev->bus_master->read_bit(dev->bus_master->data) == 0 - && count < 10) { - w1_delay(1); - count++; - } - - if (count < 10) { - if (!w1_reset_bus(dev)) { - w1_write_8(dev, W1_MATCH_ROM); - for (i = 0; i < 8; ++i) - w1_write_8(dev, - (id >> i * 8) & 0xff); - - w1_write_8(dev, W1_READ_SCRATCHPAD); - for (i = 0; i < 9; ++i) - rom[i] = w1_read_8(dev); - crc = w1_calc_crc8(rom, 8); - - if (rom[8] == crc && rom[0]) - verdict = 1; + while (max_trying--) + { + if (!w1_reset_bus (dev)) { + int count = 0; + u8 match[9] = {W1_MATCH_ROM, }; + + memcpy(&match[1], (u64 *) & sl->reg_num, 8); + + w1_write_block(dev, match, 9); + + w1_write_8(dev, W1_CONVERT_TEMP); + + if (count < 10) { + if (!w1_reset_bus(dev)) { + w1_write_block(dev, match, 9); + + w1_write_8(dev, W1_READ_SCRATCHPAD); + if ((count = w1_read_block(dev, rom, 9)) != 9) + { + dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count); + } + + crc = w1_calc_crc8(rom, 8); + + if (rom[8] == crc && rom[0]) + verdict = 1; + } } + else + dev_warn(&dev->dev, + "18S20 doesn't respond to CONVERT_TEMP.\n"); } - else - dev_warn(&dev->dev, - "18S20 doesn't respond to CONVERT_TEMP.\n"); + + if (!w1_therm_check_rom(rom)) + break; } for (i = 0; i < 9; ++i) - count += snprintf(buf + count, icount - count, "%02x ", rom[i]); - count += snprintf(buf + count, icount - count, ": crc=%02x %s\n", + count += sprintf(buf + count, "%02x ", rom[i]); + count += sprintf(buf + count, ": crc=%02x %s\n", crc, (verdict) ? "YES" : "NO"); if (verdict) memcpy(sl->rom, rom, sizeof(sl->rom)); for (i = 0; i < 9; ++i) - count += snprintf(buf + count, icount - count, "%02x ", sl->rom[i]); + count += sprintf(buf + count, "%02x ", sl->rom[i]); temp = 0; temp <<= sl->rom[1] / 2; temp |= sl->rom[0] / 2; - count += snprintf(buf + count, icount - count, "t=%u\n", temp); + count += sprintf(buf + count, "t=%u\n", temp); out: up(&dev->mutex); out_dec: