[RESEND3] Dallas 1-wire protocol implementation.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Third resend of Dallas' 1-wire protocol implementation.
Patches may be applied against 2.6.7-rc2 without problems.
Please consider for inclusion.

Thank you.

> On Fri, 14 May 2004 15:15:26 -0700
> Greg KH <greg at kroah.com> wrote:
> 
> > On Sat, May 08, 2004 at 04:47:18PM +0400, Evgeniy Polyakov wrote:
> > > This patchset is in -p1 form with minor cleanup.
> > > Please apply instead of previous.
> > 
> > Your coding style is still incorect with regards to the initial
> > placement of the { character in a number of places.  Please fix
> > this.
> 
> Grr...
> I've installed <fill yourself> indent and think that even oldmen
> Kernighan and Ritchie would like this patch :)
> 
> > Also:
> > > +ifeq ($(CONFIG_W1),y)
> > > +obj-$(CONFIG_W1)		+= w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
> > > +endif
> > > +
> > > +ifeq ($(CONFIG_W1),m)
> > > +obj-m				+= wire.o
> > > +wire-objs			:= w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
> > > +endif
> > 
> > Why the difference here?  Can't this be written as:
> > 
> > obj-$(CONFIG_W1)	+= wire.o
> > wire-objs		:= w1.o		\
> > 			   w1_int.o	\
> > 			   w1_family.o	\
> > 			   w1_netlink.o	\
> > 			   w1_io.o
> > 
> > That should do the same thing, right?
> 
> Yes it does, although the former variant doesn't generate unneded
> object in case of non-modular build, but your variant is more clear.
> 
> > thanks,
> 
> Thank you.
> 
> > greg k-h

	Evgeniy Polyakov ( s0mbre )

Only failure makes us experts. -- Theo de Raadt
-------------- next part --------------
--- linux-2.6/MAINTAINERS.orig	Tue May 25 17:13:04 2004
+++ linux-2.6/MAINTAINERS	Tue May 25 17:12:35 2004
@@ -2336,6 +2336,12 @@
 M:	kraxel at bytesex.org
 S:	Maintained
 
+W1 DALLAS'S 1-WIRE BUS
+P:	Evgeniy Polyakov
+M:	johnpol at 2ka.mipt.ru
+L:	sensors at stimpy.netroedge.com
+S:	Maintained
+
 WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
 P:	Nenad Corbic
 M:	ncorbic at sangoma.com
-------------- next part --------------
--- linux-2.6/drivers/Kconfig~	Sat Mar 13 03:39:12 2004
+++ linux-2.6/drivers/Kconfig	Sat May  8 12:05:33 2004
@@ -42,6 +42,8 @@
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/w1/Kconfig"
+
 source "drivers/misc/Kconfig"
 
 source "drivers/media/Kconfig"
-------------- next part --------------
--- linux-2.6/drivers/Makefile~	Sun Apr  4 13:20:57 2004
+++ linux-2.6/drivers/Makefile	Sat May  8 12:15:37 2004
@@ -42,6 +42,7 @@
 obj-$(CONFIG_SERIO)		+= input/serio/
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_I2C)		+= i2c/
+obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
 obj-$(CONFIG_BT)		+= bluetooth/
-------------- next part --------------
diff -Nru /tmp/w1/Kconfig linux-2.6/drivers/w1/Kconfig
--- /tmp/w1/Kconfig	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/Kconfig	Sat May  8 12:06:21 2004
@@ -0,0 +1,31 @@
+menu "Dallas's 1-wire bus"
+
+config W1
+	tristate "Dallas's 1-wire support"
+	---help---
+	  Dallas's 1-wire bus is usefull to connect slow 1-pin devices 
+	  such as iButtons and thermal sensors.
+	  
+	  If you want W1 support, you should say Y here.
+
+	  This W1 support can also be built as a module.  If so, the module
+	  will be called wire.ko.
+
+config W1_MATROX
+	tristate "Matrox G400 transport layer for 1-wire"
+	depends on W1
+	help
+	  Say Y here if you want to communicate with your 1-wire devices
+	  using Matrox's G400 GPIO pins.
+	  
+	  This support is also available as a module.  If so, the module 
+	  will be called matrox_w1.ko.
+
+config W1_THERM
+	tristate "Thermal family implementation"
+	depends on W1
+	help
+	  Say Y here if you want to connect 1-wire thermal sensors to you
+	  wire.
+
+endmenu
diff -Nru /tmp/w1/Makefile linux-2.6/drivers/w1/Makefile
--- /tmp/w1/Makefile	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/Makefile	Sat May 15 18:22:07 2004
@@ -0,0 +1,9 @@
+#
+# Makefile for the Dallas's 1-wire bus.
+#
+
+obj-$(CONFIG_W1)	+= wire.o
+wire-objs		:= w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
+
+obj-$(CONFIG_W1_MATROX)		+= matrox_w1.o
+obj-$(CONFIG_W1_THERM)		+= w1_therm.o
diff -Nru /tmp/w1/matrox_w1.c linux-2.6/drivers/w1/matrox_w1.c
--- /tmp/w1/matrox_w1.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/matrox_w1.c	Sat May 15 18:19:42 2004
@@ -0,0 +1,260 @@
+/*
+ * 	matrox_w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+
+#include "w1.h"
+#include "w1_int.h"
+#include "w1_log.h"
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>");
+MODULE_DESCRIPTION ("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
+
+static struct pci_device_id matrox_w1_tbl[] = {
+	{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+};
+MODULE_DEVICE_TABLE (pci, matrox_w1_tbl);
+
+static int __devinit matrox_w1_probe (struct pci_dev *, const struct pci_device_id *);
+static void __devexit matrox_w1_remove (struct pci_dev *);
+
+static struct pci_driver matrox_w1_pci_driver = {
+	.name = "matrox_w1",
+	.id_table = matrox_w1_tbl,
+	.probe = matrox_w1_probe,
+	.remove = __devexit_p (matrox_w1_remove),
+};
+
+/* 
+ * Matrox G400 DDC registers.
+ */
+
+#define MATROX_G400_DDC_CLK		(1<<4)
+#define MATROX_G400_DDC_DATA		(1<<1)
+
+#define MATROX_BASE			0x3C00
+#define MATROX_STATUS			0x1e14
+
+#define MATROX_PORT_INDEX_OFFSET	0x00
+#define MATROX_PORT_DATA_OFFSET		0x0A
+
+#define MATROX_GET_CONTROL		0x2A
+#define MATROX_GET_DATA			0x2B
+#define MATROX_CURSOR_CTL		0x06
+
+struct matrox_device
+{
+	unsigned long base_addr;
+	unsigned long port_index, port_data;
+	u8 data_mask;
+
+	unsigned long phys_addr, virt_addr;
+	unsigned long found;
+
+	struct w1_bus_master *bus_master;
+};
+
+static u8 matrox_w1_read_ddc_bit (unsigned long);
+static void matrox_w1_write_ddc_bit (unsigned long, u8);
+
+static __inline__ u8 mreadb (unsigned long addr)
+{
+	return readb (addr);
+}
+
+static __inline__ void mwriteb (u8 val, unsigned long addr)
+{
+	writeb (val, addr);
+}
+
+
+/*
+ * These functions read and write DDC Data bit.
+ *
+ * Using tristate pins, since i can't  fin any open-drain pin in whole motherboard.
+ * Unfortunately we can't connect to Intel's 82801xx IO controller
+ * since we don't know motherboard schema, wich has pretty unused(may be not) GPIO.
+ *
+ * I've heard that PIIX also has open drain pin.
+ *
+ * Port mapping.
+ */
+
+static __inline__ u8 matrox_w1_read_reg (struct matrox_device *dev, u8 reg)
+{
+	u8 ret;
+
+	mwriteb (reg, dev->port_index);
+	ret = mreadb (dev->port_data);
+	barrier ();
+
+	return ret;
+}
+
+static __inline__ void matrox_w1_write_reg (struct matrox_device *dev, u8 reg, u8 val)
+{
+	mwriteb (reg, dev->port_index);
+	mwriteb (val, dev->port_data);
+	wmb ();
+}
+
+static void matrox_w1_write_ddc_bit (unsigned long data, u8 bit)
+{
+	u8 ret;
+	struct matrox_device *dev = (struct matrox_device *) data;
+
+	if (bit)
+		bit = 0;
+	else
+		bit = dev->data_mask;
+
+	ret = matrox_w1_read_reg (dev, MATROX_GET_CONTROL);
+	matrox_w1_write_reg (dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
+	matrox_w1_write_reg (dev, MATROX_GET_DATA, 0x00);
+}
+
+static u8 matrox_w1_read_ddc_bit (unsigned long data)
+{
+	u8 ret;
+	struct matrox_device *dev = (struct matrox_device *) data;
+
+	ret = matrox_w1_read_reg (dev, MATROX_GET_DATA);
+
+	return ret;
+}
+
+static void matrox_w1_hw_init (struct matrox_device *dev)
+{
+	matrox_w1_write_reg (dev, MATROX_GET_DATA, 0xFF);
+	matrox_w1_write_reg (dev, MATROX_GET_CONTROL, 0x00);
+}
+
+static int __devinit matrox_w1_probe (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct matrox_device *dev;
+	int err;
+
+	assert (pdev != NULL);
+	assert (ent != NULL);
+
+	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
+		return -ENODEV;
+
+	dev = kmalloc (sizeof (struct matrox_device) +
+		       sizeof (struct w1_bus_master), GFP_KERNEL);
+	if (!dev) {
+		printk (KERN_ERR
+			"%s: Failed to create new matrox_device object.\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	memset (dev, 0, sizeof (struct matrox_device) +	sizeof (struct w1_bus_master));
+
+	dev->bus_master = (struct w1_bus_master *) (dev + 1);
+
+	/* 
+	 * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c 
+	 */
+
+	dev->phys_addr = pci_resource_start (pdev, 1);
+
+	dev->virt_addr =
+		(unsigned long) ioremap_nocache (dev->phys_addr, 16384);
+	if (!dev->virt_addr) {
+		printk (KERN_ERR "%s: failed to ioremap(0x%lx, %d).\n",
+			__func__, dev->phys_addr, 16384);
+		err = -EIO;
+		goto err_out_free_device;
+	}
+
+	dev->base_addr = dev->virt_addr + MATROX_BASE;
+	dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
+	dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
+	dev->data_mask = (MATROX_G400_DDC_DATA);
+
+	matrox_w1_hw_init (dev);
+
+	dev->bus_master->data = (unsigned long) dev;
+	dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
+	dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
+
+	err = w1_add_master_device (dev->bus_master);
+	if (err)
+		goto err_out_free_device;
+
+	pci_set_drvdata (pdev, dev);
+
+	dev->found = 1;
+
+	printk (KERN_INFO "Matrox G400 GPIO transport layer for 1-wire.\n");
+
+	return 0;
+
+err_out_free_device:
+	kfree (dev);
+
+	return err;
+}
+
+static void __devexit matrox_w1_remove (struct pci_dev *pdev)
+{
+	struct matrox_device *dev = pci_get_drvdata (pdev);
+
+	assert (dev != NULL);
+
+	if (dev->found) {
+		w1_remove_master_device (dev->bus_master);
+		iounmap ((void *) dev->virt_addr);
+	}
+	kfree (dev);
+
+}
+
+int __init matrox_w1_init (void)
+{
+	return pci_module_init (&matrox_w1_pci_driver);
+}
+
+void __exit matrox_w1_fini (void)
+{
+	pci_unregister_driver (&matrox_w1_pci_driver);
+
+	printk (KERN_INFO "matrox_w1 transport driver has been unloaded.\n");
+}
+
+module_init (matrox_w1_init);
+module_exit (matrox_w1_fini);
diff -Nru /tmp/w1/w1.c linux-2.6/drivers/w1/w1.c
--- /tmp/w1/w1.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1.c	Sat May 15 18:19:42 2004
@@ -0,0 +1,623 @@
+/*
+ * 	w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/atomic.h>
+#include <asm/delay.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+
+#include "w1.h"
+#include "w1_io.h"
+#include "w1_log.h"
+#include "w1_int.h"
+#include "w1_family.h"
+#include "w1_netlink.h"
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>");
+MODULE_DESCRIPTION ("Driver for 1-wire Dallas network protocol.");
+
+static int w1_timeout = 5 * HZ;
+int w1_max_slave_count = 10;
+
+module_param_named (timeout, w1_timeout, int, 0);
+module_param_named (max_slave_count, w1_max_slave_count, int, 0);
+
+spinlock_t mlock = SPIN_LOCK_UNLOCKED;
+LIST_HEAD (w1_masters);
+
+static pid_t control_thread;
+static int control_needs_exit;
+static DECLARE_COMPLETION (w1_control_complete);
+static DECLARE_WAIT_QUEUE_HEAD (w1_control_wait);
+
+static int w1_master_match (struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+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);
+
+	complete (&md->dev_released);
+}
+
+static void w1_slave_release (struct device *dev)
+{
+	struct w1_slave *sl = container_of (dev, struct w1_slave, dev);
+
+	complete (&sl->dev_released);
+}
+
+static ssize_t w1_default_read_name (struct device *dev, char *buf)
+{
+	return sprintf (buf, "No family registered.\n");
+}
+
+static ssize_t w1_default_read_bin (struct kobject *kobj, char *buf, loff_t off,
+		     size_t count)
+{
+	return sprintf (buf, "No family registered.\n");
+}
+
+struct bus_type w1_bus_type = {
+	.name = "w1",
+	.match = w1_master_match,
+};
+
+struct device_driver w1_driver = {
+	.name = "w1_driver",
+	.bus = &w1_bus_type,
+	.probe = w1_master_probe,
+	.remove = w1_master_remove,
+};
+
+struct device w1_device = {
+	.parent = NULL,
+	.bus = &w1_bus_type,
+	.bus_id = "w1 bus master",
+	.driver = &w1_driver,
+	.release = &w1_master_release
+};
+
+static struct device_attribute w1_slave_attribute = {
+	.attr = {
+			.name = "name",
+			.mode = S_IRUGO,
+			.owner = THIS_MODULE
+	},
+	.show = &w1_default_read_name,
+};
+
+static struct device_attribute w1_slave_attribute_val = {
+	.attr = {
+			.name = "value",
+			.mode = S_IRUGO,
+			.owner = THIS_MODULE
+	},
+	.show = &w1_default_read_name,
+};
+
+ssize_t w1_master_attribute_show (struct device *dev, char *buf)
+{
+	struct w1_master *md = container_of (dev, struct w1_master, dev);
+	int c = PAGE_SIZE;
+
+	if (down_interruptible (&md->mutex))
+		return -EBUSY;
+
+	c -= snprintf (buf + PAGE_SIZE - c, c, "%s\n", md->name);
+	c -= snprintf (buf + PAGE_SIZE - c, c,
+		       "bus_master=0x%p, timeout=%d, max_slave_count=%d, attempts=%lu\n",
+		       md->bus_master, w1_timeout, md->max_slave_count,
+		       md->attempts);
+	c -= snprintf (buf + PAGE_SIZE - c, c, "%d slaves: ",
+		       md->slave_count);
+	if (md->slave_count == 0)
+		c -= snprintf (buf + PAGE_SIZE - c, c, "no.\n");
+	else {
+		struct list_head *ent, *n;
+		struct w1_slave *sl;
+
+		list_for_each_safe (ent, n, &md->slist) {
+			sl = list_entry (ent, struct w1_slave, w1_slave_entry);
+
+			c -= snprintf (buf + PAGE_SIZE - c, c, "%s[%p] ",
+				       sl->name, sl);
+		}
+		c -= snprintf (buf + PAGE_SIZE - c, c, "\n");
+	}
+
+	up (&md->mutex);
+
+	return PAGE_SIZE - c;
+}
+
+struct device_attribute w1_master_attribute = {
+	.attr = {
+			.name = "w1_master_stats",
+			.mode = S_IRUGO,
+			.owner = THIS_MODULE
+	},
+	.show = &w1_master_attribute_show,
+};
+
+static struct bin_attribute w1_slave_bin_attribute = {
+	.attr = {
+		 	.name = "w1_slave",
+		 	.mode = S_IRUGO,
+	},
+	.size = W1_SLAVE_DATA_SIZE,
+	.read = &w1_default_read_bin,
+};
+
+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.bus = &w1_bus_type;
+	sl->dev.release = &w1_slave_release;
+
+	snprintf (&sl->dev.bus_id[0], sizeof (sl->dev.bus_id),
+		  "%x-%llx",
+		  (unsigned int) sl->reg_num.family,
+		  (unsigned long long) sl->reg_num.id);
+	snprintf (&sl->name[0], sizeof (sl->name),
+		  "%x-%llx",
+		  (unsigned int) sl->reg_num.family,
+		  (unsigned long long) sl->reg_num.id);
+
+	dev_info (&sl->dev, "%s: registering %s.\n", __func__,
+		  &sl->dev.bus_id[0]);
+
+	err = device_register (&sl->dev);
+	if (err < 0) {
+		dev_err (&sl->dev,
+			 "Device registration [%s] failed. err=%d\n",
+			 sl->dev.bus_id, err);
+		return err;
+	}
+
+	w1_slave_bin_attribute.read = sl->family->fops->rbin;
+	w1_slave_attribute.show = sl->family->fops->rname;
+	w1_slave_attribute_val.show = sl->family->fops->rval;
+	w1_slave_attribute_val.attr.name = sl->family->fops->rvalname;
+
+	err = device_create_file (&sl->dev, &w1_slave_attribute);
+	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;
+	}
+
+	err = device_create_file (&sl->dev, &w1_slave_attribute_val);
+	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, &w1_slave_attribute);
+		device_unregister (&sl->dev);
+		return err;
+	}
+
+	err = sysfs_create_bin_file (&sl->dev.kobj, &w1_slave_bin_attribute);
+	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, &w1_slave_attribute);
+		device_remove_file (&sl->dev, &w1_slave_attribute_val);
+		device_unregister (&sl->dev);
+		return err;
+	}
+
+	list_add_tail (&sl->w1_slave_entry, &sl->master->slist);
+
+	return 0;
+}
+
+static int w1_attach_slave_device (struct w1_master *dev, struct w1_reg_num *rn)
+{
+	struct w1_slave *sl;
+	struct w1_family *f;
+	int err;
+
+	sl = kmalloc (sizeof (struct w1_slave), GFP_KERNEL);
+	if (!sl) {
+		dev_err (&dev->dev,
+			 "%s: failed to allocate new slave device.\n",
+			 __func__);
+		return -ENOMEM;
+	}
+
+	memset (sl, 0, sizeof (*sl));
+
+	sl->owner = THIS_MODULE;
+	sl->master = dev;
+
+	memcpy (&sl->reg_num, rn, sizeof (sl->reg_num));
+	atomic_set (&sl->refcnt, 0);
+	init_completion (&sl->dev_released);
+
+	spin_lock (&flock);
+	f = w1_family_registered (rn->family);
+	if (!f) {
+		spin_unlock (&flock);
+		dev_info (&dev->dev, "Family %x is not registered.\n",
+			  rn->family);
+		kfree (sl);
+		return -ENODEV;
+	}
+	__family_get (f);
+	spin_unlock (&flock);
+
+	sl->family = f;
+
+
+	err = __w1_attach_slave_device (sl);
+	if (err < 0) {
+		dev_err (&dev->dev, "%s: Attaching %s failed.\n", __func__,
+			 sl->name);
+		family_put (sl->family);
+		kfree (sl);
+		return err;
+	}
+
+	dev->slave_count++;
+
+	return 0;
+}
+
+static void w1_slave_detach (struct w1_slave *sl)
+{
+	dev_info (&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
+
+	while (atomic_read (&sl->refcnt))
+		schedule_timeout (10);
+
+	sysfs_remove_bin_file (&sl->dev.kobj, &w1_slave_bin_attribute);
+	device_remove_file (&sl->dev, &w1_slave_attribute);
+	device_unregister (&sl->dev);
+	family_put (sl->family);
+}
+
+static void w1_search (struct w1_master *dev)
+{
+	u64 last, rn, tmp;
+	int i, count = 0, slave_count;
+	int last_family_desc, last_zero, last_device;
+	int search_bit, id_bit, comp_bit, desc_bit;
+	struct list_head *ent;
+	struct w1_slave *sl;
+	int family_found = 0;
+	struct w1_netlink_msg msg;
+
+	dev->attempts++;
+
+	memset (&msg, 0, sizeof (msg));
+
+	search_bit = id_bit = comp_bit = 0;
+	rn = tmp = last = 0;
+	last_device = last_zero = last_family_desc = 0;
+
+	desc_bit = 64;
+
+	while (!(id_bit && comp_bit) && !last_device
+		&& count++ < dev->max_slave_count) {
+		last = rn;
+		rn = 0;
+
+		last_family_desc = 0;
+
+		/*
+		 * Reset bus and all 1-wire device state machines
+		 * so they can respond to our requests.
+		 *
+		 * Return 0 - device(s) present, 1 - no devices present.
+		 */
+		if (w1_reset_bus (dev)) {
+			dev_info (&dev->dev, "No devices present on the wire.\n");
+			break;
+		}
+
+#if 1
+		memset (&msg, 0, sizeof (msg));
+
+		w1_write_8 (dev, W1_SEARCH);
+		for (i = 0; i < 64; ++i) {
+			/*
+			 * Read 2 bits from bus.
+			 * All who don't sleep must send ID bit and COMPLEMENT ID bit.
+			 * They actually are ANDed between all senders.
+			 */
+			id_bit = w1_read_bit (dev);
+			comp_bit = w1_read_bit (dev);
+
+			if (id_bit && comp_bit)
+				break;
+
+			if (id_bit == 0 && comp_bit == 0) {
+				if (i == desc_bit)
+					search_bit = 1;
+				else if (i > desc_bit)
+					search_bit = 0;
+				else
+					search_bit = ((last >> i) & 0x1);
+
+				if (search_bit == 0) {
+					last_zero = i;
+					if (last_zero < 9)
+						last_family_desc = last_zero;
+				}
+
+			}
+			else
+				search_bit = id_bit;
+
+			tmp = search_bit;
+			rn |= (tmp << i);
+
+			/*
+			 * Write 1 bit to bus
+			 * and make all who don't have "search_bit" in "i"'th position
+			 * in it's registration number sleep.
+			 */
+			w1_write_bit (dev, search_bit);
+
+		}
+#endif
+		msg.id.w1_id = rn;
+		msg.val = w1_calc_crc8 ((u8 *) & rn, 7);
+		w1_netlink_send (dev, &msg);
+
+		if (desc_bit == last_zero)
+			last_device = 1;
+
+		desc_bit = last_zero;
+
+		slave_count = 0;
+		list_for_each (ent, &dev->slist) {
+			struct w1_reg_num *tmp;
+
+			tmp = (struct w1_reg_num *) &rn;
+
+			sl = list_entry (ent, struct w1_slave, w1_slave_entry);
+
+			if (sl->reg_num.family == tmp->family &&
+			    sl->reg_num.id == tmp->id &&
+			    sl->reg_num.crc == tmp->crc)
+				break;
+			else if (sl->reg_num.family == tmp->family) {
+				family_found = 1;
+				break;
+			}
+
+			slave_count++;
+		}
+
+		if (slave_count == dev->slave_count &&
+		    msg.val && (*((__u8 *) & msg.val) == msg.id.id.crc)) {
+			w1_attach_slave_device (dev, (struct w1_reg_num *) &rn);
+		}
+	}
+}
+
+int w1_control (void *data)
+{
+	struct w1_slave *sl;
+	struct w1_master *dev;
+	struct list_head *ent, *ment, *n, *mn;
+	int err, have_to_wait = 0, timeout;
+
+	daemonize ("w1_control");
+	allow_signal (SIGTERM);
+
+	while (!control_needs_exit || have_to_wait) {
+		have_to_wait = 0;
+
+		timeout = w1_timeout;
+		do {
+			timeout = interruptible_sleep_on_timeout (&w1_control_wait, timeout);
+			if (current->flags & PF_FREEZE)
+				refrigerator (PF_FREEZE);
+		} while (!signal_pending (current) && (timeout > 0));
+
+		if (signal_pending (current))
+			flush_signals (current);
+
+		list_for_each_safe (ment, mn, &w1_masters) {
+			dev = list_entry (ment, struct w1_master, w1_master_entry);
+
+			if (!control_needs_exit && !dev->need_exit)
+				continue;
+			/*
+			 * Little race: we can create thread but not set the flag.
+			 * Get a chance for external process to set flag up.
+			 */
+			if (!dev->initialized) {
+				have_to_wait = 1;
+				continue;
+			}
+
+			spin_lock (&mlock);
+			list_del (&dev->w1_master_entry);
+			spin_unlock (&mlock);
+
+			if (control_needs_exit) {
+				dev->need_exit = 1;
+
+				err = kill_proc (dev->kpid, SIGTERM, 1);
+				if (err)
+					dev_err (&dev->dev,
+						 "Failed to send signal to w1 kernel thread %d.\n",
+						 dev->kpid);
+			}
+
+			wait_for_completion (&dev->dev_exited);
+
+			list_for_each_safe (ent, n, &dev->slist) {
+				sl = list_entry (ent, struct w1_slave, w1_slave_entry);
+
+				if (!sl)
+					dev_warn (&dev->dev,
+						  "%s: slave entry is NULL.\n",
+						  __func__);
+				else {
+					list_del (&sl->w1_slave_entry);
+
+					w1_slave_detach (sl);
+					kfree (sl);
+				}
+			}
+			device_remove_file (&dev->dev, &w1_master_attribute);
+			atomic_dec (&dev->refcnt);
+		}
+	}
+
+	complete_and_exit (&w1_control_complete, 0);
+}
+
+int w1_process (void *data)
+{
+	struct w1_master *dev = (struct w1_master *) data;
+	unsigned long timeout;
+
+	daemonize ("%s", dev->name);
+	allow_signal (SIGTERM);
+
+	while (!dev->need_exit) {
+		timeout = w1_timeout;
+		do {
+			timeout = interruptible_sleep_on_timeout (&dev->kwait, timeout);
+			if (current->flags & PF_FREEZE)
+				refrigerator (PF_FREEZE);
+		} while (!signal_pending (current) && (timeout > 0));
+
+		if (signal_pending (current))
+			flush_signals (current);
+
+		if (dev->need_exit)
+			break;
+
+		if (!dev->initialized)
+			continue;
+
+		if (down_interruptible (&dev->mutex))
+			continue;
+		w1_search (dev);
+		up (&dev->mutex);
+	}
+
+	atomic_dec (&dev->refcnt);
+	complete_and_exit (&dev->dev_exited, 0);
+
+	return 0;
+}
+
+int w1_init (void)
+{
+	int retval;
+
+	printk (KERN_INFO "Driver for 1-wire Dallas network protocol.\n");
+
+	retval = bus_register (&w1_bus_type);
+	if (retval) {
+		printk (KERN_ERR "Failed to register bus. err=%d.\n", retval);
+		goto err_out_exit_init;
+	}
+
+	retval = driver_register (&w1_driver);
+	if (retval) {
+		printk (KERN_ERR
+			"Failed to register master driver. err=%d.\n",
+			retval);
+		goto err_out_bus_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;
+	}
+
+	return 0;
+
+err_out_driver_unregister:
+	driver_unregister (&w1_driver);
+
+err_out_bus_unregister:
+	bus_unregister (&w1_bus_type);
+
+err_out_exit_init:
+	return retval;
+}
+
+void
+w1_fini (void)
+{
+	struct w1_master *dev;
+	struct list_head *ent, *n;
+
+	list_for_each_safe (ent, n, &w1_masters) {
+		dev = list_entry (ent, struct w1_master, w1_master_entry);
+		__w1_remove_master_device (dev);
+	}
+
+	control_needs_exit = 1;
+
+	wait_for_completion (&w1_control_complete);
+
+	driver_unregister (&w1_driver);
+	bus_unregister (&w1_bus_type);
+
+	printk (KERN_INFO "Driver for 1-wire Dallas network protocol is removed.\n");
+}
+
+module_init (w1_init);
+module_exit (w1_fini);
diff -Nru /tmp/w1/w1.h linux-2.6/drivers/w1/w1.h
--- /tmp/w1/w1.h	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1.h	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,112 @@
+/*
+ * 	w1.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __W1_H
+#define __W1_H
+
+struct w1_reg_num
+{
+	__u64	family:8,
+		id:48,
+		crc:8;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/completion.h>
+#include <linux/device.h>
+
+#include <net/sock.h>
+
+#include <asm/semaphore.h>
+
+#include "w1_family.h"
+
+#define W1_MAXNAMELEN		32
+#define W1_SLAVE_DATA_SIZE	128
+
+#define W1_SEARCH		0xF0
+#define W1_CONDITIONAL_SEARCH	0xEC
+#define W1_CONVERT_TEMP		0x44
+#define W1_SKIP_ROM		0xCC
+#define W1_READ_SCRATCHPAD	0xBE
+#define W1_READ_ROM		0x33
+#define W1_READ_PSUPPLY		0xB4
+#define W1_MATCH_ROM		0x55
+
+struct w1_slave
+{
+	struct module		*owner;
+	unsigned char		name[W1_MAXNAMELEN];
+	struct list_head	w1_slave_entry;
+	struct w1_reg_num	reg_num;
+	atomic_t		refcnt;
+	u8			rom[9];
+
+	struct w1_master	*master;
+	struct w1_family 	*family;
+	struct device 		dev;
+	struct completion 	dev_released;
+};
+
+struct w1_bus_master
+{
+	unsigned long		data;
+
+	u8			(*read_bit)(unsigned long);
+	void			(*write_bit)(unsigned long, u8);
+};
+
+struct w1_master
+{
+	struct list_head	w1_master_entry;
+	struct module		*owner;
+	unsigned char		name[W1_MAXNAMELEN];
+	struct list_head	slist;
+	int			max_slave_count, slave_count;
+	unsigned long		attempts;
+	int			initialized;
+	u32			id;
+
+	atomic_t		refcnt;
+
+	void			*priv;
+	int			priv_size;
+
+	int			need_exit;
+	pid_t			kpid;
+	wait_queue_head_t 	kwait;
+	struct semaphore 	mutex;
+
+	struct device_driver	*driver;
+	struct device 		dev;
+	struct completion 	dev_released;
+	struct completion 	dev_exited;
+
+	struct w1_bus_master	*bus_master;
+
+	u32			seq, groups;
+	struct sock 		*nls;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* __W1_H */
diff -Nru /tmp/w1/w1_family.c linux-2.6/drivers/w1/w1_family.c
--- /tmp/w1/w1_family.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_family.c	Sat May 15 18:19:42 2004
@@ -0,0 +1,133 @@
+/*
+ * 	w1_family.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#include "w1_family.h"
+
+spinlock_t flock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD (w1_families);
+
+int w1_register_family (struct w1_family *newf)
+{
+	struct list_head *ent, *n;
+	struct w1_family *f;
+	int ret = 0;
+
+	spin_lock (&flock);
+	list_for_each_safe (ent, n, &w1_families) {
+		f = list_entry (ent, struct w1_family, family_entry);
+
+		if (f->fid == newf->fid) {
+			ret = -EEXIST;
+			break;
+		}
+	}
+
+	if (!ret) {
+		atomic_set (&newf->refcnt, 0);
+		newf->need_exit = 0;
+		list_add_tail (&newf->family_entry, &w1_families);
+	}
+
+	spin_unlock (&flock);
+
+	return ret;
+}
+
+void w1_unregister_family (struct w1_family *fent)
+{
+	struct list_head *ent, *n;
+	struct w1_family *f;
+
+	spin_lock (&flock);
+	list_for_each_safe (ent, n, &w1_families) {
+		f = list_entry (ent, struct w1_family, family_entry);
+
+		if (f->fid == fent->fid) {
+			list_del (&fent->family_entry);
+			break;
+		}
+	}
+
+	fent->need_exit = 1;
+
+	spin_unlock (&flock);
+
+	while (atomic_read (&fent->refcnt))
+		schedule_timeout (10);
+}
+
+/*
+ * Should be called under flock held.
+ */
+struct w1_family * w1_family_registered (u8 fid)
+{
+	struct list_head *ent, *n;
+	struct w1_family *f = NULL;
+	int ret = 0;
+
+	list_for_each_safe (ent, n, &w1_families) {
+		f = list_entry (ent, struct w1_family, family_entry);
+
+		if (f->fid == fid) {
+			ret = 1;
+			break;
+		}
+	}
+
+	return (ret) ? f : NULL;
+}
+
+void family_put (struct w1_family *f)
+{
+	spin_lock (&flock);
+	__family_put (f);
+	spin_unlock (&flock);
+}
+
+void __family_put (struct w1_family *f)
+{
+	if (atomic_dec_and_test (&f->refcnt))
+		f->need_exit = 1;
+}
+
+void family_get (struct w1_family *f)
+{
+	spin_lock (&flock);
+	__family_get (f);
+	spin_unlock (&flock);
+
+}
+
+void __family_get (struct w1_family *f)
+{
+	atomic_inc (&f->refcnt);
+}
+
+EXPORT_SYMBOL (family_get);
+EXPORT_SYMBOL (family_put);
+EXPORT_SYMBOL (__family_get);
+EXPORT_SYMBOL (__family_put);
+EXPORT_SYMBOL (w1_family_registered);
+EXPORT_SYMBOL (w1_unregister_family);
+EXPORT_SYMBOL (w1_register_family);
diff -Nru /tmp/w1/w1_family.h linux-2.6/drivers/w1/w1_family.h
--- /tmp/w1/w1_family.h	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_family.h	Sat May  8 16:42:19 2004
@@ -0,0 +1,65 @@
+/*
+ * 	w1_family.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __W1_FAMILY_H
+#define __W1_FAMILY_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <asm/atomic.h>
+
+#define W1_FAMILY_DEFAULT	0
+#define W1_FAMILY_THERM		0x10
+#define W1_FAMILY_IBUT		0xff /* ? */
+
+#define MAXNAMELEN		32
+
+struct w1_family_ops
+{
+	ssize_t (* rname)(struct device *, char *);
+	ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t);
+	
+	ssize_t (* rval)(struct device *, char *);
+	unsigned char rvalname[MAXNAMELEN];
+};
+
+struct w1_family
+{
+	struct list_head	family_entry;
+	u8			fid;
+	
+	struct w1_family_ops	*fops;
+	
+	atomic_t		refcnt;
+	u8			need_exit;
+};
+
+extern spinlock_t flock;
+
+void family_get(struct w1_family *);
+void family_put(struct w1_family *);
+void __family_get(struct w1_family *);
+void __family_put(struct w1_family *);
+struct w1_family * w1_family_registered(u8);
+void w1_unregister_family(struct w1_family *);
+int w1_register_family(struct w1_family *);
+
+#endif /* __W1_FAMILY_H */
diff -Nru /tmp/w1/w1_int.c linux-2.6/drivers/w1/w1_int.c
--- /tmp/w1/w1_int.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_int.c	Sat May 15 18:19:42 2004
@@ -0,0 +1,208 @@
+/*
+ * 	w1_int.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include "w1.h"
+#include "w1_log.h"
+
+static u32 w1_ids = 1;
+
+extern struct device_driver w1_driver;
+extern struct bus_type w1_bus_type;
+extern struct device w1_device;
+extern struct device_attribute w1_master_attribute;
+extern int w1_max_slave_count;
+extern struct list_head w1_masters;
+extern spinlock_t mlock;
+
+extern int w1_process (void *);
+
+struct w1_master * w1_alloc_dev (u32 id, int slave_count,
+	      struct device_driver *driver, struct device *device)
+{
+	struct w1_master *dev;
+	int err;
+
+	/*
+	 * We are in process context(kernel thread), so can sleep.
+	 */
+	dev = kmalloc (sizeof (struct w1_master) + sizeof (struct w1_bus_master), GFP_KERNEL);
+	if (!dev) {
+		printk (KERN_ERR
+			"Failed to allocate %d bytes for new w1 device.\n",
+			sizeof (struct w1_master));
+		return NULL;
+	}
+
+	memset (dev, 0, sizeof (struct w1_master) + sizeof (struct w1_bus_master));
+
+	dev->bus_master = (struct w1_bus_master *) (dev + 1);
+
+	dev->owner 		= THIS_MODULE;
+	dev->max_slave_count 	= slave_count;
+	dev->slave_count 	= 0;
+	dev->attempts 		= 0;
+	dev->kpid 		= -1;
+	dev->initialized 	= 0;
+	dev->id 		= id;
+
+	atomic_set (&dev->refcnt, 2);
+
+	INIT_LIST_HEAD (&dev->slist);
+	init_MUTEX (&dev->mutex);
+
+	init_waitqueue_head (&dev->kwait);
+	init_completion (&dev->dev_released);
+	init_completion (&dev->dev_exited);
+
+	memcpy (&dev->dev, device, sizeof (struct device));
+	snprintf (dev->dev.bus_id, sizeof (dev->dev.bus_id),
+		  "w1_bus_master%u", dev->id);
+	snprintf (dev->name, sizeof (dev->name), "w1_bus_master%u", dev->id);
+
+	dev->driver = driver;
+
+	dev->groups = 23;
+	dev->seq = 1;
+	dev->nls = netlink_kernel_create (NETLINK_NFLOG, NULL);
+	if (!dev->nls) {
+		printk (KERN_ERR "Failed to create new netlink socket(%u).\n",
+			NETLINK_NFLOG);
+		memset (dev, 0, sizeof (struct w1_master));
+		kfree (dev);
+		dev = NULL;
+	}
+
+	err = device_register (&dev->dev);
+	if (err) {
+		printk (KERN_ERR "Failed to register master device. err=%d\n", err);
+		if (dev->nls->sk_socket)
+			sock_release (dev->nls->sk_socket);
+		memset (dev, 0, sizeof (struct w1_master));
+		kfree (dev);
+		dev = NULL;
+	}
+
+	return dev;
+}
+
+void w1_free_dev (struct w1_master *dev)
+{
+	device_unregister (&dev->dev);
+	if (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)
+{
+	struct w1_master *dev;
+	int retval = 0;
+
+	dev = w1_alloc_dev (w1_ids++, w1_max_slave_count, &w1_driver, &w1_device);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->kpid = kernel_thread (&w1_process, dev, 0);
+	if (dev->kpid < 0) {
+		dev_err (&dev->dev,
+			 "Failed to create new kernel thread. err=%d\n",
+			 dev->kpid);
+		retval = dev->kpid;
+		goto err_out_free_dev;
+	}
+
+	retval = device_create_file (&dev->dev, &w1_master_attribute);
+	if (retval)
+		goto err_out_kill_thread;
+
+	memcpy (dev->bus_master, master, sizeof (struct w1_bus_master));
+
+	dev->initialized = 1;
+
+	spin_lock (&mlock);
+	list_add (&dev->w1_master_entry, &w1_masters);
+	spin_unlock (&mlock);
+
+	return 0;
+
+err_out_kill_thread:
+	dev->need_exit = 1;
+	if (kill_proc (dev->kpid, SIGTERM, 1))
+		dev_err (&dev->dev,
+			 "Failed to send signal to w1 kernel thread %d.\n",
+			 dev->kpid);
+	wait_for_completion (&dev->dev_exited);
+
+err_out_free_dev:
+	w1_free_dev (dev);
+
+	return retval;
+}
+
+void
+__w1_remove_master_device (struct w1_master *dev)
+{
+	int err;
+
+	dev->need_exit = 1;
+	err = kill_proc (dev->kpid, SIGTERM, 1);
+	if (err)
+		dev_err (&dev->dev,
+			 "%s: Failed to send signal to w1 kernel thread %d.\n",
+			 __func__, dev->kpid);
+
+	while (atomic_read (&dev->refcnt))
+		schedule_timeout (10);
+
+	w1_free_dev (dev);
+}
+
+void w1_remove_master_device (struct w1_bus_master *bm)
+{
+	struct w1_master *dev = NULL;
+	struct list_head *ent, *n;
+
+	list_for_each_safe (ent, n, &w1_masters) {
+		dev = list_entry (ent, struct w1_master, w1_master_entry);
+		if (!dev->initialized)
+			continue;
+
+		if (dev->bus_master->data == bm->data)
+			break;
+	}
+
+	if (!dev) {
+		printk (KERN_ERR "Device doesn't exist.\n");
+		return;
+	}
+
+	__w1_remove_master_device (dev);
+}
+
+EXPORT_SYMBOL (w1_alloc_dev);
+EXPORT_SYMBOL (w1_free_dev);
+EXPORT_SYMBOL (w1_add_master_device);
+EXPORT_SYMBOL (w1_remove_master_device);
+EXPORT_SYMBOL (__w1_remove_master_device);
diff -Nru /tmp/w1/w1_int.h linux-2.6/drivers/w1/w1_int.h
--- /tmp/w1/w1_int.h	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_int.h	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,36 @@
+/*
+ * 	w1_int.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __W1_INT_H
+#define __W1_INT_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "w1.h"
+
+struct w1_master * w1_alloc_dev(int, struct device_driver *, struct device *);
+void w1_free_dev(struct w1_master *dev);
+int w1_add_master_device(struct w1_bus_master *);
+void w1_remove_master_device(struct w1_bus_master *);
+void __w1_remove_master_device(struct w1_master *);
+
+#endif /* __W1_INT_H */
diff -Nru /tmp/w1/w1_io.c linux-2.6/drivers/w1/w1_io.c
--- /tmp/w1/w1_io.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_io.c	Sat May 15 18:19:42 2004
@@ -0,0 +1,138 @@
+/*
+ * 	w1_io.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include <linux/moduleparam.h>
+
+#include "w1.h"
+#include "w1_log.h"
+#include "w1_io.h"
+
+int w1_delay_parm = 1;
+module_param_named (delay_coef, w1_delay_parm, int, 0);
+
+static u8 w1_crc8_table[] = {
+	0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
+	157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
+	35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
+	190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
+	70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
+	219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
+	101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
+	248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
+	140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
+	17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
+	175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
+	50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
+	202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
+	87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
+	233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
+	116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
+};
+
+void w1_delay (unsigned long tm)
+{
+	udelay (tm * w1_delay_parm);
+}
+
+void w1_write_bit (struct w1_master *dev, int bit)
+{
+	if (bit) {
+		dev->bus_master->write_bit (dev->bus_master->data, 0);
+		w1_delay (6);
+		dev->bus_master->write_bit (dev->bus_master->data, 1);
+		w1_delay (64);
+	} else {
+		dev->bus_master->write_bit (dev->bus_master->data, 0);
+		w1_delay (60);
+		dev->bus_master->write_bit (dev->bus_master->data, 1);
+		w1_delay (10);
+	}
+}
+
+void w1_write_8 (struct w1_master *dev, u8 byte)
+{
+	int i;
+
+	for (i = 0; i < 8; ++i)
+		w1_write_bit (dev, (byte >> i) & 0x1);
+}
+
+u8 w1_read_bit (struct w1_master *dev)
+{
+	int result;
+
+	dev->bus_master->write_bit (dev->bus_master->data, 0);
+	w1_delay (6);
+	dev->bus_master->write_bit (dev->bus_master->data, 1);
+	w1_delay (9);
+
+	result = dev->bus_master->read_bit (dev->bus_master->data);
+	w1_delay (55);
+
+	return result & 0x1;
+}
+
+u8 w1_read_8 (struct w1_master * dev)
+{
+	int i;
+	u8 res = 0;
+
+	for (i = 0; i < 8; ++i)
+		res |= (w1_read_bit (dev) << i);
+
+	return res;
+}
+
+int w1_reset_bus (struct w1_master *dev)
+{
+	int result;
+
+	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);
+
+	return result;
+}
+
+u8 w1_calc_crc8 (u8 * data, int len)
+{
+	u8 crc = 0;
+
+	while (len--)
+		crc = w1_crc8_table[crc ^ *data++];
+
+	return crc;
+}
+
+EXPORT_SYMBOL (w1_write_bit);
+EXPORT_SYMBOL (w1_write_8);
+EXPORT_SYMBOL (w1_read_bit);
+EXPORT_SYMBOL (w1_read_8);
+EXPORT_SYMBOL (w1_reset_bus);
+EXPORT_SYMBOL (w1_calc_crc8);
+EXPORT_SYMBOL (w1_delay);
diff -Nru /tmp/w1/w1_io.h linux-2.6/drivers/w1/w1_io.h
--- /tmp/w1/w1_io.h	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_io.h	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,35 @@
+/*
+ * 	w1_io.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __W1_IO_H
+#define __W1_IO_H
+
+#include "w1.h"
+
+void w1_delay(unsigned long);
+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);
+
+#endif /* __W1_IO_H */
diff -Nru /tmp/w1/w1_log.h linux-2.6/drivers/w1/w1_log.h
--- /tmp/w1/w1_log.h	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_log.h	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,38 @@
+/*
+ * 	w1_log.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __W1_LOG_H
+#define __W1_LOG_H
+
+#define DEBUG
+
+#ifdef W1_DEBUG
+#  define assert(expr) do {} while (0)
+#else
+#  define assert(expr) \
+        if(unlikely(!(expr))) {				        \
+        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n",	\
+        #expr,__FILE__,__FUNCTION__,__LINE__);		        \
+        }
+#endif
+
+#endif /* __W1_LOG_H */
+
diff -Nru /tmp/w1/w1_netlink.c linux-2.6/drivers/w1/w1_netlink.c
--- /tmp/w1/w1_netlink.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_netlink.c	Sat May 15 18:19:42 2004
@@ -0,0 +1,55 @@
+/*
+ * w1_netlink.c
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+
+#include "w1.h"
+#include "w1_log.h"
+#include "w1_netlink.h"
+
+void w1_netlink_send (struct w1_master *dev, struct w1_netlink_msg *msg)
+{
+	unsigned int size;
+	struct sk_buff *skb;
+	struct w1_netlink_msg *data;
+	struct nlmsghdr *nlh;
+
+	size = NLMSG_SPACE (sizeof (struct w1_netlink_msg));
+
+	skb = alloc_skb (size, GFP_ATOMIC);
+	if (!skb) {
+		dev_err (&dev->dev, "skb_alloc() failed.\n");
+		return;
+	}
+
+	nlh = NLMSG_PUT (skb, 0, dev->seq++, NLMSG_DONE, size - sizeof (*nlh));
+
+	data = (struct w1_netlink_msg *) NLMSG_DATA (nlh);
+
+	memcpy (data, msg, sizeof (struct w1_netlink_msg));
+
+	NETLINK_CB (skb).dst_groups = dev->groups;
+	netlink_broadcast (dev->nls, skb, 0, dev->groups, GFP_ATOMIC);
+
+nlmsg_failure:
+	return;
+}
diff -Nru /tmp/w1/w1_netlink.h linux-2.6/drivers/w1/w1_netlink.h
--- /tmp/w1/w1_netlink.h	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_netlink.h	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,44 @@
+/*
+ * w1_netlink.h
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol at 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __W1_NETLINK_H
+#define __W1_NETLINK_H
+
+#include <asm/types.h>
+
+#include "w1.h"
+
+struct w1_netlink_msg 
+{
+	union
+	{
+		struct w1_reg_num 	id;
+		__u64			w1_id;
+	} id;
+	__u64				val;
+};
+
+#ifdef __KERNEL__
+
+void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
+
+#endif /* __KERNEL__ */
+#endif /* __W1_NETLINK_H */
diff -Nru /tmp/w1/w1_therm.c linux-2.6/drivers/w1/w1_therm.c
--- /tmp/w1/w1_therm.c	Thu Jan  1 03:00:00 1970
+++ linux-2.6/drivers/w1/w1_therm.c	Sat May 15 18:23:18 2004
@@ -0,0 +1,177 @@
+/*
+ * 	w1_therm.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol at 2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the therms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/types.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "w1.h"
+#include "w1_io.h"
+#include "w1_int.h"
+#include "w1_family.h"
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>");
+MODULE_DESCRIPTION ("Driver for 1-wire Dallas network protocol, temperature family.");
+
+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);
+
+static struct w1_family_ops w1_therm_fops = {
+	.rname = &w1_therm_read_name,
+	.rbin = &w1_therm_read_bin,
+	.rval = &w1_therm_read_temp,
+	.rvalname = "temp1_input",
+};
+
+static ssize_t w1_therm_read_name (struct device *dev, char *buf)
+{
+	struct w1_slave *sl = container_of (dev, struct w1_slave, dev);
+
+	return sprintf (buf, "%s\n", sl->name);
+}
+
+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", temp * 1000);
+}
+
+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_master *dev = sl->master;
+	u8 rom[9], crc, verdict;
+	size_t icount;
+	int i;
+	u16 temp;
+
+	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 = W1_SLAVE_DATA_SIZE - off;
+
+	icount = count;
+
+	memset (buf, 0, count);
+	memset (rom, 0, sizeof (rom));
+
+	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;
+			}
+		}
+		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 ", rom[i]);
+	count += snprintf (buf + count, icount - 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]);
+	temp = 0;
+	temp <<= sl->rom[1] / 2;
+	temp |= sl->rom[0] / 2;
+	count += snprintf (buf + count, icount - count, "t=%u\n", temp);
+out:
+	up (&dev->mutex);
+out_dec:
+	atomic_dec (&sl->refcnt);
+
+	return count;
+}
+
+static struct w1_family w1_therm_family = {
+	.fid = W1_FAMILY_THERM,
+	.fops = &w1_therm_fops,
+};
+
+int __init w1_therm_init (void)
+{
+	return w1_register_family (&w1_therm_family);
+}
+
+void __exit w1_therm_fini (void)
+{
+	w1_unregister_family (&w1_therm_family);
+}
+
+module_init (w1_therm_init);
+module_exit (w1_therm_fini);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.lm-sensors.org/pipermail/lm-sensors/attachments/20040607/60b8aefc/attachment.bin 


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux