diff options
| -rw-r--r-- | drivers/w1/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/w1/Makefile | 6 | ||||
| -rw-r--r-- | drivers/w1/w1_ds2433.c | 117 |
3 files changed, 125 insertions, 7 deletions
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 1d5d0872eb4d..9a1e00dd3e02 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig | |||
| @@ -61,4 +61,13 @@ config W1_DS2433 | |||
| 61 | Say Y here if you want to use a 1-wire | 61 | Say Y here if you want to use a 1-wire |
| 62 | 4kb EEPROM family device (DS2433). | 62 | 4kb EEPROM family device (DS2433). |
| 63 | 63 | ||
| 64 | config W1_DS2433_CRC | ||
| 65 | bool "Protect DS2433 data with a CRC16" | ||
| 66 | depends on W1_DS2433 | ||
| 67 | select CRC16 | ||
| 68 | help | ||
| 69 | Say Y here to protect DS2433 data with a CRC16. | ||
| 70 | Each block has 30 bytes of data and a two byte CRC16. | ||
| 71 | Full block writes are only allowed if the CRC is valid. | ||
| 72 | |||
| 64 | endmenu | 73 | endmenu |
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile index d894a9896b18..01fb54391470 100644 --- a/drivers/w1/Makefile +++ b/drivers/w1/Makefile | |||
| @@ -6,6 +6,10 @@ ifneq ($(CONFIG_NET), y) | |||
| 6 | EXTRA_CFLAGS += -DNETLINK_DISABLED | 6 | EXTRA_CFLAGS += -DNETLINK_DISABLED |
| 7 | endif | 7 | endif |
| 8 | 8 | ||
| 9 | ifeq ($(CONFIG_W1_DS2433_CRC), y) | ||
| 10 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC | ||
| 11 | endif | ||
| 12 | |||
| 9 | obj-$(CONFIG_W1) += wire.o | 13 | obj-$(CONFIG_W1) += wire.o |
| 10 | wire-objs := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o | 14 | wire-objs := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o |
| 11 | 15 | ||
| @@ -13,7 +17,7 @@ obj-$(CONFIG_W1_MATROX) += matrox_w1.o | |||
| 13 | obj-$(CONFIG_W1_THERM) += w1_therm.o | 17 | obj-$(CONFIG_W1_THERM) += w1_therm.o |
| 14 | obj-$(CONFIG_W1_SMEM) += w1_smem.o | 18 | obj-$(CONFIG_W1_SMEM) += w1_smem.o |
| 15 | 19 | ||
| 16 | obj-$(CONFIG_W1_DS9490) += ds9490r.o | 20 | obj-$(CONFIG_W1_DS9490) += ds9490r.o |
| 17 | ds9490r-objs := dscore.o | 21 | ds9490r-objs := dscore.o |
| 18 | 22 | ||
| 19 | obj-$(CONFIG_W1_DS9490_BRIDGE) += ds_w1_bridge.o | 23 | obj-$(CONFIG_W1_DS9490_BRIDGE) += ds_w1_bridge.o |
diff --git a/drivers/w1/w1_ds2433.c b/drivers/w1/w1_ds2433.c index 9ec9163a0a9b..b7c24b34d270 100644 --- a/drivers/w1/w1_ds2433.c +++ b/drivers/w1/w1_ds2433.c | |||
| @@ -3,9 +3,8 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> | 4 | * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This source code is licensed under the GNU General Public License, |
| 7 | * it under the smems of the GNU General Public License as published by | 7 | * Version 2. See the file COPYING for more details. |
| 8 | * the Free Software Foundation; version 2 of the License. | ||
| 9 | */ | 8 | */ |
| 10 | 9 | ||
| 11 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| @@ -14,6 +13,9 @@ | |||
| 14 | #include <linux/device.h> | 13 | #include <linux/device.h> |
| 15 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 16 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
| 16 | #ifdef CONFIG_W1_F23_CRC | ||
| 17 | #include <linux/crc16.h> | ||
| 18 | #endif | ||
| 17 | 19 | ||
| 18 | #include "w1.h" | 20 | #include "w1.h" |
| 19 | #include "w1_io.h" | 21 | #include "w1_io.h" |
| @@ -25,18 +27,26 @@ MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); | |||
| 25 | MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM"); | 27 | MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM"); |
| 26 | 28 | ||
| 27 | #define W1_EEPROM_SIZE 512 | 29 | #define W1_EEPROM_SIZE 512 |
| 30 | #define W1_PAGE_COUNT 16 | ||
| 28 | #define W1_PAGE_SIZE 32 | 31 | #define W1_PAGE_SIZE 32 |
| 29 | #define W1_PAGE_BITS 5 | 32 | #define W1_PAGE_BITS 5 |
| 30 | #define W1_PAGE_MASK 0x1F | 33 | #define W1_PAGE_MASK 0x1F |
| 31 | 34 | ||
| 35 | #define W1_F23_TIME 300 | ||
| 36 | |||
| 32 | #define W1_F23_READ_EEPROM 0xF0 | 37 | #define W1_F23_READ_EEPROM 0xF0 |
| 33 | #define W1_F23_WRITE_SCRATCH 0x0F | 38 | #define W1_F23_WRITE_SCRATCH 0x0F |
| 34 | #define W1_F23_READ_SCRATCH 0xAA | 39 | #define W1_F23_READ_SCRATCH 0xAA |
| 35 | #define W1_F23_COPY_SCRATCH 0x55 | 40 | #define W1_F23_COPY_SCRATCH 0x55 |
| 36 | 41 | ||
| 42 | struct w1_f23_data { | ||
| 43 | u8 memory[W1_EEPROM_SIZE]; | ||
| 44 | u32 validcrc; | ||
| 45 | }; | ||
| 46 | |||
| 37 | /** | 47 | /** |
| 38 | * Check the file size bounds and adjusts count as needed. | 48 | * Check the file size bounds and adjusts count as needed. |
| 39 | * This may not be needed if the sysfs layer checks bounds. | 49 | * This would not be needed if the file size didn't reset to 0 after a write. |
| 40 | */ | 50 | */ |
| 41 | static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size) | 51 | static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size) |
| 42 | { | 52 | { |
| @@ -49,10 +59,45 @@ static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size) | |||
| 49 | return count; | 59 | return count; |
| 50 | } | 60 | } |
| 51 | 61 | ||
| 52 | static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) | 62 | #ifdef CONFIG_W1_F23_CRC |
| 63 | static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, | ||
| 64 | int block) | ||
| 65 | { | ||
| 66 | u8 wrbuf[3]; | ||
| 67 | int off = block * W1_PAGE_SIZE; | ||
| 68 | |||
| 69 | if (data->validcrc & (1 << block)) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (w1_reset_select_slave(sl)) { | ||
| 73 | data->validcrc = 0; | ||
| 74 | return -EIO; | ||
| 75 | } | ||
| 76 | |||
| 77 | wrbuf[0] = W1_F23_READ_EEPROM; | ||
| 78 | wrbuf[1] = off & 0xff; | ||
| 79 | wrbuf[2] = off >> 8; | ||
| 80 | w1_write_block(sl->master, wrbuf, 3); | ||
| 81 | w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE); | ||
| 82 | |||
| 83 | /* cache the block if the CRC is valid */ | ||
| 84 | if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID) | ||
| 85 | data->validcrc |= (1 << block); | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | #endif /* CONFIG_W1_F23_CRC */ | ||
| 90 | |||
| 91 | static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | ||
| 92 | size_t count) | ||
| 53 | { | 93 | { |
| 54 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | 94 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
| 95 | #ifdef CONFIG_W1_F23_CRC | ||
| 96 | struct w1_f23_data *data = sl->family_data; | ||
| 97 | int i, min_page, max_page; | ||
| 98 | #else | ||
| 55 | u8 wrbuf[3]; | 99 | u8 wrbuf[3]; |
| 100 | #endif | ||
| 56 | 101 | ||
| 57 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) | 102 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) |
| 58 | return 0; | 103 | return 0; |
| @@ -63,6 +108,20 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, size | |||
| 63 | goto out_dec; | 108 | goto out_dec; |
| 64 | } | 109 | } |
| 65 | 110 | ||
| 111 | #ifdef CONFIG_W1_F23_CRC | ||
| 112 | |||
| 113 | min_page = (off >> W1_PAGE_BITS); | ||
| 114 | max_page = (off + count - 1) >> W1_PAGE_BITS; | ||
| 115 | for (i = min_page; i <= max_page; i++) { | ||
| 116 | if (w1_f23_refresh_block(sl, data, i)) { | ||
| 117 | count = -EIO; | ||
| 118 | goto out_up; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | memcpy(buf, &data->memory[off], count); | ||
| 122 | |||
| 123 | #else /* CONFIG_W1_F23_CRC */ | ||
| 124 | |||
| 66 | /* read directly from the EEPROM */ | 125 | /* read directly from the EEPROM */ |
| 67 | if (w1_reset_select_slave(sl)) { | 126 | if (w1_reset_select_slave(sl)) { |
| 68 | count = -EIO; | 127 | count = -EIO; |
| @@ -75,6 +134,8 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, size | |||
| 75 | w1_write_block(sl->master, wrbuf, 3); | 134 | w1_write_block(sl->master, wrbuf, 3); |
| 76 | w1_read_block(sl->master, buf, count); | 135 | w1_read_block(sl->master, buf, count); |
| 77 | 136 | ||
| 137 | #endif /* CONFIG_W1_F23_CRC */ | ||
| 138 | |||
| 78 | out_up: | 139 | out_up: |
| 79 | up(&sl->master->mutex); | 140 | up(&sl->master->mutex); |
| 80 | out_dec: | 141 | out_dec: |
| @@ -85,6 +146,8 @@ out_dec: | |||
| 85 | 146 | ||
| 86 | /** | 147 | /** |
| 87 | * Writes to the scratchpad and reads it back for verification. | 148 | * Writes to the scratchpad and reads it back for verification. |
| 149 | * Then copies the scratchpad to EEPROM. | ||
| 150 | * The data must be on one page. | ||
| 88 | * The master must be locked. | 151 | * The master must be locked. |
| 89 | * | 152 | * |
| 90 | * @param sl The slave structure | 153 | * @param sl The slave structure |
| @@ -148,6 +211,23 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 148 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) | 211 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) |
| 149 | return 0; | 212 | return 0; |
| 150 | 213 | ||
| 214 | #ifdef CONFIG_W1_F23_CRC | ||
| 215 | /* can only write full blocks in cached mode */ | ||
| 216 | if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) { | ||
| 217 | dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n", | ||
| 218 | (int)off, count); | ||
| 219 | return -EINVAL; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* make sure the block CRCs are valid */ | ||
| 223 | for (idx = 0; idx < count; idx += W1_PAGE_SIZE) { | ||
| 224 | if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) { | ||
| 225 | dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off); | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | #endif /* CONFIG_W1_F23_CRC */ | ||
| 230 | |||
| 151 | atomic_inc(&sl->refcnt); | 231 | atomic_inc(&sl->refcnt); |
| 152 | if (down_interruptible(&sl->master->mutex)) { | 232 | if (down_interruptible(&sl->master->mutex)) { |
| 153 | count = 0; | 233 | count = 0; |
| @@ -190,11 +270,36 @@ static struct bin_attribute w1_f23_bin_attr = { | |||
| 190 | 270 | ||
| 191 | static int w1_f23_add_slave(struct w1_slave *sl) | 271 | static int w1_f23_add_slave(struct w1_slave *sl) |
| 192 | { | 272 | { |
| 193 | return sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); | 273 | int err; |
| 274 | #ifdef CONFIG_W1_F23_CRC | ||
| 275 | struct w1_f23_data *data; | ||
| 276 | |||
| 277 | data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL); | ||
| 278 | if (!data) | ||
| 279 | return -ENOMEM; | ||
| 280 | memset(data, 0, sizeof(struct w1_f23_data)); | ||
| 281 | sl->family_data = data; | ||
| 282 | |||
| 283 | #endif /* CONFIG_W1_F23_CRC */ | ||
| 284 | |||
| 285 | err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); | ||
| 286 | |||
| 287 | #ifdef CONFIG_W1_F23_CRC | ||
| 288 | if (err) | ||
| 289 | kfree(data); | ||
| 290 | #endif /* CONFIG_W1_F23_CRC */ | ||
| 291 | |||
| 292 | return err; | ||
| 194 | } | 293 | } |
| 195 | 294 | ||
| 196 | static void w1_f23_remove_slave(struct w1_slave *sl) | 295 | static void w1_f23_remove_slave(struct w1_slave *sl) |
| 197 | { | 296 | { |
| 297 | #ifdef CONFIG_W1_F23_CRC | ||
| 298 | if (sl->family_data) { | ||
| 299 | kfree(sl->family_data); | ||
| 300 | sl->family_data = NULL; | ||
| 301 | } | ||
| 302 | #endif /* CONFIG_W1_F23_CRC */ | ||
| 198 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); | 303 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); |
| 199 | } | 304 | } |
| 200 | 305 | ||
