summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/w1/Kconfig16
-rw-r--r--drivers/w1/Makefile7
-rw-r--r--drivers/w1/ds_w1_bridge.c24
-rw-r--r--drivers/w1/dscore.c161
-rw-r--r--drivers/w1/dscore.h10
-rw-r--r--drivers/w1/w1.c302
-rw-r--r--drivers/w1/w1.h22
-rw-r--r--drivers/w1/w1_ds2433.c327
-rw-r--r--drivers/w1/w1_family.c11
-rw-r--r--drivers/w1/w1_family.h7
-rw-r--r--drivers/w1/w1_int.c26
-rw-r--r--drivers/w1/w1_io.c24
-rw-r--r--drivers/w1/w1_io.h1
-rw-r--r--drivers/w1/w1_netlink.c26
-rw-r--r--drivers/w1/w1_netlink.h2
-rw-r--r--drivers/w1/w1_smem.c49
-rw-r--r--drivers/w1/w1_therm.c47
-rw-r--r--include/linux/crc16.h44
-rw-r--r--lib/Kconfig8
-rw-r--r--lib/Makefile3
-rw-r--r--lib/crc16.c67
21 files changed, 871 insertions, 313 deletions
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 711b90903e7b..9a1e00dd3e02 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -54,4 +54,20 @@ config W1_SMEM
 	  Say Y here if you want to connect 1-wire
 	  simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
 
+config W1_DS2433
+	tristate "4kb EEPROM family support (DS2433)"
+	depends on W1
+	help
+	  Say Y here if you want to use a 1-wire
+	  4kb EEPROM family device (DS2433).
+
+config W1_DS2433_CRC
+	bool "Protect DS2433 data with a CRC16"
+	depends on W1_DS2433
+	select CRC16
+	help
+	  Say Y here to protect DS2433 data with a CRC16.
+	  Each block has 30 bytes of data and a two byte CRC16.
+	  Full block writes are only allowed if the CRC is valid.
+
 endmenu
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile
index 80725c348e70..01fb54391470 100644
--- a/drivers/w1/Makefile
+++ b/drivers/w1/Makefile
@@ -6,6 +6,10 @@ ifneq ($(CONFIG_NET), y)
 EXTRA_CFLAGS	+= -DNETLINK_DISABLED
 endif
 
+ifeq ($(CONFIG_W1_DS2433_CRC), y)
+EXTRA_CFLAGS	+= -DCONFIG_W1_F23_CRC
+endif
+
 obj-$(CONFIG_W1)	+= wire.o
 wire-objs		:= w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
 
@@ -13,8 +17,9 @@ obj-$(CONFIG_W1_MATROX)		+= matrox_w1.o
 obj-$(CONFIG_W1_THERM)		+= w1_therm.o
 obj-$(CONFIG_W1_SMEM)		+= w1_smem.o
 
-obj-$(CONFIG_W1_DS9490)		+= ds9490r.o 
+obj-$(CONFIG_W1_DS9490)		+= ds9490r.o
 ds9490r-objs    := dscore.o
 
 obj-$(CONFIG_W1_DS9490_BRIDGE)	+= ds_w1_bridge.o
 
+obj-$(CONFIG_W1_DS2433)		+= w1_ds2433.o
diff --git a/drivers/w1/ds_w1_bridge.c b/drivers/w1/ds_w1_bridge.c
index 7bddd8ac7d7f..a79d16d5666f 100644
--- a/drivers/w1/ds_w1_bridge.c
+++ b/drivers/w1/ds_w1_bridge.c
@@ -1,8 +1,8 @@
 /*
- * 	ds_w1_bridge.c
+ *	ds_w1_bridge.c
  *
  * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- * 
+ *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
 #include "../w1/w1.h"
 #include "../w1/w1_int.h"
 #include "dscore.h"
-	
+
 static struct ds_device *ds_dev;
 static struct w1_bus_master *ds_bus_master;
 
@@ -120,7 +120,7 @@ static u8 ds9490r_reset(unsigned long data)
 static int __devinit ds_w1_init(void)
 {
 	int err;
-	
+
 	ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
 	if (!ds_bus_master) {
 		printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
@@ -136,14 +136,14 @@ static int __devinit ds_w1_init(void)
 
 	memset(ds_bus_master, 0, sizeof(*ds_bus_master));
 
-	ds_bus_master->data 		= (unsigned long)ds_dev;
-	ds_bus_master->touch_bit 	= &ds9490r_touch_bit;
-	ds_bus_master->read_bit 	= &ds9490r_read_bit;
-	ds_bus_master->write_bit 	= &ds9490r_write_bit;
-	ds_bus_master->read_byte 	= &ds9490r_read_byte;
-	ds_bus_master->write_byte 	= &ds9490r_write_byte;
-	ds_bus_master->read_block 	= &ds9490r_read_block;
-	ds_bus_master->write_block 	= &ds9490r_write_block;
+	ds_bus_master->data		= (unsigned long)ds_dev;
+	ds_bus_master->touch_bit	= &ds9490r_touch_bit;
+	ds_bus_master->read_bit		= &ds9490r_read_bit;
+	ds_bus_master->write_bit	= &ds9490r_write_bit;
+	ds_bus_master->read_byte	= &ds9490r_read_byte;
+	ds_bus_master->write_byte	= &ds9490r_write_byte;
+	ds_bus_master->read_block	= &ds9490r_read_block;
+	ds_bus_master->write_block	= &ds9490r_write_block;
 	ds_bus_master->reset_bus	= &ds9490r_reset;
 
 	err = w1_add_master_device(ds_bus_master);
diff --git a/drivers/w1/dscore.c b/drivers/w1/dscore.c
index eee6644d33d6..15fb250451e5 100644
--- a/drivers/w1/dscore.c
+++ b/drivers/w1/dscore.c
@@ -1,8 +1,8 @@
 /*
- * 	dscore.c
+ *	dscore.c
  *
  * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- * 
+ *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,19 +32,16 @@ static struct usb_device_id ds_id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, ds_id_table);
 
-int ds_probe(struct usb_interface *, const struct usb_device_id *);
-void ds_disconnect(struct usb_interface *);
+static int ds_probe(struct usb_interface *, const struct usb_device_id *);
+static void ds_disconnect(struct usb_interface *);
 
 int ds_touch_bit(struct ds_device *, u8, u8 *);
 int ds_read_byte(struct ds_device *, u8 *);
 int ds_read_bit(struct ds_device *, u8 *);
 int ds_write_byte(struct ds_device *, u8);
 int ds_write_bit(struct ds_device *, u8);
-int ds_start_pulse(struct ds_device *, int);
-int ds_set_speed(struct ds_device *, int);
+static int ds_start_pulse(struct ds_device *, int);
 int ds_reset(struct ds_device *, struct ds_status *);
-int ds_detect(struct ds_device *, struct ds_status *);
-int ds_stop_pulse(struct ds_device *, int);
 struct ds_device * ds_get_device(void);
 void ds_put_device(struct ds_device *);
 
@@ -79,11 +76,11 @@ void ds_put_device(struct ds_device *dev)
 static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
 {
 	int err;
-	
-	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
 			CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
 	if (err < 0) {
-		printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n", 
+		printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
 				value, index, err);
 		return err;
 	}
@@ -94,11 +91,11 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
 static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
 {
 	int err;
-	
-	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
 			MODE_CMD, 0x40, value, index, NULL, 0, 1000);
 	if (err < 0) {
-		printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n", 
+		printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
 				value, index, err);
 		return err;
 	}
@@ -109,11 +106,11 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
 static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
 {
 	int err;
-	
-	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
 			COMM_CMD, 0x40, value, index, NULL, 0, 1000);
 	if (err < 0) {
-		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n", 
+		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
 				value, index, err);
 		return err;
 	}
@@ -126,19 +123,20 @@ static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int of
 	printk("%45s: %8x\n", str, buf[off]);
 }
 
-int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, unsigned char *buf, int size)
+static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
+				 unsigned char *buf, int size)
 {
 	int count, err;
-		
+
 	memset(st, 0, sizeof(st));
-	
+
 	count = 0;
 	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
 	if (err < 0) {
 		printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
 		return err;
 	}
-	
+
 	if (count >= sizeof(*st))
 		memcpy(st, buf, sizeof(*st));
 
@@ -149,13 +147,13 @@ static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
 {
 	unsigned char buf[64];
 	int count, err = 0, i;
-	
+
 	memcpy(st, buf, sizeof(*st));
-		
+
 	count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
 	if (count < 0)
 		return err;
-	
+
 	printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
 	for (i=0; i<count; ++i)
 		printk("%02x ", buf[i]);
@@ -199,7 +197,7 @@ static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
 			return err;
 	}
 #endif
-	
+
 	return err;
 }
 
@@ -207,9 +205,9 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
 {
 	int count, err;
 	struct ds_status st;
-	
+
 	count = 0;
-	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), 
+	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
 				buf, size, &count, 1000);
 	if (err < 0) {
 		printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
@@ -234,7 +232,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
 static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
 {
 	int count, err;
-	
+
 	count = 0;
 	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
 	if (err < 0) {
@@ -245,12 +243,14 @@ static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
 	return err;
 }
 
+#if 0
+
 int ds_stop_pulse(struct ds_device *dev, int limit)
 {
 	struct ds_status st;
 	int count = 0, err = 0;
 	u8 buf[0x20];
-	
+
 	do {
 		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
 		if (err)
@@ -275,7 +275,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
 int ds_detect(struct ds_device *dev, struct ds_status *st)
 {
 	int err;
-	
+
 	err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
 	if (err)
 		return err;
@@ -283,11 +283,11 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
 	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
 	if (err)
 		return err;
-	
+
 	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
 	if (err)
 		return err;
-	
+
 	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
 	if (err)
 		return err;
@@ -297,7 +297,9 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
 	return err;
 }
 
-int ds_wait_status(struct ds_device *dev, struct ds_status *st)
+#endif  /*  0  */
+
+static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
 {
 	u8 buf[0x20];
 	int err, count = 0;
@@ -305,7 +307,7 @@ int ds_wait_status(struct ds_device *dev, struct ds_status *st)
 	do {
 		err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
 #if 0
-		if (err >= 0) {	
+		if (err >= 0) {
 			int i;
 			printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
 			for (i=0; i<err; ++i)
@@ -319,10 +321,8 @@ int ds_wait_status(struct ds_device *dev, struct ds_status *st)
 	if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
 		ds_recv_status(dev, st);
 		return -1;
-	}
-	else {
+	} else
 		return 0;
-	}
 }
 
 int ds_reset(struct ds_device *dev, struct ds_status *st)
@@ -345,6 +345,7 @@ int ds_reset(struct ds_device *dev, struct ds_status *st)
 	return 0;
 }
 
+#if 0
 int ds_set_speed(struct ds_device *dev, int speed)
 {
 	int err;
@@ -356,20 +357,21 @@ int ds_set_speed(struct ds_device *dev, int speed)
 		speed = SPEED_FLEXIBLE;
 
 	speed &= 0xff;
-	
+
 	err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
 	if (err)
 		return err;
 
 	return err;
 }
+#endif  /*  0  */
 
-int ds_start_pulse(struct ds_device *dev, int delay)
+static int ds_start_pulse(struct ds_device *dev, int delay)
 {
 	int err;
 	u8 del = 1 + (u8)(delay >> 4);
 	struct ds_status st;
-	
+
 #if 0
 	err = ds_stop_pulse(dev, 10);
 	if (err)
@@ -390,7 +392,7 @@ int ds_start_pulse(struct ds_device *dev, int delay)
 	mdelay(delay);
 
 	ds_wait_status(dev, &st);
-	
+
 	return err;
 }
 
@@ -400,7 +402,7 @@ int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
 	struct ds_status st;
 	u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
 	u16 cmd;
-	
+
 	err = ds_send_control(dev, value, 0);
 	if (err)
 		return err;
@@ -430,7 +432,7 @@ int ds_write_bit(struct ds_device *dev, u8 bit)
 {
 	int err;
 	struct ds_status st;
-	
+
 	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
 	if (err)
 		return err;
@@ -445,7 +447,7 @@ int ds_write_byte(struct ds_device *dev, u8 byte)
 	int err;
 	struct ds_status st;
 	u8 rbyte;
-	
+
 	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
 	if (err)
 		return err;
@@ -453,11 +455,11 @@ int ds_write_byte(struct ds_device *dev, u8 byte)
 	err = ds_wait_status(dev, &st);
 	if (err)
 		return err;
-		
+
 	err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
 	if (err < 0)
 		return err;
-	
+
 	ds_start_pulse(dev, PULLUP_PULSE_DURATION);
 
 	return !(byte == rbyte);
@@ -470,11 +472,11 @@ int ds_read_bit(struct ds_device *dev, u8 *bit)
 	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
 	if (err)
 		return err;
-	
+
 	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
 	if (err)
 		return err;
-	
+
 	err = ds_recv_data(dev, bit, sizeof(*bit));
 	if (err < 0)
 		return err;
@@ -492,7 +494,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte)
 		return err;
 
 	ds_wait_status(dev, &st);
-	
+
 	err = ds_recv_data(dev, byte, sizeof(*byte));
 	if (err < 0)
 		return err;
@@ -509,17 +511,17 @@ int ds_read_block(struct ds_device *dev, u8 *buf, int len)
 		return -E2BIG;
 
 	memset(buf, 0xFF, len);
-	
+
 	err = ds_send_data(dev, buf, len);
 	if (err < 0)
 		return err;
-	
+
 	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
 	if (err)
 		return err;
 
 	ds_wait_status(dev, &st);
-	
+
 	memset(buf, 0x00, len);
 	err = ds_recv_data(dev, buf, len);
 
@@ -530,11 +532,11 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len)
 {
 	int err;
 	struct ds_status st;
-	
+
 	err = ds_send_data(dev, buf, len);
 	if (err < 0)
 		return err;
-	
+
 	ds_wait_status(dev, &st);
 
 	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
@@ -548,10 +550,12 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len)
 		return err;
 
 	ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-	
+
 	return !(err == len);
 }
 
+#if 0
+
 int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
 {
 	int err;
@@ -559,11 +563,11 @@ int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int condi
 	struct ds_status st;
 
 	memset(buf, 0, sizeof(buf));
-	
+
 	err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
 	if (err)
 		return err;
-	
+
 	ds_wait_status(ds_dev, &st);
 
 	value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
@@ -589,7 +593,7 @@ int ds_match_access(struct ds_device *dev, u64 init)
 	err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
 	if (err)
 		return err;
-	
+
 	ds_wait_status(dev, &st);
 
 	err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
@@ -609,11 +613,11 @@ int ds_set_path(struct ds_device *dev, u64 init)
 
 	memcpy(buf, &init, 8);
 	buf[8] = BRANCH_MAIN;
-	
+
 	err = ds_send_data(dev, buf, sizeof(buf));
 	if (err)
 		return err;
-	
+
 	ds_wait_status(dev, &st);
 
 	err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
@@ -625,7 +629,10 @@ int ds_set_path(struct ds_device *dev, u64 init)
 	return 0;
 }
 
-int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
+#endif  /*  0  */
+
+static int ds_probe(struct usb_interface *intf,
+		    const struct usb_device_id *udev_id)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_endpoint_descriptor *endpoint;
@@ -653,7 +660,7 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
 		printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
 		return err;
 	}
-	
+
 	iface_desc = &intf->altsetting[0];
 	if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
 		printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
@@ -662,37 +669,37 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
 
 	atomic_set(&ds_dev->refcnt, 0);
 	memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
-	
+
 	/*
-	 * This loop doesn'd show control 0 endpoint, 
+	 * This loop doesn'd show control 0 endpoint,
 	 * so we will fill only 1-3 endpoints entry.
 	 */
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
 
 		ds_dev->ep[i+1] = endpoint->bEndpointAddress;
-		
+
 		printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
 			i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
 			(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
 			endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
 	}
-	
+
 #if 0
 	{
 		int err, i;
 		u64 buf[3];
 		u64 init=0xb30000002078ee81ull;
 		struct ds_status st;
-		
+
 		ds_reset(ds_dev, &st);
 		err = ds_search(ds_dev, init, buf, 3, 0);
 		if (err < 0)
 			return err;
 		for (i=0; i<err; ++i)
 			printk("%d: %llx\n", i, buf[i]);
-		
-		printk("Resetting...\n");	
+
+		printk("Resetting...\n");
 		ds_reset(ds_dev, &st);
 		printk("Setting path for %llx.\n", init);
 		err = ds_set_path(ds_dev, init);
@@ -707,12 +714,12 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
 		err = ds_search(ds_dev, init, buf, 3, 0);
 
 		printk("ds_search() returned %d\n", err);
-		
+
 		if (err < 0)
 			return err;
 		for (i=0; i<err; ++i)
 			printk("%d: %llx\n", i, buf[i]);
-		
+
 		return 0;
 	}
 #endif
@@ -720,10 +727,10 @@ int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
 	return 0;
 }
 
-void ds_disconnect(struct usb_interface *intf)
+static void ds_disconnect(struct usb_interface *intf)
 {
 	struct ds_device *dev;
-	
+
 	dev = usb_get_intfdata(intf);
 	usb_set_intfdata(intf, NULL);
 
@@ -740,7 +747,7 @@ void ds_disconnect(struct usb_interface *intf)
 	ds_dev = NULL;
 }
 
-int ds_init(void)
+static int ds_init(void)
 {
 	int err;
 
@@ -753,7 +760,7 @@ int ds_init(void)
 	return 0;
 }
 
-void ds_fini(void)
+static void ds_fini(void)
 {
 	usb_deregister(&ds_driver);
 }
@@ -776,8 +783,8 @@ EXPORT_SYMBOL(ds_get_device);
 EXPORT_SYMBOL(ds_put_device);
 
 /*
- * This functions can be used for EEPROM programming, 
- * when driver will be included into mainline this will 
+ * This functions can be used for EEPROM programming,
+ * when driver will be included into mainline this will
  * require uncommenting.
  */
 #if 0
diff --git a/drivers/w1/dscore.h b/drivers/w1/dscore.h
index 9c767ef4ac24..6cf5671d6ebe 100644
--- a/drivers/w1/dscore.h
+++ b/drivers/w1/dscore.h
@@ -1,8 +1,8 @@
 /*
- * 	dscore.h
+ *	dscore.h
  *
  * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- * 
+ *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -122,7 +122,7 @@
 
 struct ds_device
 {
-	struct usb_device 	*udev;
+	struct usb_device	*udev;
 	struct usb_interface	*intf;
 
 	int			ep[NUM_EP];
@@ -156,11 +156,7 @@ int ds_read_byte(struct ds_device *, u8 *);
 int ds_read_bit(struct ds_device *, u8 *);
 int ds_write_byte(struct ds_device *, u8);
 int ds_write_bit(struct ds_device *, u8);
-int ds_start_pulse(struct ds_device *, int);
-int ds_set_speed(struct ds_device *, int);
 int ds_reset(struct ds_device *, struct ds_status *);
-int ds_detect(struct ds_device *, struct ds_status *);
-int ds_stop_pulse(struct ds_device *, int);
 struct ds_device * ds_get_device(void);
 void ds_put_device(struct ds_device *);
 int ds_write_block(struct ds_device *, u8 *, int);
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 0bbf029b1ef1..1b6b74c116a9 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -45,10 +45,12 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
 MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
 
 static int w1_timeout = 10;
+static int w1_control_timeout = 1;
 int w1_max_slave_count = 10;
 int w1_max_slave_ttl = 10;
 
 module_param_named(timeout, w1_timeout, int, 0);
+module_param_named(control_timeout, w1_control_timeout, int, 0);
 module_param_named(max_slave_count, w1_max_slave_count, int, 0);
 module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
 
@@ -59,19 +61,6 @@ static pid_t control_thread;
 static int control_needs_exit;
 static DECLARE_COMPLETION(w1_control_complete);
 
-/* stuff for the default family */
-static ssize_t w1_famdefault_read_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
-	return(sprintf(buf, "%s\n", sl->name));
-}
-static struct w1_family_ops w1_default_fops = {
-	.rname = &w1_famdefault_read_name,
-};
-static struct w1_family w1_default_family = {
-	.fops = &w1_default_fops,
-};
-
 static int w1_master_match(struct device *dev, struct device_driver *drv)
 {
 	return 1;
@@ -82,73 +71,116 @@ static int w1_master_probe(struct device *dev)
 	return -ENODEV;
 }
 
-static int w1_master_remove(struct device *dev)
-{
-	return 0;
-}
-
 static void w1_master_release(struct device *dev)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 
-	complete(&md->dev_released);
+	dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name);
+
+	if (md->nls && md->nls->sk_socket)
+		sock_release(md->nls->sk_socket);
+	memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
+	kfree(md);
 }
 
 static void w1_slave_release(struct device *dev)
 {
-	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+
+	dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
+
+	while (atomic_read(&sl->refcnt)) {
+		dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
+				sl->name, atomic_read(&sl->refcnt));
+		if (msleep_interruptible(1000))
+			flush_signals(current);
+	}
+
+	w1_family_put(sl->family);
+	sl->master->slave_count--;
 
-	complete(&sl->dev_released);
+	complete(&sl->released);
 }
 
-static ssize_t w1_default_read_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "No family registered.\n");
+	struct w1_slave *sl = dev_to_w1_slave(dev);
+
+	return sprintf(buf, "%s\n", sl->name);
 }
 
-static ssize_t w1_default_read_bin(struct kobject *kobj, char *buf, loff_t off,
-		     size_t count)
+static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count)
 {
-	return sprintf(buf, "No family registered.\n");
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+
+	atomic_inc(&sl->refcnt);
+	if (off > 8) {
+		count = 0;
+	} else {
+		if (off + count > 8)
+			count = 8 - off;
+
+		memcpy(buf, (u8 *)&sl->reg_num, count);
+	}
+	atomic_dec(&sl->refcnt);
+
+	return count;
 }
 
-static struct device_attribute w1_slave_attribute =
-	__ATTR(name, S_IRUGO, w1_default_read_name, NULL);
-
-static struct bin_attribute w1_slave_bin_attribute = {
-	.attr = {
-		.name = "w1_slave",
-		.mode = S_IRUGO,
-		.owner = THIS_MODULE,
-	},
-	.size = W1_SLAVE_DATA_SIZE,
-	.read = &w1_default_read_bin,
+static struct device_attribute w1_slave_attr_name =
+	__ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
+
+static struct bin_attribute w1_slave_attr_bin_id = {
+      .attr = {
+              .name = "id",
+              .mode = S_IRUGO,
+              .owner = THIS_MODULE,
+      },
+      .size = 8,
+      .read = w1_slave_read_id,
 };
 
+/* Default family */
+static struct w1_family w1_default_family;
+
+static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
 
 static struct bus_type w1_bus_type = {
 	.name = "w1",
 	.match = w1_master_match,
+	.hotplug = w1_hotplug,
 };
 
-struct device_driver w1_driver = {
-	.name = "w1_driver",
+struct device_driver w1_master_driver = {
+	.name = "w1_master_driver",
 	.bus = &w1_bus_type,
 	.probe = w1_master_probe,
-	.remove = w1_master_remove,
 };
 
-struct device w1_device = {
+struct device w1_master_device = {
 	.parent = NULL,
 	.bus = &w1_bus_type,
 	.bus_id = "w1 bus master",
-	.driver = &w1_driver,
+	.driver = &w1_master_driver,
 	.release = &w1_master_release
 };
 
+struct device_driver w1_slave_driver = {
+	.name = "w1_slave_driver",
+	.bus = &w1_bus_type,
+};
+
+struct device w1_slave_device = {
+	.parent = NULL,
+	.bus = &w1_bus_type,
+	.bus_id = "w1 bus slave",
+	.driver = &w1_slave_driver,
+	.release = &w1_slave_release
+};
+
 static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	ssize_t count;
 
 	if (down_interruptible (&md->mutex))
@@ -165,7 +197,7 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
 						struct device_attribute *attr,
 						const char * buf, size_t count)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 
 	if (down_interruptible (&md->mutex))
 		return -EBUSY;
@@ -181,7 +213,7 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
 					       struct device_attribute *attr,
 					       char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	ssize_t count;
 
 	if (down_interruptible (&md->mutex))
@@ -196,7 +228,7 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
 
 static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	ssize_t count;
 
 	if (down_interruptible(&md->mutex))
@@ -217,7 +249,7 @@ static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct devic
 
 static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	ssize_t count;
 
 	if (down_interruptible(&md->mutex))
@@ -231,7 +263,7 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru
 
 static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	ssize_t count;
 
 	if (down_interruptible(&md->mutex))
@@ -245,7 +277,7 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi
 
 static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	ssize_t count;
 
 	if (down_interruptible(&md->mutex))
@@ -259,7 +291,7 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d
 
 static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct w1_master *md = container_of(dev, struct w1_master, dev);
+	struct w1_master *md = dev_to_w1_master(dev);
 	int c = PAGE_SIZE;
 
 	if (down_interruptible(&md->mutex))
@@ -329,12 +361,55 @@ void w1_destroy_master_attributes(struct w1_master *master)
 	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
 }
 
+#ifdef CONFIG_HOTPLUG
+static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	struct w1_master *md = NULL;
+	struct w1_slave *sl = NULL;
+	char *event_owner, *name;
+	int err, cur_index=0, cur_len=0;
+
+	if (dev->driver == &w1_master_driver) {
+		md = container_of(dev, struct w1_master, dev);
+		event_owner = "master";
+		name = md->name;
+	} else if (dev->driver == &w1_slave_driver) {
+		sl = container_of(dev, struct w1_slave, dev);
+		event_owner = "slave";
+		name = sl->name;
+	} else {
+		dev_dbg(dev, "Unknown hotplug event.\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id);
+
+	if (dev->driver != &w1_slave_driver || !sl)
+		return 0;
+
+	err = add_hotplug_env_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_FID=%02X", sl->reg_num.family);
+	if (err)
+		return err;
+
+	err = add_hotplug_env_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (u64)sl->reg_num.id);
+	if (err)
+		return err;
+
+	return 0;
+};
+#else
+static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	return 0;
+}
+#endif
+
 static int __w1_attach_slave_device(struct w1_slave *sl)
 {
 	int err;
 
 	sl->dev.parent = &sl->master->dev;
-	sl->dev.driver = sl->master->driver;
+	sl->dev.driver = &w1_slave_driver;
 	sl->dev.bus = &w1_bus_type;
 	sl->dev.release = &w1_slave_release;
 
@@ -347,8 +422,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
 		 (unsigned int) sl->reg_num.family,
 		 (unsigned long long) sl->reg_num.id);
 
-	dev_dbg(&sl->dev, "%s: registering %s.\n", __func__,
-		&sl->dev.bus_id[0]);
+	dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]);
 
 	err = device_register(&sl->dev);
 	if (err < 0) {
@@ -358,36 +432,44 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
 		return err;
 	}
 
-	memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin));
-	memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name));
-
-	sl->attr_bin.read = sl->family->fops->rbin;
-	sl->attr_name.show = sl->family->fops->rname;
+	/* Create "name" entry */
+	err = device_create_file(&sl->dev, &w1_slave_attr_name);
+	if (err < 0) {
+		dev_err(&sl->dev,
+			"sysfs file creation for [%s] failed. err=%d\n",
+			sl->dev.bus_id, err);
+		goto out_unreg;
+	}
 
-	err = device_create_file(&sl->dev, &sl->attr_name);
+	/* Create "id" entry */
+	err = sysfs_create_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
 	if (err < 0) {
 		dev_err(&sl->dev,
 			"sysfs file creation for [%s] failed. err=%d\n",
 			sl->dev.bus_id, err);
-		device_unregister(&sl->dev);
-		return err;
+		goto out_rem1;
 	}
 
-	if ( sl->attr_bin.read ) {
-		err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
-		if (err < 0) {
-			dev_err(&sl->dev,
-				"sysfs file creation for [%s] failed. err=%d\n",
-				sl->dev.bus_id, err);
-			device_remove_file(&sl->dev, &sl->attr_name);
-			device_unregister(&sl->dev);
-			return err;
-		}
+	/* if the family driver needs to initialize something... */
+	if (sl->family->fops && sl->family->fops->add_slave &&
+	    ((err = sl->family->fops->add_slave(sl)) < 0)) {
+		dev_err(&sl->dev,
+			"sysfs file creation for [%s] failed. err=%d\n",
+			sl->dev.bus_id, err);
+		goto out_rem2;
 	}
 
 	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
 
 	return 0;
+
+out_rem2:
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+out_rem1:
+	device_remove_file(&sl->dev, &w1_slave_attr_name);
+out_unreg:
+	device_unregister(&sl->dev);
+	return err;
 }
 
 static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
@@ -413,7 +495,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 
 	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
 	atomic_set(&sl->refcnt, 0);
-	init_completion(&sl->dev_released);
+	init_completion(&sl->released);
 
 	spin_lock(&w1_flock);
 	f = w1_family_registered(rn->family);
@@ -452,28 +534,23 @@ static void w1_slave_detach(struct w1_slave *sl)
 {
 	struct w1_netlink_msg msg;
 
-	dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
-
-	while (atomic_read(&sl->refcnt)) {
-		printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
-				sl->name, atomic_read(&sl->refcnt));
+	dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__, sl->name, sl);
 
-		if (msleep_interruptible(1000))
-			flush_signals(current);
-	}
-
-	if ( sl->attr_bin.read ) {
-		sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
-	}
-	device_remove_file(&sl->dev, &sl->attr_name);
-	device_unregister(&sl->dev);
-	w1_family_put(sl->family);
+	list_del(&sl->w1_slave_entry);
 
-	sl->master->slave_count--;
+	if (sl->family->fops && sl->family->fops->remove_slave)
+		sl->family->fops->remove_slave(sl);
 
 	memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
 	msg.type = W1_SLAVE_REMOVE;
 	w1_netlink_send(sl->master, &msg);
+
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+	device_remove_file(&sl->dev, &w1_slave_attr_name);
+	device_unregister(&sl->dev);
+
+	wait_for_completion(&sl->released);
+	kfree(sl);
 }
 
 static struct w1_master *w1_search_master(unsigned long data)
@@ -500,14 +577,13 @@ void w1_reconnect_slaves(struct w1_family *f)
 
 	spin_lock_bh(&w1_mlock);
 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
-		dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
+		dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
 				dev->name, f->fid);
 		set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
 	}
 	spin_unlock_bh(&w1_mlock);
 }
 
-
 static void w1_slave_found(unsigned long data, u64 rn)
 {
 	int slave_count;
@@ -646,7 +722,7 @@ static int w1_control(void *data)
 		have_to_wait = 0;
 
 		try_to_freeze();
-		msleep_interruptible(w1_timeout * 1000);
+		msleep_interruptible(w1_control_timeout * 1000);
 
 		if (signal_pending(current))
 			flush_signals(current);
@@ -679,33 +755,30 @@ static int w1_control(void *data)
 				list_del(&dev->w1_master_entry);
 				spin_unlock_bh(&w1_mlock);
 
+				down(&dev->mutex);
 				list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
-					list_del(&sl->w1_slave_entry);
-
 					w1_slave_detach(sl);
-					kfree(sl);
 				}
 				w1_destroy_master_attributes(dev);
+				up(&dev->mutex);
 				atomic_dec(&dev->refcnt);
 				continue;
 			}
 
 			if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
-				dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
+				dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
 				down(&dev->mutex);
-				list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+				list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
 					if (sl->family->fid == W1_FAMILY_DEFAULT) {
 						struct w1_reg_num rn;
-						list_del(&sl->w1_slave_entry);
-						w1_slave_detach(sl);
 
 						memcpy(&rn, &sl->reg_num, sizeof(rn));
-
-						kfree(sl);
+						w1_slave_detach(sl);
 
 						w1_attach_slave_device(dev, &rn);
 					}
 				}
+				dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name);
 				clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
 				up(&dev->mutex);
 			}
@@ -749,10 +822,7 @@ int w1_process(void *data)
 
 		list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
 			if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
-				list_del (&sl->w1_slave_entry);
-
-				w1_slave_detach (sl);
-				kfree (sl);
+				w1_slave_detach(sl);
 
 				dev->slave_count--;
 			} else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
@@ -783,7 +853,7 @@ static int w1_init(void)
 		goto err_out_exit_init;
 	}
 
-	retval = driver_register(&w1_driver);
+	retval = driver_register(&w1_master_driver);
 	if (retval) {
 		printk(KERN_ERR
 			"Failed to register master driver. err=%d.\n",
@@ -791,18 +861,29 @@ static int w1_init(void)
 		goto err_out_bus_unregister;
 	}
 
+	retval = driver_register(&w1_slave_driver);
+	if (retval) {
+		printk(KERN_ERR
+			"Failed to register master driver. err=%d.\n",
+			retval);
+		goto err_out_master_unregister;
+	}
+
 	control_thread = kernel_thread(&w1_control, NULL, 0);
 	if (control_thread < 0) {
 		printk(KERN_ERR "Failed to create control thread. err=%d\n",
 			control_thread);
 		retval = control_thread;
-		goto err_out_driver_unregister;
+		goto err_out_slave_unregister;
 	}
 
 	return 0;
 
-err_out_driver_unregister:
-	driver_unregister(&w1_driver);
+err_out_slave_unregister:
+	driver_unregister(&w1_slave_driver);
+
+err_out_master_unregister:
+	driver_unregister(&w1_master_driver);
 
 err_out_bus_unregister:
 	bus_unregister(&w1_bus_type);
@@ -821,7 +902,8 @@ static void w1_fini(void)
 	control_needs_exit = 1;
 	wait_for_completion(&w1_control_complete);
 
-	driver_unregister(&w1_driver);
+	driver_unregister(&w1_slave_driver);
+	driver_unregister(&w1_master_driver);
 	bus_unregister(&w1_bus_type);
 }
 
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 4f0a986e33e3..d8900780c3bf 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -75,11 +75,9 @@ struct w1_slave
 
 	struct w1_master	*master;
 	struct w1_family	*family;
+	void			*family_data;
 	struct device		dev;
-	struct completion	dev_released;
-
-	struct bin_attribute	attr_bin;
-	struct device_attribute	attr_name;
+	struct completion	released;
 };
 
 typedef void (* w1_slave_found_callback)(unsigned long, u64);
@@ -179,7 +177,6 @@ struct w1_master
 
 	struct device_driver	*driver;
 	struct device		dev;
-	struct completion	dev_released;
 	struct completion	dev_exited;
 
 	struct w1_bus_master	*bus_master;
@@ -191,6 +188,21 @@ struct w1_master
 int w1_create_master_attributes(struct w1_master *);
 void w1_search(struct w1_master *dev, w1_slave_found_callback cb);
 
+static inline struct w1_slave* dev_to_w1_slave(struct device *dev)
+{
+	return container_of(dev, struct w1_slave, dev);
+}
+
+static inline struct w1_slave* kobj_to_w1_slave(struct kobject *kobj)
+{
+	return dev_to_w1_slave(container_of(kobj, struct device, kobj));
+}
+
+static inline struct w1_master* dev_to_w1_master(struct device *dev)
+{
+	return container_of(dev, struct w1_master, dev);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* __W1_H */
diff --git a/drivers/w1/w1_ds2433.c b/drivers/w1/w1_ds2433.c
new file mode 100644
index 000000000000..b7c24b34d270
--- /dev/null
+++ b/drivers/w1/w1_ds2433.c
@@ -0,0 +1,327 @@
+/*
+ *	w1_ds2433.c - w1 family 23 (DS2433) driver
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#ifdef CONFIG_W1_F23_CRC
+#include <linux/crc16.h>
+#endif
+
+#include "w1.h"
+#include "w1_io.h"
+#include "w1_int.h"
+#include "w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
+
+#define W1_EEPROM_SIZE		512
+#define W1_PAGE_COUNT		16
+#define W1_PAGE_SIZE		32
+#define W1_PAGE_BITS		5
+#define W1_PAGE_MASK		0x1F
+
+#define W1_F23_TIME		300
+
+#define W1_F23_READ_EEPROM	0xF0
+#define W1_F23_WRITE_SCRATCH	0x0F
+#define W1_F23_READ_SCRATCH	0xAA
+#define W1_F23_COPY_SCRATCH	0x55
+
+struct w1_f23_data {
+	u8	memory[W1_EEPROM_SIZE];
+	u32	validcrc;
+};
+
+/**
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return (size - off);
+
+	return count;
+}
+
+#ifdef CONFIG_W1_F23_CRC
+static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
+				int block)
+{
+	u8	wrbuf[3];
+	int	off = block * W1_PAGE_SIZE;
+
+	if (data->validcrc & (1 << block))
+		return 0;
+
+	if (w1_reset_select_slave(sl)) {
+		data->validcrc = 0;
+		return -EIO;
+	}
+
+	wrbuf[0] = W1_F23_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
+
+	/* cache the block if the CRC is valid */
+	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
+		data->validcrc |= (1 << block);
+
+	return 0;
+}
+#endif	/* CONFIG_W1_F23_CRC */
+
+static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
+			       size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+#ifdef CONFIG_W1_F23_CRC
+	struct w1_f23_data *data = sl->family_data;
+	int i, min_page, max_page;
+#else
+	u8 wrbuf[3];
+#endif
+
+	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
+		return 0;
+
+	atomic_inc(&sl->refcnt);
+	if (down_interruptible(&sl->master->mutex)) {
+		count = 0;
+		goto out_dec;
+	}
+
+#ifdef CONFIG_W1_F23_CRC
+
+	min_page = (off >> W1_PAGE_BITS);
+	max_page = (off + count - 1) >> W1_PAGE_BITS;
+	for (i = min_page; i <= max_page; i++) {
+		if (w1_f23_refresh_block(sl, data, i)) {
+			count = -EIO;
+			goto out_up;
+		}
+	}
+	memcpy(buf, &data->memory[off], count);
+
+#else 	/* CONFIG_W1_F23_CRC */
+
+	/* read directly from the EEPROM */
+	if (w1_reset_select_slave(sl)) {
+		count = -EIO;
+		goto out_up;
+	}
+
+	wrbuf[0] = W1_F23_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, buf, count);
+
+#endif	/* CONFIG_W1_F23_CRC */
+
+out_up:
+	up(&sl->master->mutex);
+out_dec:
+	atomic_dec(&sl->refcnt);
+
+	return count;
+}
+
+/**
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be on one page.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+	u8 wrbuf[4];
+	u8 rdbuf[W1_PAGE_SIZE + 3];
+	u8 es = (addr + len - 1) & 0x1f;
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F23_WRITE_SCRATCH;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_write_block(sl->master, data, len);
+
+	/* Read the scratchpad and verify */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	w1_write_8(sl->master, W1_F23_READ_SCRATCH);
+	w1_read_block(sl->master, rdbuf, len + 3);
+
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
+		return -1;
+
+	/* Copy the scratchpad to EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F23_COPY_SCRATCH;
+	wrbuf[3] = es;
+	w1_write_block(sl->master, wrbuf, 4);
+
+	/* Sleep for 5 ms to wait for the write to complete */
+	msleep(5);
+
+	/* Reset the bus to wake up the EEPROM (this may not be needed) */
+	w1_reset_bus(sl->master);
+
+	return 0;
+}
+
+static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
+				size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len, idx;
+
+	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
+		return 0;
+
+#ifdef CONFIG_W1_F23_CRC
+	/* can only write full blocks in cached mode */
+	if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
+		dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n",
+			(int)off, count);
+		return -EINVAL;
+	}
+
+	/* make sure the block CRCs are valid */
+	for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
+		if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
+			dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
+			return -EINVAL;
+		}
+	}
+#endif	/* CONFIG_W1_F23_CRC */
+
+	atomic_inc(&sl->refcnt);
+	if (down_interruptible(&sl->master->mutex)) {
+		count = 0;
+		goto out_dec;
+	}
+
+	/* Can only write data to one page at a time */
+	idx = 0;
+	while (idx < count) {
+		addr = off + idx;
+		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
+		if (len > (count - idx))
+			len = count - idx;
+
+		if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
+			count = -EIO;
+			goto out_up;
+		}
+		idx += len;
+	}
+
+out_up:
+	up(&sl->master->mutex);
+out_dec:
+	atomic_dec(&sl->refcnt);
+
+	return count;
+}
+
+static struct bin_attribute w1_f23_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = W1_EEPROM_SIZE,
+	.read = w1_f23_read_bin,
+	.write = w1_f23_write_bin,
+};
+
+static int w1_f23_add_slave(struct w1_slave *sl)
+{
+	int err;
+#ifdef CONFIG_W1_F23_CRC
+	struct w1_f23_data *data;
+
+	data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	memset(data, 0, sizeof(struct w1_f23_data));
+	sl->family_data = data;
+
+#endif	/* CONFIG_W1_F23_CRC */
+
+	err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
+
+#ifdef CONFIG_W1_F23_CRC
+	if (err)
+		kfree(data);
+#endif	/* CONFIG_W1_F23_CRC */
+
+	return err;
+}
+
+static void w1_f23_remove_slave(struct w1_slave *sl)
+{
+#ifdef CONFIG_W1_F23_CRC
+	if (sl->family_data) {
+		kfree(sl->family_data);
+		sl->family_data = NULL;
+	}
+#endif	/* CONFIG_W1_F23_CRC */
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
+}
+
+static struct w1_family_ops w1_f23_fops = {
+	.add_slave      = w1_f23_add_slave,
+	.remove_slave   = w1_f23_remove_slave,
+};
+
+static struct w1_family w1_family_23 = {
+	.fid = W1_EEPROM_DS2433,
+	.fops = &w1_f23_fops,
+};
+
+static int __init w1_f23_init(void)
+{
+	return w1_register_family(&w1_family_23);
+}
+
+static void __exit w1_f23_fini(void)
+{
+	w1_unregister_family(&w1_family_23);
+}
+
+module_init(w1_f23_init);
+module_exit(w1_f23_fini);
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index 02eee57d3c0c..88c517a4c178 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -29,23 +29,12 @@ DEFINE_SPINLOCK(w1_flock);
 static LIST_HEAD(w1_families);
 extern void w1_reconnect_slaves(struct w1_family *f);
 
-static int w1_check_family(struct w1_family *f)
-{
-	if (!f->fops->rname || !f->fops->rbin)
-		return -EINVAL;
-
-	return 0;
-}
-
 int w1_register_family(struct w1_family *newf)
 {
 	struct list_head *ent, *n;
 	struct w1_family *f;
 	int ret = 0;
 
-	if (w1_check_family(newf))
-		return -EINVAL;
-
 	spin_lock(&w1_flock);
 	list_for_each_safe(ent, n, &w1_families) {
 		f = list_entry(ent, struct w1_family, family_entry);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index b26da01bbc38..2ca0489c716a 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -31,14 +31,17 @@
 #define W1_FAMILY_SMEM_81	0x81
 #define W1_THERM_DS18S20 	0x10
 #define W1_THERM_DS1822  	0x22
+#define W1_EEPROM_DS2433  	0x23
 #define W1_THERM_DS18B20 	0x28
 
 #define MAXNAMELEN		32
 
+struct w1_slave;
+
 struct w1_family_ops
 {
-	ssize_t (* rname)(struct device *, struct device_attribute *, char *);
-	ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t);
+	int  (* add_slave)(struct w1_slave *);
+	void (* remove_slave)(struct w1_slave *);
 };
 
 struct w1_family
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 498ad505fa5f..c3f67eafc7ec 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -29,9 +29,9 @@
 
 static u32 w1_ids = 1;
 
-extern struct device_driver w1_driver;
+extern struct device_driver w1_master_driver;
 extern struct bus_type w1_bus_type;
-extern struct device w1_device;
+extern struct device w1_master_device;
 extern int w1_max_slave_count;
 extern int w1_max_slave_ttl;
 extern struct list_head w1_masters;
@@ -76,7 +76,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 	INIT_LIST_HEAD(&dev->slist);
 	init_MUTEX(&dev->mutex);
 
-	init_completion(&dev->dev_released);
 	init_completion(&dev->dev_exited);
 
 	memcpy(&dev->dev, device, sizeof(struct device));
@@ -88,17 +87,14 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 
 	dev->groups = 1;
 	dev->seq = 1;
-	dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE);
-	if (!dev->nls) {
-		printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
-			NETLINK_NFLOG, dev->dev.bus_id);
-	}
+	dev_init_netlink(dev);
 
 	err = device_register(&dev->dev);
 	if (err) {
 		printk(KERN_ERR "Failed to register master device. err=%d\n", err);
-		if (dev->nls && dev->nls->sk_socket)
-			sock_release(dev->nls->sk_socket);
+
+		dev_fini_netlink(dev);
+
 		memset(dev, 0, sizeof(struct w1_master));
 		kfree(dev);
 		dev = NULL;
@@ -107,13 +103,9 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 	return dev;
 }
 
-static void w1_free_dev(struct w1_master *dev)
+void w1_free_dev(struct w1_master *dev)
 {
 	device_unregister(&dev->dev);
-	if (dev->nls && dev->nls->sk_socket)
-		sock_release(dev->nls->sk_socket);
-	memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
-	kfree(dev);
 }
 
 int w1_add_master_device(struct w1_bus_master *master)
@@ -129,7 +121,7 @@ int w1_add_master_device(struct w1_bus_master *master)
 		return(-EINVAL);
         }
 
-	dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
+	dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device);
 	if (!dev)
 		return -ENOMEM;
 
@@ -188,7 +180,7 @@ void __w1_remove_master_device(struct w1_master *dev)
 			 __func__, dev->kpid);
 
 	while (atomic_read(&dev->refcnt)) {
-		printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+		dev_dbg(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
 				dev->name, atomic_read(&dev->refcnt));
 
 		if (msleep_interruptible(1000))
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 00f032220173..e2a043354ddf 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -277,6 +277,29 @@ void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb)
 		w1_search(dev, cb);
 }
 
+/**
+ * Resets the bus and then selects the slave by sending either a skip rom
+ * or a rom match.
+ * The w1 master lock must be held.
+ *
+ * @param sl	the slave to select
+ * @return 	0=success, anything else=error
+ */
+int w1_reset_select_slave(struct w1_slave *sl)
+{
+	if (w1_reset_bus(sl->master))
+		return -1;
+
+	if (sl->master->slave_count == 1)
+		w1_write_8(sl->master, W1_SKIP_ROM);
+	else {
+		u8 match[9] = {W1_MATCH_ROM, };
+		memcpy(&match[1], (u8 *)&sl->reg_num, 8);
+		w1_write_block(sl->master, match, 9);
+	}
+	return 0;
+}
+
 EXPORT_SYMBOL(w1_touch_bit);
 EXPORT_SYMBOL(w1_write_8);
 EXPORT_SYMBOL(w1_read_8);
@@ -286,3 +309,4 @@ EXPORT_SYMBOL(w1_delay);
 EXPORT_SYMBOL(w1_read_block);
 EXPORT_SYMBOL(w1_write_block);
 EXPORT_SYMBOL(w1_search_devices);
+EXPORT_SYMBOL(w1_reset_select_slave);
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h
index af5829778aaa..232860184a29 100644
--- a/drivers/w1/w1_io.h
+++ b/drivers/w1/w1_io.h
@@ -34,5 +34,6 @@ u8 w1_calc_crc8(u8 *, int);
 void w1_write_block(struct w1_master *, const u8 *, int);
 u8 w1_read_block(struct w1_master *, u8 *, int);
 void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb);
+int w1_reset_select_slave(struct w1_slave *sl);
 
 #endif /* __W1_IO_H */
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index e7b774423dd6..328645da7972 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -57,10 +57,36 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
 nlmsg_failure:
 	return;
 }
+
+int dev_init_netlink(struct w1_master *dev)
+{
+	dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE);
+	if (!dev->nls) {
+		printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
+			NETLINK_W1, dev->dev.bus_id);
+	}
+
+	return 0;
+}
+
+void dev_fini_netlink(struct w1_master *dev)
+{
+	if (dev->nls && dev->nls->sk_socket)
+		sock_release(dev->nls->sk_socket);
+}
 #else
 #warning Netlink support is disabled. Please compile with NET support enabled.
 
 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
 {
 }
+
+int dev_init_netlink(struct w1_master *dev)
+{
+	return 0;
+}
+
+void dev_fini_netlink(struct w1_master *dev)
+{
+}
 #endif
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index 8615756946df..eb0c8b3152c8 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -52,6 +52,8 @@ struct w1_netlink_msg
 #ifdef __KERNEL__
 
 void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
+int dev_init_netlink(struct w1_master *dev);
+void dev_fini_netlink(struct w1_master *dev);
 
 #endif /* __KERNEL__ */
 #endif /* __W1_NETLINK_H */
diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c
index 70d2d469963c..e3209d0aca9b 100644
--- a/drivers/w1/w1_smem.c
+++ b/drivers/w1/w1_smem.c
@@ -36,61 +36,12 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
 MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
 
-static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *);
-static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t);
-
-static struct w1_family_ops w1_smem_fops = {
-	.rname = &w1_smem_read_name,
-	.rbin = &w1_smem_read_bin,
-};
-
-static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
-
-	return sprintf(buf, "%s\n", sl->name);
-}
-
-static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-	struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
-					   struct w1_slave, dev);
-	int i;
-
-	atomic_inc(&sl->refcnt);
-	if (down_interruptible(&sl->master->mutex)) {
-		count = 0;
-		goto out_dec;
-	}
-
-	if (off > W1_SLAVE_DATA_SIZE) {
-		count = 0;
-		goto out;
-	}
-	if (off + count > W1_SLAVE_DATA_SIZE) {
-		count = 0;
-		goto out;
-	}
-	for (i = 0; i < 8; ++i)
-		count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
-	count += sprintf(buf + count, "\n");
-
-out:
-	up(&sl->master->mutex);
-out_dec:
-	atomic_dec(&sl->refcnt);
-
-	return count;
-}
-
 static struct w1_family w1_smem_family_01 = {
 	.fid = W1_FAMILY_SMEM_01,
-	.fops = &w1_smem_fops,
 };
 
 static struct w1_family w1_smem_family_81 = {
 	.fid = W1_FAMILY_SMEM_81,
-	.fops = &w1_smem_fops,
 };
 
 static int __init w1_smem_init(void)
diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c
index 165526c9360a..4577df3cfc48 100644
--- a/drivers/w1/w1_therm.c
+++ b/drivers/w1/w1_therm.c
@@ -42,12 +42,31 @@ static u8 bad_roms[][9] = {
 				{}
 			};
 
-static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *);
 static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
 
+static struct bin_attribute w1_therm_bin_attr = {
+	.attr = {
+		.name = "w1_slave",
+		.mode = S_IRUGO,
+		.owner = THIS_MODULE,
+	},
+	.size = W1_SLAVE_DATA_SIZE,
+	.read = w1_therm_read_bin,
+};
+
+static int w1_therm_add_slave(struct w1_slave *sl)
+{
+	return sysfs_create_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+}
+
+static void w1_therm_remove_slave(struct w1_slave *sl)
+{
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+}
+
 static struct w1_family_ops w1_therm_fops = {
-	.rname = &w1_therm_read_name,
-	.rbin = &w1_therm_read_bin,
+	.add_slave	= w1_therm_add_slave,
+	.remove_slave	= w1_therm_remove_slave,
 };
 
 static struct w1_family w1_therm_family_DS18S20 = {
@@ -59,6 +78,7 @@ static struct w1_family w1_therm_family_DS18B20 = {
 	.fid = W1_THERM_DS18B20,
 	.fops = &w1_therm_fops,
 };
+
 static struct w1_family w1_therm_family_DS1822 = {
 	.fid = W1_THERM_DS1822,
 	.fops = &w1_therm_fops,
@@ -90,13 +110,6 @@ static struct w1_therm_family_converter w1_therm_families[] = {
 	},
 };
 
-static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
-
-	return sprintf(buf, "%s\n", sl->name);
-}
-
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 {
 	int t = (rom[1] << 8) | rom[0];
@@ -148,8 +161,7 @@ static int w1_therm_check_rom(u8 rom[9])
 
 static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
 {
-	struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
-					   struct w1_slave, dev);
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	struct w1_master *dev = sl->master;
 	u8 rom[9], crc, verdict;
 	int i, max_trying = 10;
@@ -178,15 +190,10 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
 	crc = 0;
 
 	while (max_trying--) {
-		if (!w1_reset_bus (dev)) {
+		if (!w1_reset_select_slave(sl)) {
 			int count = 0;
-			u8 match[9] = {W1_MATCH_ROM, };
 			unsigned int tm = 750;
 
-			memcpy(&match[1], (u64 *) & sl->reg_num, 8);
-
-			w1_write_block(dev, match, 9);
-
 			w1_write_8(dev, W1_CONVERT_TEMP);
 
 			while (tm) {
@@ -195,8 +202,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
 					flush_signals(current);
 			}
 
-			if (!w1_reset_bus (dev)) {
-				w1_write_block(dev, match, 9);
+			if (!w1_reset_select_slave(sl)) {
 
 				w1_write_8(dev, W1_READ_SCRATCHPAD);
 				if ((count = w1_read_block(dev, rom, 9)) != 9) {
@@ -207,7 +213,6 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
 
 				if (rom[8] == crc && rom[0])
 					verdict = 1;
-
 			}
 		}
 
diff --git a/include/linux/crc16.h b/include/linux/crc16.h
new file mode 100644
index 000000000000..bdedf825b04a
--- /dev/null
+++ b/include/linux/crc16.h
@@ -0,0 +1,44 @@
+/*
+ *	crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16, as used with 1-wire devices:
+ *   Width 16
+ *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
+ *   Init  0
+ *
+ * For 1-wire devices, the CRC is stored inverted, LSB-first
+ *
+ * Example buffer with the CRC attached:
+ *   31 32 33 34 35 36 37 38 39 C2 44
+ *
+ * The CRC over a buffer with the CRC attached is 0xB001.
+ * So, if (crc16(0, buf, size) == 0xB001) then the buffer is valid.
+ *
+ * Refer to "Application Note 937: Book of iButton Standards" for details.
+ * http://www.maxim-ic.com/appnotes.cfm/appnote_number/937
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <linux/types.h>
+
+#define CRC16_INIT		0
+#define CRC16_VALID		0xb001
+
+extern u16 const crc16_table[256];
+
+extern u16 crc16(u16 crc, const u8 *buffer, size_t len);
+
+static inline u16 crc16_byte(u16 crc, const u8 data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H */
+
diff --git a/lib/Kconfig b/lib/Kconfig
index e43197efeb9c..3de93357f5ab 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -12,6 +12,14 @@ config CRC_CCITT
 	  the kernel tree does. Such modules that use library CRC-CCITT
 	  functions require M here.
 
+config CRC16
+	tristate "CRC16 functions"
+	help
+	  This option is provided for the case where no in-kernel-tree
+	  modules require CRC16 functions, but a module built outside
+	  the kernel tree does. Such modules that use library CRC16
+	  functions require M here.
+
 config CRC32
 	tristate "CRC32 functions"
 	default y
diff --git a/lib/Makefile b/lib/Makefile
index 3e2bd0df23bb..d9c38ba05e7b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -23,11 +23,12 @@ lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
 obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
 
-ifneq ($(CONFIG_HAVE_DEC_LOCK),y) 
+ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
   lib-y += dec_and_lock.o
 endif
 
 obj-$(CONFIG_CRC_CCITT)	+= crc-ccitt.o
+obj-$(CONFIG_CRC16)	+= crc16.o
 obj-$(CONFIG_CRC32)	+= crc32.o
 obj-$(CONFIG_LIBCRC32C)	+= libcrc32c.o
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
diff --git a/lib/crc16.c b/lib/crc16.c
new file mode 100644
index 000000000000..011fe573c666
--- /dev/null
+++ b/lib/crc16.c
@@ -0,0 +1,67 @@
+/*
+ *      crc16.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/crc16.h>
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+u16 const crc16_table[256] = {
+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+EXPORT_SYMBOL(crc16_table);
+
+/**
+ * Compute the CRC-16 for the data buffer
+ *
+ * @param crc     previous CRC value
+ * @param buffer  data pointer
+ * @param len     number of bytes in the buffer
+ * @return        the updated CRC value
+ */
+u16 crc16(u16 crc, u8 const *buffer, size_t len)
+{
+	while (len--)
+		crc = crc16_byte(crc, *buffer++);
+	return crc;
+}
+EXPORT_SYMBOL(crc16);
+
+MODULE_DESCRIPTION("CRC16 calculations");
+MODULE_LICENSE("GPL");
+