[RESEND] Re: Dallas 1-wire protocol implementation.

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

 



Hello.

This patchset against 2.6 linux kernel implements Dallas's 1-wire protocol.
All technical issues discussed before are successfully resolved.
Patchset contains 
 w1.diff 		- Dallas's 1-wire protocol implementation
 w1.therm.diff		- thermal operation
 w1.matrox.diff		- Matrox's G400 GPIO transport layer
 w1d.c			- userspace daemon to monitor w1 netlink events

Please consider for inclusion if you think it is worth to do.

Thank you.


-- 
	Evgeniy Polaykov ( s0mbre )

Crash is better than data corruption. -- Art Grabowski
-------------- next part --------------
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1.c	Tue Apr 13 01:20:42 2004
@@ -0,0 +1,622 @@
+/*
+ * 	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/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, "%s: sysfs file creation for [%s] failed. err=%d\n", 
+				__func__, 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)
+			{
+				//dev_info(&sl->dev, "%s: %s still exists.\n", __func__, sl->name);
+				break;
+			}
+			else if (sl->reg_num.family == tmp->family)
+			{
+				//dev_info(&dev->dev, "%s: found new family %u.\n", __func__, 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_IOTHREAD);
+		} 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, "%s: Failed to send signal to w1 kernel thread %d.\n", 
+							__func__, 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_IOTHREAD);
+		} 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);
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ 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 */
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1_family.c	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,138 @@
+/*
+ * 	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);
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1_family.h	Mon Apr 12 17:24:34 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_TERM		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 */
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1_int.c	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,205 @@
+/*
+ * 	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, "%s: Failed to send signal to w1 kernel thread %d.\n", 
+				__func__, 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);
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ 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 */
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1_io.c	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,141 @@
+/*
+ * 	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);
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ 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 */
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ 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 */
+
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1_netlink.c	Mon Apr 12 17:24:34 2004
@@ -0,0 +1,58 @@
+/*
+ * 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;
+}
+
+
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ 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 */

-------------- next part --------------
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/matrox_w1.c	Mon Apr 12 17:24:33 2004
@@ -0,0 +1,272 @@
+/*
+ * 	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).");
+
+#define MEMORY_MAPPED_ACCESS
+
+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)
+{
+#ifdef MEMORY_MAPPED_ACCESS
+	return readb(addr);
+#else
+	return inb_p(addr);
+#endif
+}
+
+static __inline__ void mwriteb(u8 val, unsigned long addr)
+{ 
+#ifdef MEMORY_MAPPED_ACCESS
+	writeb(val, addr);
+#else
+	outb_p(val, addr);
+#endif
+}
+
+
+/*
+ * 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 1, 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);
+
+	printk(KERN_INFO "virt_addr=0x%lx, base_addr=0x%lx, port_index=0x%lx, port_data=0x%lx\n", 
+		dev->virt_addr, dev->base_addr, 
+		dev->port_index, dev->port_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;
+
+	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);
+
-------------- next part --------------
--- /dev/null	Thu Oct 30 21:31:23 2003
+++ drivers/w1/w1_therm.c	Mon Apr 12 18:22:23 2004
@@ -0,0 +1,181 @@
+/*
+ * 	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 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/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_TERM,
+	.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: w1d.c
Type: text/x-c
Size: 2906 bytes
Desc: not available
Url : http://lists.lm-sensors.org/pipermail/lm-sensors/attachments/20040507/752cf437/attachment.bin 
-------------- 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/20040507/752cf437/attachment-0001.bin 


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

  Powered by Linux