Hi Evgeniy! I have quickly looked through your patch, and it seems your implementation only support 1 wire adapters in bit mode, ie the data line is drived by the driver. I own a 1 wire <-> USB bridge built using a DS2490 chip from Dallas. It drivew directly the 1 wire bus, so you just have to send it "medium" level commands such as "Match access", "Search access", "Block I/O", "Write EEPROM", etc. It would be good if your patch has a preliminary support for this type of adapters, I mean I think it would be better to move all bit functions into a separate file called w1-algo-bit.c, just like for the I2C bus. BTW, I would like to write a driver for the DS2490, but I don't really have the time by now. Maybe latter. Bye, Aurelien On Mon, Jun 07, 2004 at 02:04:00PM +0400, Evgeniy Polyakov wrote: > 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 > --- 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 > --- 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" > --- 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/ > 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); -- .''`. Aurelien Jarno GPG: 1024D/F1BCDB73 : :' : Debian GNU/Linux developer | Electrical Engineering Student `. `' aurel32 at debian.org | aurelien at aurel32.net `- people.debian.org/~aurel32 | www.aurel32.net