X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fw1%2Fw1_therm.c;h=8ca23df9da7b03ff3289595eadbc6419918d05db;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=3eed829841052d490ecf95f7115f34b2280ba24c;hpb=5fc42a6ed0ec81088c37caadb45898ae6cd0ad2c;p=linux-2.6.git diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index 3eed82984..8ca23df9d 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c @@ -36,6 +36,11 @@ MODULE_LICENSE("GPL"); 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); @@ -54,19 +59,39 @@ static ssize_t w1_therm_read_name(struct device *dev, char *buf) return sprintf(buf, "%s\n", sl->name); } +static inline int w1_convert_temp(u8 rom[9]) +{ + int t, h; + + if (rom[1] == 0) + t = ((s32)rom[0] >> 1)*1000; + else + t = 1000*(-1*(s32)(0x100-rom[0]) >> 1); + + t -= 250; + h = 1000*((s32)rom[7] - (s32)rom[6]); + h /= (s32)rom[7]; + t += h; + + return t; +} + static ssize_t w1_therm_read_temp(struct device *dev, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - s16 temp; - /* - * Must be more precise. - */ - temp = 0; - temp <<= sl->rom[1] / 2; - temp |= sl->rom[0] / 2; + return sprintf(buf, "%d\n", w1_convert_temp(sl->rom)); +} + +static int w1_therm_check_rom(u8 rom[9]) +{ + int i; - return sprintf(buf, "%d\n", temp * 1000); + for (i=0; imaster; u8 rom[9], crc, verdict; - size_t icount; - int i; - u16 temp; + int i, max_trying = 10; atomic_inc(&sl->refcnt); if (down_interruptible(&sl->master->mutex)) { @@ -89,10 +112,10 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si 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 +123,61 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si 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); + while (max_trying--) { + if (!w1_reset_bus (dev)) { + int count = 0; + u8 match[9] = {W1_MATCH_ROM, }; + unsigned long tm; - w1_write_8(dev, W1_CONVERT_TEMP); + memcpy(&match[1], (u64 *) & sl->reg_num, 8); + + w1_write_block(dev, match, 9); - while (dev->bus_master->read_bit(dev->bus_master->data) == 0 - && count < 10) { - w1_delay(1); - count++; - } + w1_write_8(dev, W1_CONVERT_TEMP); - 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); + tm = jiffies + msecs_to_jiffies(750); + while(time_before(jiffies, tm)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(tm-jiffies); + if (signal_pending(current)) + flush_signals(current); + } + + if (!w1_reset_bus (dev)) { + w1_write_block(dev, match, 9); + w1_write_8(dev, W1_READ_SCRATCHPAD); - for (i = 0; i < 9; ++i) - rom[i] = w1_read_8(dev); + 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"); + + 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)); + else + dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n"); + for (i = 0; i < 9; ++i) - count += snprintf(buf + count, icount - 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, "%02x ", sl->rom[i]); + + count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom)); out: up(&dev->mutex); out_dec: